diff -uNr zaptel-1.4.8/wcte12xp/base.c zaptel-1.4/wcte12xp/base.c
--- zaptel-1.4.8/wcte12xp/base.c	2008-01-11 23:39:16.000000000 +0100
+++ zaptel-1.4/wcte12xp/base.c	2008-02-03 17:46:02.000000000 +0100
@@ -47,8 +47,11 @@
 #include "../wct4xxp/wct4xxp.h"	/* For certain definitions */
 
 #include "wcte12xp.h"
+
+#if defined(VPM_SUPPORT)
 #include "vpmadt032.h"
 #include "GpakApi.h"
+#endif
 
 struct pci_driver te12xp_driver;
 
@@ -92,6 +95,9 @@
 int vpmsupport = 1;
 int vpmdtmfsupport = 0;
 int vpmtsisupport = 0;
+int vpmnlptype = 1;
+int vpmnlpthresh = 24;
+int vpmnlpmaxsupp = 0;
 #endif
 
 struct t1 *ifaces[WC_MAX_IFACES];
@@ -1352,8 +1358,12 @@
 	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
 	wc->span.manufacturer = "Digium";
 	strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
+
+#if defined(VPM_SUPPORT)
 	if (wc->vpm150m)
 		strncat(wc->span.devicetype, " with VPMADT032", sizeof(wc->span.devicetype) - 1);
+#endif
+
 	snprintf(wc->span.location, sizeof(wc->span.location) - 1,
 		"PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
 
@@ -2012,9 +2022,9 @@
 
 static void __devexit te12xp_remove_one(struct pci_dev *pdev)
 {
-	unsigned long flags;
 	struct t1 *wc = pci_get_drvdata(pdev);
 #ifdef VPM_SUPPORT
+	unsigned long flags;
 	struct vpm150m *vpm150m = wc->vpm150m;
 #endif
 	if (!wc)
@@ -2115,6 +2125,9 @@
 MODULE_PARM(vpmsupport, "i");
 MODULE_PARM(vpmdtmfsupport, "i");
 MODULE_PARM(vpmtsisupport, "i");
+MODULE_PARM(vpmnlptype, "i");
+MODULE_PARM(vpmnlpthresh, "i");
+MODULE_PARM(vpmnlpmaxsupp, "i");
 #endif
 #endif
 
diff -uNr zaptel-1.4.8/wcte12xp/Kbuild zaptel-1.4/wcte12xp/Kbuild
--- zaptel-1.4.8/wcte12xp/Kbuild	2007-12-11 09:43:22.000000000 +0100
+++ zaptel-1.4/wcte12xp/Kbuild	2008-02-03 17:46:02.000000000 +0100
@@ -2,6 +2,10 @@
 
 EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
 
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+  EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
 wcte12xp-objs := base.o vpmadt032.o GpakApi.o
 
 ifneq ($(HOTPLUG_FIRMWARE),yes)
diff -uNr zaptel-1.4.8/wcte12xp/Makefile zaptel-1.4/wcte12xp/Makefile
--- zaptel-1.4.8/wcte12xp/Makefile	2007-12-11 09:43:22.000000000 +0100
+++ zaptel-1.4/wcte12xp/Makefile	2008-02-03 17:46:02.000000000 +0100
@@ -1,24 +1,22 @@
 ifneq ($(KBUILD_EXTMOD),)
-# We only get here on kernels 2.6.0-2.6.8 .
+# We only get here on kernels 2.6.0-2.6.9 .
 # For newer kernels, Kbuild will be included directly by the kernel
 # build system.
 include $(src)/Kbuild
 
 else
 
+# building for 2.4 kernels means no VPM support, so none of the VPM support
+# modules are included in the Makefile rules
+
 all: wcte12xp.o
 
 %.o: %.c
 	$(CC) $(KFLAGS) -o $@ -c $<
 
-base.o: ../zaptel.h vpmadt032.h
-
-vpmadt032.o: vpmadt032.h
-
-../firmware/zaptel-fw-vpmadt032.o: base.o
-	$(MAKE) -C ../firmware zaptel-fw-vpmadt032.o
+base.o: ../zaptel.h
 
-wcte12xp.o: base.o vpmadt032.o GpakApi.o ../firmware/zaptel-fw-vpmadt032.o
+wcte12xp.o: base.o
 	$(LD) -r -o $@ $^
 
 clean:
diff -uNr zaptel-1.4.8/wcte12xp/.svn/all-wcprops zaptel-1.4/wcte12xp/.svn/all-wcprops
--- zaptel-1.4.8/wcte12xp/.svn/all-wcprops	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/all-wcprops	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,71 @@
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svn/zaptel/!svn/ver/3748/branches/1.4/wcte12xp
+END
+vpmadt032.c
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svn/zaptel/!svn/ver/3731/branches/1.4/wcte12xp/vpmadt032.c
+END
+GpakApi.h
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svn/zaptel/!svn/ver/3371/branches/1.4/wcte12xp/GpakApi.h
+END
+wcte12xp.h
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svn/zaptel/!svn/ver/3738/branches/1.4/wcte12xp/wcte12xp.h
+END
+GpakErrs.h
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svn/zaptel/!svn/ver/3371/branches/1.4/wcte12xp/GpakErrs.h
+END
+vpmadt032.h
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svn/zaptel/!svn/ver/3649/branches/1.4/wcte12xp/vpmadt032.h
+END
+GpakHpi.h
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svn/zaptel/!svn/ver/3371/branches/1.4/wcte12xp/GpakHpi.h
+END
+Kbuild
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/zaptel/!svn/ver/3721/branches/1.4/wcte12xp/Kbuild
+END
+base.c
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svn/zaptel/!svn/ver/3738/branches/1.4/wcte12xp/base.c
+END
+GpakApi.c
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svn/zaptel/!svn/ver/3371/branches/1.4/wcte12xp/GpakApi.c
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svn/zaptel/!svn/ver/3748/branches/1.4/wcte12xp/Makefile
+END
+gpakenum.h
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svn/zaptel/!svn/ver/3371/branches/1.4/wcte12xp/gpakenum.h
+END
diff -uNr zaptel-1.4.8/wcte12xp/.svn/dir-prop-base zaptel-1.4/wcte12xp/.svn/dir-prop-base
--- zaptel-1.4.8/wcte12xp/.svn/dir-prop-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/dir-prop-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,8 @@
+K 10
+svn:ignore
+V 19
+*.mod.c
+*.cmd
+*.ko
+
+END
diff -uNr zaptel-1.4.8/wcte12xp/.svn/entries zaptel-1.4/wcte12xp/.svn/entries
--- zaptel-1.4.8/wcte12xp/.svn/entries	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/entries	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,160 @@
+8
+
+dir
+3788
+http://svn.digium.com/svn/zaptel/branches/1.4/wcte12xp
+http://svn.digium.com/svn/zaptel
+
+
+
+2008-01-27T23:10:09.554228Z
+3748
+tzafrir
+has-props
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+f558416c-6c06-0410-9f27-dde2687782d0
+
+vpmadt032.c
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+7a7bc225dfd5968b76b382d2b79a6a09
+2008-01-23T21:35:23.884040Z
+3731
+mattf
+
+GpakApi.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+458122bf91992498df9699f16feda1bf
+2007-12-08T19:55:17.407807Z
+3371
+mattf
+
+wcte12xp.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+48256930bd05517fe422981f3941f1c6
+2008-01-25T23:13:41.201127Z
+3738
+kpfleming
+
+GpakErrs.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+5e98eff72f35f0c81277b0090fb0f63f
+2007-12-08T19:55:17.407807Z
+3371
+mattf
+
+vpmadt032.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+4a0b36e3b78fe54678b22a6b5539ee86
+2008-01-10T23:15:28.791257Z
+3649
+kpfleming
+
+GpakHpi.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+e0ff5314c3e64c96c20203e1f0666264
+2007-12-08T19:55:17.407807Z
+3371
+mattf
+
+Kbuild
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+6a393d4fd432fa0752701dd71f625a1b
+2008-01-21T23:15:03.509891Z
+3721
+tzafrir
+
+base.c
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+da12b534379334f927f32f43e054273d
+2008-01-25T23:13:41.201127Z
+3738
+kpfleming
+
+GpakApi.c
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+2c8fbd44ee5c365dcc3214c1d2c1341e
+2007-12-08T19:55:17.407807Z
+3371
+mattf
+
+Makefile
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+156fe8f2b1e7988b311fe2e6fb4c9d2c
+2008-01-27T23:10:09.554228Z
+3748
+tzafrir
+
+gpakenum.h
+file
+
+
+
+
+2008-02-03T16:46:02.000000Z
+391884e1113d265ad0a2d194bf722d1e
+2007-12-08T19:55:17.407807Z
+3371
+mattf
+
diff -uNr zaptel-1.4.8/wcte12xp/.svn/format zaptel-1.4/wcte12xp/.svn/format
--- zaptel-1.4.8/wcte12xp/.svn/format	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/format	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1 @@
+8
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/base.c.svn-base zaptel-1.4/wcte12xp/.svn/text-base/base.c.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/base.c.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/base.c.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,2139 @@
+/*
+ * Digium, Inc.  Wildcard TE12xP T1/E1 card Driver
+ *
+ * Written by Michael Spiceland <mspiceland@digium.com>
+ *
+ * Adapted from the wctdm24xxp and wcte11xp drivers originally
+ * written by Mark Spencer <markster@digium.com>
+ *            Matthew Fredrickson <creslin@digium.com>
+ *            William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+
+#ifdef LINUX26
+#include <linux/moduleparam.h>
+#endif
+
+#include "zaptel.h"
+
+#include "../wct4xxp/wct4xxp.h"	/* For certain definitions */
+
+#include "wcte12xp.h"
+
+#if defined(VPM_SUPPORT)
+#include "vpmadt032.h"
+#include "GpakApi.h"
+#endif
+
+struct pci_driver te12xp_driver;
+
+static int chanmap_t1[] = 
+{ 2,1,0,
+  6,5,4,
+  10,9,8,
+  14,13,12,
+  18,17,16,
+  22,21,20,
+  26,25,24,
+  30,29,28 };
+
+static int chanmap_e1[] = 
+{ 2,1,0,
+  7,6,5,4,
+  11,10,9,8,
+  15,14,13,12,
+  19,18,17,16,
+  23,22,21,20,
+  27,26,25,24,
+  31,30,29,28 };
+
+static int chanmap_e1uc[] =
+{ 3,2,1,0,
+  7,6,5,4,
+  11,10,9,8,
+  15,14,13,12,
+  19,18,17,16,
+  23,22,21,20,
+  27,26,25,24,
+  31,30,29,28 };
+
+int debug = 0;
+static int j1mode = 0;
+static int alarmdebounce = 0;
+static int loopback = 0;
+static int t1e1override = -1;
+static int unchannelized = 0;
+#ifdef VPM_SUPPORT
+int vpmsupport = 1;
+int vpmdtmfsupport = 0;
+int vpmtsisupport = 0;
+int vpmnlptype = 1;
+int vpmnlpthresh = 24;
+int vpmnlpmaxsupp = 0;
+#endif
+
+struct t1 *ifaces[WC_MAX_IFACES];
+spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
+
+struct t1_desc {
+	char *name;
+	int flags;
+};
+
+static struct t1_desc te120p = { "Wildcard TE120P", 0 };
+static struct t1_desc te122 = { "Wildcard TE122", 0 };
+static struct t1_desc te121 = { "Wildcard TE121", 0 };
+
+int schluffen(wait_queue_head_t *q)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	add_wait_queue(q, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	if (!signal_pending(current)) schedule();
+	current->state = TASK_RUNNING;
+	remove_wait_queue(q, &wait);
+	if (signal_pending(current)) return -ERESTARTSYS;
+	return(0);
+}
+
+static inline int empty_slot(struct t1 *wc)
+{
+	unsigned int x;
+
+	for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+		if (!wc->cmdq.cmds[x].flags && !wc->cmdq.cmds[x].address)
+			return x;
+	}
+	return -1;
+}
+
+static inline void __t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val)
+{
+	outl(val, wc->iobase + addr);
+}
+
+static inline void t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	__t1_setctl(wc, addr, val);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline unsigned int __t1_getctl(struct t1 *wc, unsigned int addr)
+{
+	return inl(wc->iobase + addr);
+}
+
+static inline unsigned int t1_getctl(struct t1 *wc, unsigned int addr)
+{
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	val = __t1_getctl(wc, addr);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	return val;
+}
+
+static void t1_init_descriptors(struct t1 *wc)
+{
+	volatile unsigned int *descrip;
+	dma_addr_t descripdma;
+	dma_addr_t writedma;
+	dma_addr_t readdma;
+	int x;
+	
+	descrip = wc->descripchunk;
+	descripdma = wc->descripdma;
+	writedma = wc->writedma;
+	readdma = wc->readdma;
+
+	for (x = 0; x < ERING_SIZE; x++) {
+		if (x < ERING_SIZE - 1)
+			descripdma += 16;
+		else
+			descripdma = wc->descripdma;
+
+		/* Transmit descriptor */
+		descrip[0] = 0x80000000;
+		descrip[1] = 0xe5800000 | (SFRAME_SIZE);
+		if (x % 2)
+			descrip[2] = writedma + SFRAME_SIZE;
+		else
+			descrip[2] = writedma;
+		descrip[3] = descripdma;
+	
+		/* Receive descriptor */
+		descrip[0 + ERING_SIZE * 4] = 0x80000000;
+		descrip[1 + ERING_SIZE * 4] = 0x01000000 | (SFRAME_SIZE);
+		if (x % 2)
+			descrip[2 + ERING_SIZE * 4] = readdma + SFRAME_SIZE;
+		else
+			descrip[2 + ERING_SIZE * 4] = readdma;
+		descrip[3 + ERING_SIZE * 4] = descripdma + ERING_SIZE * 16;
+	
+		/* Advance descriptor */
+		descrip += 4;
+	}	
+}
+
+static inline void t1_reinit_descriptor(struct t1 *wc, int tx, int dbl, char *s)
+{
+	int o2 = dbl * 4;
+
+	if (!tx)
+		o2 += ERING_SIZE * 4;
+
+	wc->descripchunk[o2] = 0x80000000;
+}
+
+static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot)
+{
+	struct command *curcmd=NULL;
+	unsigned int x;
+
+	/* Skip audio */
+	writechunk += 66;
+	/* Search for something waiting to transmit */
+	if ((slot < 6) && (eframe) && (eframe < ZT_CHUNKSIZE - 1)) { 
+		/* only 6 useable cs slots per */
+
+		/* framer */
+		for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+			if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) && 
+			    !(wc->cmdq.cmds[x].flags & (__CMD_TX | __CMD_FIN))) {
+			   	curcmd = &wc->cmdq.cmds[x];
+				wc->cmdq.cmds[x].flags |= __CMD_TX;
+				wc->cmdq.cmds[x].ident = wc->txident;
+				break;
+			}
+		}
+		if (!curcmd) {
+			curcmd = &wc->dummy;
+			/* If nothing else, use filler */
+			curcmd->address = 0x4a;
+			curcmd->data = 0x00;
+			curcmd->flags = __CMD_RD;
+		}
+		curcmd->cs_slot = slot; 
+		if (curcmd->flags & __CMD_WR)
+			writechunk[CMD_BYTE(slot,0,0)] = 0x0c; /* 0c write command */
+		else if (curcmd->flags & __CMD_LEDS)
+			writechunk[CMD_BYTE(slot,0,0)] = 0x10 | ((curcmd->address) & 0x0E); /* led set command */ 
+		else if (curcmd->flags & __CMD_PINS)
+			writechunk[CMD_BYTE(slot,0,0)] = 0x30; /* CPLD2 pin state */
+		else
+			writechunk[CMD_BYTE(slot,0,0)] = 0x0a; /* read command */ 
+		writechunk[CMD_BYTE(slot,1,0)] = curcmd->address;
+		writechunk[CMD_BYTE(slot,2,0)] = curcmd->data;
+	} 
+
+}
+
+static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
+{
+	unsigned char ident, cs_slot;
+	unsigned int x;
+	unsigned int is_vpm = 0;
+
+	/* Skip audio */
+	readchunk += 66;
+	/* Search for any pending results */
+	for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+		if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) && 
+		    (wc->cmdq.cmds[x].flags & (__CMD_TX)) && 
+		    !(wc->cmdq.cmds[x].flags & (__CMD_FIN))) {
+		   	ident = wc->cmdq.cmds[x].ident;
+		   	cs_slot = wc->cmdq.cmds[x].cs_slot;
+
+		   	if (ident == wc->rxident) {
+				/* Store result */
+				wc->cmdq.cmds[x].data |= readchunk[CMD_BYTE(cs_slot,2,is_vpm)];
+				/*printk("answer in rxident=%d cs_slot=%d is %d CMD_BYTE=%d jiffies=%d\n", ident, cs_slot, last_read_command, CMD_BYTE(cs_slot, 2), jiffies); */
+				wc->cmdq.cmds[x].flags |= __CMD_FIN;
+				if (wc->cmdq.cmds[x].flags & (__CMD_WR | __CMD_LEDS))
+					/* clear out writes (and leds) since they need no ack */
+					memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
+			}
+		}
+	}
+}
+
+static inline unsigned int __t1_sdi_clk(struct t1 *wc)
+{
+	unsigned int ret;
+
+	wc->sdi &= ~SDI_CLK;
+	__t1_setctl(wc, 0x0048, wc->sdi);
+	ret = __t1_getctl(wc, 0x0048);
+	wc->sdi |= SDI_CLK;
+	__t1_setctl(wc, 0x0048, wc->sdi);
+	return ret & SDI_DIN;
+}
+
+static inline void __t1_sdi_sendbits(struct t1 *wc, unsigned int bits, int count)
+{
+	wc->sdi &= ~SDI_DREAD;
+	__t1_setctl(wc, 0x0048, wc->sdi);
+	while (count--) {
+		if (bits & (1 << count))
+			wc->sdi |= SDI_DOUT;
+		else
+			wc->sdi &= ~SDI_DOUT;
+		__t1_sdi_clk(wc);
+	}
+}
+
+static inline unsigned int __t1_sdi_recvbits(struct t1 *wc, int count)
+{
+	unsigned int bits=0;
+
+	wc->sdi |= SDI_DREAD;
+	__t1_setctl(wc, 0x0048, wc->sdi);
+	while (count--) {
+		bits <<= 1;
+		if (__t1_sdi_clk(wc))
+			bits |= 1;
+		else
+			bits &= ~1;
+	}
+	return bits;
+}
+
+static inline unsigned short __t1_getsdi(struct t1 *wc, unsigned char addr)
+{
+	unsigned int bits;
+
+	/* Send preamble */
+	bits = 0xffffffff;
+	__t1_sdi_sendbits(wc, bits, 32);
+	bits = (0x6 << 10) | (1 << 5) | (addr);
+	__t1_sdi_sendbits(wc, bits, 14);
+
+	return __t1_sdi_recvbits(wc, 18);
+}
+
+static inline unsigned short t1_getsdi(struct t1 *wc, unsigned char addr)
+{
+	unsigned long flags;
+	unsigned short val;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	val = __t1_getsdi(wc, addr);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	return val;
+}
+
+static inline void __t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value)
+{
+	unsigned int bits;
+
+	/* Send preamble */
+	bits = 0xffffffff;
+	__t1_sdi_sendbits(wc, bits, 32);
+	bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2;
+	__t1_sdi_sendbits(wc, bits, 16);
+	__t1_sdi_sendbits(wc, value, 16);
+}
+
+static inline void t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	__t1_setsdi(wc, addr, value);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int inisr, int vpm_num)
+{
+	unsigned long flags;
+	int hit;
+	int ret;
+
+
+	do {
+		if (!inisr)
+			spin_lock_irqsave(&wc->reglock, flags);
+		hit = empty_slot(wc);
+		if (hit > -1) {
+			wc->cmdq.cmds[hit].address = addr;
+			wc->cmdq.cmds[hit].data = val;
+			wc->cmdq.cmds[hit].flags |= __CMD_WR;
+			if(vpm_num >= 0) {
+				wc->cmdq.cmds[hit].flags |= __CMD_VPM;
+				wc->cmdq.cmds[hit].vpm_num = vpm_num;
+			}
+		}
+		if (inisr)
+			break;
+	
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		if (hit < 0) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit < 0);
+
+	return (hit > -1) ? 0 : -1;
+}
+
+static inline int t1_setreg(struct t1 *wc, int addr, int val)
+{
+	return t1_setreg_full(wc, addr, val, 0, NOT_VPM);
+}
+
+/***************************************************************************
+ * clean_leftovers()
+ *
+ * Check for unconsumed isr register reads and clean them up.
+ **************************************************************************/
+static inline void clean_leftovers(struct t1 *wc)
+{
+	unsigned int x;
+	int count = 0;
+	
+	/* find our requested command */
+	for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+		if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
+		    (wc->cmdq.cmds[x].flags & __CMD_ISR) &&
+		    !(wc->cmdq.cmds[x].flags & __CMD_FIN)) {
+			debug_printk(1,"leftover isr read! %d", count);
+			memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x]));
+		}
+	}
+}
+
+/********************************************************************
+ * t1_getreg_isr()
+ *
+ * Called in interrupt context to retrieve a value already requested
+ * by the normal t1_getreg().
+ *******************************************************************/
+static inline int t1_getreg_isr(struct t1 *wc, int addr)
+{
+	int hit=-1;
+	int ret;
+	unsigned int x;
+	
+	/* find our requested command */
+	for (x = 0;x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+		if ((wc->cmdq.cmds[x].flags & __CMD_RD) &&
+		    (wc->cmdq.cmds[x].flags & __CMD_FIN) &&
+		    (wc->cmdq.cmds[x].address==addr)) {
+			hit = x;
+			break;
+		}
+	}
+
+	if (hit < 0) {
+		debug_printk(2, "t1_getreg_isr() no addr=%02x\n", addr);
+		return -1; /* oops, couldn't find it */
+	}
+
+	ret = wc->cmdq.cmds[hit].data;
+	memset(&wc->cmdq.cmds[hit], 0, sizeof(struct command));
+
+	return ret;
+}
+
+static inline int t1_getreg_full(struct t1 *wc, int addr, int inisr, int vpm_num)
+{
+	unsigned long flags;
+	int hit;
+	int ret = 0;
+
+	do {
+		if (!inisr) {
+			spin_lock_irqsave(&wc->reglock, flags);
+		}
+		hit = empty_slot(wc);
+		if (hit > -1) {
+			wc->cmdq.cmds[hit].address = addr;
+			wc->cmdq.cmds[hit].data = 0x00;
+			wc->cmdq.cmds[hit].flags |= __CMD_RD;
+			if(vpm_num >= 0) {
+				wc->cmdq.cmds[hit].flags |= __CMD_VPM;
+				wc->cmdq.cmds[hit].vpm_num = vpm_num;
+			}
+			if (inisr)
+				wc->cmdq.cmds[hit].flags |= __CMD_ISR;
+		}
+		if (inisr) /* must be requested in t1_getreg_isr() */
+			return (hit > -1) ? 0 : -1;
+		else {
+			spin_unlock_irqrestore(&wc->reglock, flags);
+		}
+		if (hit < 0) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit < 0);
+
+	do {
+		spin_lock_irqsave(&wc->reglock, flags);
+		if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
+			ret = wc->cmdq.cmds[hit].data;
+			memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
+			hit = -1;
+		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		if (hit > -1) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit > -1);
+
+	return ret;
+}
+
+static inline int t1_getreg(struct t1 *wc, int addr, int inisr)
+{
+	return t1_getreg_full(wc, addr, inisr, NOT_VPM);
+}
+
+static inline int t1_setleds(struct t1 *wc, int leds, int inisr)
+{
+	unsigned long flags;
+	int hit;
+	int ret = 0;
+
+	leds = ~leds & 0x0E; /* invert the LED bits (3 downto 1)*/
+
+	do {
+		if (!inisr) {
+			spin_lock_irqsave(&wc->reglock, flags);
+		}
+		hit = empty_slot(wc);
+		if (hit > -1) {
+			wc->cmdq.cmds[hit].flags |= __CMD_LEDS;
+			wc->cmdq.cmds[hit].address = leds;
+		}
+		if (inisr) {
+			break;
+		} else {
+			spin_unlock_irqrestore(&wc->reglock, flags);
+		}
+		if (hit < 0) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit < 0);
+
+	return (hit > -1) ? 0 : -1;
+}
+
+static inline int t1_getpins(struct t1 *wc, int inisr)
+{
+	unsigned long flags;
+	int hit;
+	int ret = 0;
+
+	do {
+		spin_lock_irqsave(&wc->reglock, flags);
+		hit = empty_slot(wc);
+		if (hit > -1) {
+			wc->cmdq.cmds[hit].address = 0x00;
+			wc->cmdq.cmds[hit].data = 0x00;
+			wc->cmdq.cmds[hit].flags |= __CMD_PINS;
+		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		if (inisr)
+			return (hit > -1) ? 0 : -1;
+		if (hit < 0) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit < 0);
+
+	do {
+		spin_lock_irqsave(&wc->reglock, flags);
+		if (wc->cmdq.cmds[hit].flags & __CMD_FIN) {
+			ret = wc->cmdq.cmds[hit].data;
+			memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit]));
+			hit = -1;
+		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		if (hit > -1) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (hit > -1);
+
+	return ret;
+}
+
+static void t1_setintmask(struct t1 *wc, unsigned int intmask)
+{
+	wc->intmask = intmask;
+	t1_setctl(wc, 0x0038, intmask);
+}
+
+static void t1_enable_interrupts(struct t1 *wc)
+{
+	/* Enable interrupts */ 
+	t1_setintmask(wc, 0x00010041); /* only RX */
+}
+
+static void t1_disable_interrupts(struct t1 *wc)	
+{
+	/* Disable interrupts */
+	t1_setintmask(wc, 0x00000000);
+	t1_setctl(wc, 0x0084, 0x00000000);
+}
+
+static void t1_start_dma(struct t1 *wc)
+{
+	unsigned int reg;
+	int x;
+
+	wmb();
+	t1_setctl(wc, 0x0020, wc->descripdma);
+	t1_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE));
+	/* Start receiver/transmitter */
+	reg = t1_getctl(wc, 0x0030);
+	t1_setctl(wc, 0x0030, reg | 0x00002002);
+	t1_setctl(wc, 0x0008, 0x00000000);
+	t1_setctl(wc, 0x0010, 0x00000000);
+	reg = t1_getctl(wc, 0x0028);
+	t1_setctl(wc, 0x0028, reg);
+
+	/* Set Reset - now with MAGIC TIPS */
+	t1_setctl(wc, 0x0048, 0x00000000);
+	for (x = 0; x < 10; x++)
+		schluffen(&wc->regq);
+	/* Clear reset */
+	t1_setctl(wc, 0x0048, 0x00010000);
+	for (x = 0; x < 10; x++)
+		schluffen(&wc->regq);
+	/* Switch to caring only about receive interrupts */
+	t1_setintmask(wc, 0x00010040);
+}
+
+static void t1_stop_dma(struct t1 *wc)
+{
+	/* Disable interrupts and reset */
+	unsigned int reg;
+
+	/* Disable interrupts */
+	t1_setintmask(wc, 0x00000000);
+	t1_setctl(wc, 0x0084, 0x00000000);
+	t1_setctl(wc, 0x0048, 0x00000000);
+	/* Reset the part to be on the safe side */
+	reg = t1_getctl(wc, 0x0000);
+	reg |= 0x00000001;
+	t1_setctl(wc, 0x0000, reg);
+}
+
+static void __t1xxp_set_clear(struct t1 *wc, int channo)
+{
+	int i,j;
+	int ret;
+	unsigned short val=0;
+	
+	for (i = 0; i < 24; i++) {
+		j = (i / 8);
+		if (wc->span.chans[i].flags & ZT_FLAG_CLEAR) 
+			val |= 1 << (7 - (i % 8));
+		if (((i % 8)==7) &&  /* write byte every 8 channels */
+		    ((channo < 0) ||    /* channo=-1 means all channels */ 
+		     (j == (channo-1)/8) )) { /* only the register for this channo */    
+			ret = t1_setreg_full(wc, 0x2f + j, val, 1, NOT_VPM);
+			if (ret < 0)
+				module_printk("set_clear failed for chan %d!\n",i); 
+			val = 0;
+		}
+	}
+}
+
+static void t1_release(struct t1 *wc)
+{
+	zt_unregister(&wc->span);
+	if (wc->freeregion)
+		release_region(wc->iobase, 0xff);
+	kfree(wc);
+	printk("Freed a Wildcard TE12xP\n");
+}
+
+static void t4_serial_setup(struct t1 *wc)
+{
+	module_printk("Setting up global serial parameters for %s\n", 
+		      wc->spantype == TYPE_E1 ? (unchannelized ? "Unchannelized E1" : "E1") : "T1");
+
+	t1_setreg(wc, 0x85, 0xe0);	/* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
+	t1_setreg(wc, 0x08, 0x05);	/* IPC: Interrupt push/pull active low */
+
+	/* Global clocks (8.192 Mhz CLK) */
+	t1_setreg(wc, 0x92, 0x00);	
+	t1_setreg(wc, 0x93, 0x18);
+	t1_setreg(wc, 0x94, 0xfb);
+	t1_setreg(wc, 0x95, 0x0b);
+	t1_setreg(wc, 0x96, 0x00);
+	t1_setreg(wc, 0x97, 0x0b);
+	t1_setreg(wc, 0x98, 0xdb);
+	t1_setreg(wc, 0x99, 0xdf);
+
+	/* Configure interrupts */	
+	t1_setreg(wc, 0x46, 0xc0);	/* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+
+	/* Configure system interface */
+	t1_setreg(wc, 0x3e, 0x0a /* 0x02 */);	/* SIC1: 4.096 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
+	t1_setreg(wc, 0x3f, 0x00); 	/* SIC2: No FFS, no center receive eliastic buffer, phase 0 */
+	t1_setreg(wc, 0x40, 0x04);	/* SIC3: Edges for capture */
+	t1_setreg(wc, 0x44, 0x30);	/* CMR1: RCLK is at 8.192 Mhz dejittered */
+	t1_setreg(wc, 0x45, 0x00);	/* CMR2: We provide sync and clock for tx and rx. */
+	t1_setreg(wc, 0x22, 0x00);	/* XC0: Normal operation of Sa-bits */
+	t1_setreg(wc, 0x23, 0x04);	/* XC1: 0 offset */
+	t1_setreg(wc, 0x24, 0x00);	/* RC0: Just shy of 255 */
+	t1_setreg(wc, 0x25, 0x05);	/* RC1: The rest of RC0 */
+	
+	/* Configure ports */
+	t1_setreg(wc, 0x80, 0x00);	/* PC1: SPYR/SPYX input on RPA/XPA */
+	t1_setreg(wc, 0x81, 0x22);	/* PC2: RMFB/XSIG output/input on RPB/XPB */
+	t1_setreg(wc, 0x82, 0x65);	/* PC3: Some unused stuff */
+	t1_setreg(wc, 0x83, 0x35);	/* PC4: Some more unused stuff */
+	t1_setreg(wc, 0x84, 0x31);	/* PC5: XMFS active low, SCLKR is input, RCLK is output */
+	t1_setreg(wc, 0x86, 0x03);	/* PC6: CLK1 is Tx Clock output, CLK2 is 8.192 Mhz from DCO-R */
+	t1_setreg(wc, 0x3b, 0x00);	/* Clear LCR1 */
+}
+
+static void t1_configure_t1(struct t1 *wc, int lineconfig, int txlevel)
+{
+	unsigned int fmr4, fmr2, fmr1, fmr0, lim2;
+	char *framing, *line;
+	int mytxlevel;
+
+	if ((txlevel > 7) || (txlevel < 4))
+		mytxlevel = 0;
+	else
+		mytxlevel = txlevel - 4;
+	fmr1 = 0x9e; /* FMR1: Mode 0, T1 mode, CRC on for ESF, 2.048 Mhz system data rate, no XAIS */
+	fmr2 = 0x22; /* FMR2: no payload loopback, auto send yellow alarm */
+	if (loopback)
+		fmr2 |= 0x4;
+
+	if (j1mode)
+		fmr4 = 0x1c;
+	else
+		fmr4 = 0x0c; /* FMR4: Lose sync on 2 out of 5 framing bits, auto resync */
+
+	lim2 = 0x21; /* LIM2: 50% peak is a "1", Advanced Loss recovery */
+	lim2 |= (mytxlevel << 6);	/* LIM2: Add line buildout */
+	t1_setreg(wc, 0x1d, fmr1);
+	t1_setreg(wc, 0x1e, fmr2);
+
+	/* Configure line interface */
+	if (lineconfig & ZT_CONFIG_AMI) {
+		line = "AMI";
+		fmr0 = 0xa0;
+	} else {
+		line = "B8ZS";
+		fmr0 = 0xf0;
+	}
+	if (lineconfig & ZT_CONFIG_D4) {
+		framing = "D4";
+	} else {
+		framing = "ESF";
+		fmr4 |= 0x2;
+		fmr2 |= 0xc0;
+	}
+	t1_setreg(wc, 0x1c, fmr0);
+
+	t1_setreg(wc, 0x20, fmr4);
+	t1_setreg(wc, 0x21, 0x40);	/* FMR5: Enable RBS mode */
+
+	t1_setreg(wc, 0x37, 0xf8);	/* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+	t1_setreg(wc, 0x36, 0x08);	/* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+	t1_setreg(wc, 0x02, 0x50);	/* CMDR: Reset the receiver and transmitter line interface */
+	t1_setreg(wc, 0x02, 0x00);	/* CMDR: Reset the receiver and transmitter line interface */
+
+	t1_setreg(wc, 0x3a, lim2);	/* LIM2: 50% peak amplitude is a "1" */
+	t1_setreg(wc, 0x38, 0x0a);	/* PCD: LOS after 176 consecutive "zeros" */
+	t1_setreg(wc, 0x39, 0x15);	/* PCR: 22 "ones" clear LOS */
+
+	if (j1mode)
+		t1_setreg(wc, 0x24, 0x80); /* J1 overide */
+		
+	/* Generate pulse mask for T1 */
+	switch (mytxlevel) {
+	case 3:
+		t1_setreg(wc, 0x26, 0x07);	/* XPM0 */
+		t1_setreg(wc, 0x27, 0x01);	/* XPM1 */
+		t1_setreg(wc, 0x28, 0x00);	/* XPM2 */
+		break;
+	case 2:
+		t1_setreg(wc, 0x26, 0x8c);	/* XPM0 */
+		t1_setreg(wc, 0x27, 0x11);	/* XPM1 */
+		t1_setreg(wc, 0x28, 0x01);	/* XPM2 */
+		break;
+	case 1:
+		t1_setreg(wc, 0x26, 0x8c);	/* XPM0 */
+		t1_setreg(wc, 0x27, 0x01);	/* XPM1 */
+		t1_setreg(wc, 0x28, 0x00);	/* XPM2 */
+		break;
+	case 0:
+	default:
+		t1_setreg(wc, 0x26, 0xd7);	/* XPM0 */
+		t1_setreg(wc, 0x27, 0x22);	/* XPM1 */
+		t1_setreg(wc, 0x28, 0x01);	/* XPM2 */
+		break;
+	}
+
+	module_printk("Span configured for %s/%s\n", framing, line);
+}
+
+static void t1_configure_e1(struct t1 *wc, int lineconfig)
+{
+	unsigned int fmr2, fmr1, fmr0;
+	unsigned int cas = 0;
+	char *crc4 = "";
+	char *framing, *line;
+
+	fmr1 = 0x46; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */
+	fmr2 = 0x03; /* FMR2: Auto transmit remote alarm, auto loss of multiframe recovery, no payload loopback */
+	if (unchannelized)
+		fmr2 |= 0x30;
+	if (loopback)
+		fmr2 |= 0x4;
+	if (lineconfig & ZT_CONFIG_CRC4) {
+		fmr1 |= 0x08;	/* CRC4 transmit */
+		fmr2 |= 0xc0;	/* CRC4 receive */
+		crc4 = "/CRC4";
+	}
+	t1_setreg(wc, 0x1d, fmr1);
+	t1_setreg(wc, 0x1e, fmr2);
+
+	/* Configure line interface */
+	if (lineconfig & ZT_CONFIG_AMI) {
+		line = "AMI";
+		fmr0 = 0xa0;
+	} else {
+		line = "HDB3";
+		fmr0 = 0xf0;
+	}
+	if (lineconfig & ZT_CONFIG_CCS) {
+		framing = "CCS";
+	} else {
+		framing = "CAS";
+		cas = 0x40;
+	}
+	t1_setreg(wc, 0x1c, fmr0);
+
+	if (unchannelized)
+		t1_setreg(wc, 0x1f, 0x40);
+
+	t1_setreg(wc, 0x37, 0xf0 /*| 0x6 */ );	/* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
+	t1_setreg(wc, 0x36, 0x08);	/* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
+
+	t1_setreg(wc, 0x02, 0x50);	/* CMDR: Reset the receiver and transmitter line interface */
+	t1_setreg(wc, 0x02, 0x00);	/* CMDR: Reset the receiver and transmitter line interface */
+
+	/* Condition receive line interface for E1 after reset */
+	t1_setreg(wc, 0xbb, 0x17);
+	t1_setreg(wc, 0xbc, 0x55);
+	t1_setreg(wc, 0xbb, 0x97);
+	t1_setreg(wc, 0xbb, 0x11);
+	t1_setreg(wc, 0xbc, 0xaa);
+	t1_setreg(wc, 0xbb, 0x91);
+	t1_setreg(wc, 0xbb, 0x12);
+	t1_setreg(wc, 0xbc, 0x55);
+	t1_setreg(wc, 0xbb, 0x92);
+	t1_setreg(wc, 0xbb, 0x0c);
+	t1_setreg(wc, 0xbb, 0x00);
+	t1_setreg(wc, 0xbb, 0x8c);
+	
+	t1_setreg(wc, 0x3a, 0x20);	/* LIM2: 50% peak amplitude is a "1" */
+	t1_setreg(wc, 0x38, 0x0a);	/* PCD: LOS after 176 consecutive "zeros" */
+	t1_setreg(wc, 0x39, 0x15);	/* PCR: 22 "ones" clear LOS */
+	
+	t1_setreg(wc, 0x20, 0x9f);	/* XSW: Spare bits all to 1 */
+	if (unchannelized)
+		t1_setreg(wc, 0x21, 0x3c);
+	else
+		t1_setreg(wc, 0x21, 0x1c|cas);	/* XSP: E-bit set when async. AXS auto, XSIF to 1 */
+	
+	
+	/* Generate pulse mask for E1 */
+	t1_setreg(wc, 0x26, 0x54);	/* XPM0 */
+	t1_setreg(wc, 0x27, 0x02);	/* XPM1 */
+	t1_setreg(wc, 0x28, 0x00);	/* XPM2 */
+	module_printk("Span configured for %s/%s%s\n", framing, line, crc4);
+}
+
+static void t1xxp_framer_start(struct t1 *wc, struct zt_span *span)
+{
+	int alreadyrunning = wc->span.flags & ZT_FLAG_RUNNING;
+	unsigned long flags;
+
+	if (wc->spantype == TYPE_E1) { /* if this is an E1 card */
+		t1_configure_e1(wc, span->lineconfig);
+	} else { /* is a T1 card */
+		t1_configure_t1(wc, span->lineconfig, span->txlevel);
+		__t1xxp_set_clear(wc, -1);
+	}
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	if (!alreadyrunning) 
+		wc->span.flags |= ZT_FLAG_RUNNING;
+	spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
+static int t1xxp_startup(struct zt_span *span)
+{
+	struct t1 *wc = span->pvt;
+	int i;
+
+	/* initialize the start value for the entire chunk of last ec buffer */
+	for (i = 0; i < span->channels; i++) {
+		memset(wc->ec_chunk1[i], ZT_LIN2X(0, &span->chans[i]), ZT_CHUNKSIZE);
+		memset(wc->ec_chunk2[i], ZT_LIN2X(0, &span->chans[i]), ZT_CHUNKSIZE);
+	}
+
+	/* Reset framer with proper parameters and start */
+	t1xxp_framer_start(wc, span);
+	debug_printk(1, "Calling startup (flags is %d)\n", span->flags);
+
+	return 0;
+}
+
+static int t1xxp_shutdown(struct zt_span *span)
+{
+	struct t1 *wc = span->pvt;
+	unsigned long flags;
+
+	t1_setreg(wc, 0x46, 0x41);	/* GCR: Interrupt on Activation/Deactivation of AIX, LOS */
+	spin_lock_irqsave(&wc->reglock, flags);
+	span->flags &= ~ZT_FLAG_RUNNING;
+	spin_unlock_irqrestore(&wc->reglock, flags);
+	return 0;
+}
+
+static int t1xxp_chanconfig(struct zt_chan *chan, int sigtype)
+{
+	struct t1 *wc = chan->pvt;
+	int alreadyrunning = chan->span->flags & ZT_FLAG_RUNNING;
+
+	if (alreadyrunning && (wc->spantype != TYPE_E1))
+		__t1xxp_set_clear(wc, chan->channo);
+
+	return 0;
+}
+
+static int t1xxp_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
+{
+	struct t1 *wc = span->pvt;
+
+	/* Do we want to SYNC on receive or not */
+	wc->sync = lc->sync;
+	if (wc->sync)
+		wc->ctlreg |= 0x80;
+	else
+		wc->ctlreg &= ~0x80;
+
+	/* If already running, apply changes immediately */
+	if (span->flags & ZT_FLAG_RUNNING)
+		return t1xxp_startup(span);
+
+	return 0;
+}
+
+static int t1xxp_rbsbits(struct zt_chan *chan, int bits)
+{
+	u_char m,c;
+	int n,b;
+	struct t1 *wc = chan->pvt;
+	unsigned long flags;
+	
+	debug_printk(2, "Setting bits to %d on channel %s\n", bits, chan->name);
+	if (wc->spantype == TYPE_E1) { /* do it E1 way */
+		if (chan->chanpos == 16)
+			return 0;
+
+		n = chan->chanpos - 1;
+		if (chan->chanpos > 15) n--;
+		b = (n % 15);
+		spin_lock_irqsave(&wc->reglock, flags);	
+		c = wc->txsigs[b];
+		m = (n / 15) << 2; /* nibble selector */
+		c &= (0xf << m); /* keep the other nibble */
+		c |= (bits & 0xf) << (4 - m); /* put our new nibble here */
+		wc->txsigs[b] = c;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		  /* output them to the chip */
+		t1_setreg_full(wc,0x71 + b,c,1,NOT_VPM); 
+	} else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+		n = chan->chanpos - 1;
+		b = (n / 4);
+		spin_lock_irqsave(&wc->reglock, flags);	
+		c = wc->txsigs[b];
+		m = ((3 - (n % 4)) << 1); /* nibble selector */
+		c &= ~(0x3 << m); /* keep the other nibble */
+		c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */
+		wc->txsigs[b] = c;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		/* output them to the chip */
+		t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM); 
+		t1_setreg_full(wc,0x70 + b + 6,c,1,NOT_VPM); 
+	} else if (wc->span.lineconfig & ZT_CONFIG_ESF) {
+		n = chan->chanpos - 1;
+		b = (n / 2);
+		spin_lock_irqsave(&wc->reglock, flags);	
+		c = wc->txsigs[b];
+		m = ((n % 2) << 2); /* nibble selector */
+		c &= (0xf << m); /* keep the other nibble */
+		c |= (bits & 0xf) << (4 - m); /* put our new nibble here */
+		wc->txsigs[b] = c;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		  /* output them to the chip */
+		t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM); 
+	} 
+	debug_printk(2,"Finished setting RBS bits\n");
+
+	return 0;
+}
+
+static inline void __t1_check_sigbits_reads(struct t1 *wc)
+{
+	int i;
+
+	if (!(wc->span.flags & ZT_FLAG_RUNNING))
+		return;
+	if (wc->spantype == TYPE_E1) {
+		for (i = 0; i < 15; i++) {
+			if (t1_getreg(wc, 0x71 + i, 1))
+				wc->isrreaderrors++;
+		}
+	} else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+		for (i = 0; i < 24; i+=4) {
+			if (t1_getreg(wc, 0x70 + (i >> 2), 1))
+				wc->isrreaderrors++;
+		}
+	} else {
+		for (i = 0; i < 24; i+=2) {
+			if (t1_getreg(wc, 0x70 + (i >> 1), 1))
+				wc->isrreaderrors++;
+		}
+	}
+}
+
+static inline void __t1_check_sigbits(struct t1 *wc)
+{
+	int a,i,rxs;
+
+	if (!(wc->span.flags & ZT_FLAG_RUNNING))
+		return;
+	if (wc->spantype == TYPE_E1) {
+		for (i = 0; i < 15; i++) {
+			a = t1_getreg_isr(wc, 0x71 + i);
+			if (a > -1) {
+				/* Get high channel in low bits */
+				rxs = (a & 0xf);
+				if (!(wc->span.chans[i+16].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i+16].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i+16], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+				rxs = (a >> 4) & 0xf;
+				if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+			} else {
+				debug_printk(1, "no space to request register in isr\n");
+			}
+		}
+	} else if (wc->span.lineconfig & ZT_CONFIG_D4) {
+		for (i = 0; i < 24; i+=4) {
+			a = t1_getreg_isr(wc, 0x70 + (i>>2));
+			if (a > -1) {
+				/* Get high channel in low bits */
+				rxs = (a & 0x3) << 2;
+				if (!(wc->span.chans[i+3].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i+3].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i+3], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+				rxs = (a & 0xc);
+				if (!(wc->span.chans[i+2].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i+2].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i+2], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+				rxs = (a >> 2) & 0xc;
+				if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i+1].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i+1], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+				rxs = (a >> 4) & 0xc;
+				if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i], rxs);
+						spin_lock(&wc->reglock);
+					}	
+				}
+			}
+		}
+	} else {
+		for (i = 0; i < 24; i+=2) {
+			a = t1_getreg_isr(wc, 0x70 + (i>>1));
+			if (a > -1) {
+				/* Get high channel in low bits */
+				rxs = (a & 0xf);
+				if (!(wc->span.chans[i+1].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i+1].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i+1], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+				rxs = (a >> 4) & 0xf;
+				if (!(wc->span.chans[i].sig & ZT_SIG_CLEAR)) {
+					if (wc->span.chans[i].rxsig != rxs) {
+						spin_unlock(&wc->reglock);
+						zt_rbsbits(&wc->span.chans[i], rxs);
+						spin_lock(&wc->reglock);
+					}
+				}
+			}
+		}
+	}
+}
+
+static int t1xxp_maint(struct zt_span *span, int cmd)
+{
+	struct t1 *wc = span->pvt;
+
+	if (wc->spantype == TYPE_E1) {
+		switch (cmd) {
+		case ZT_MAINT_NONE:
+			module_printk("XXX Turn off local and remote loops E1 XXX\n");
+			break;
+		case ZT_MAINT_LOCALLOOP:
+			module_printk("XXX Turn on local loopback E1 XXX\n");
+			break;
+		case ZT_MAINT_REMOTELOOP:
+			module_printk("XXX Turn on remote loopback E1 XXX\n");
+			break;
+		case ZT_MAINT_LOOPUP:
+			module_printk("XXX Send loopup code E1 XXX\n");
+			break;
+		case ZT_MAINT_LOOPDOWN:
+			module_printk("XXX Send loopdown code E1 XXX\n");
+			break;
+		case ZT_MAINT_LOOPSTOP:
+			module_printk("XXX Stop sending loop codes E1 XXX\n");
+			break;
+		default:
+			module_printk("Unknown E1 maint command: %d\n", cmd);
+			break;
+		}
+	} else {
+		switch (cmd) {
+		case ZT_MAINT_NONE:
+			module_printk("XXX Turn off local and remote loops T1 XXX\n");
+			break;
+		case ZT_MAINT_LOCALLOOP:
+			module_printk("XXX Turn on local loop and no remote loop XXX\n");
+			break;
+		case ZT_MAINT_REMOTELOOP:
+			module_printk("XXX Turn on remote loopup XXX\n");
+			break;
+		case ZT_MAINT_LOOPUP:
+			t1_setreg(wc, 0x21, 0x50);	/* FMR5: Nothing but RBS mode */
+			break;
+		case ZT_MAINT_LOOPDOWN:
+			t1_setreg(wc, 0x21, 0x60);	/* FMR5: Nothing but RBS mode */
+			break;
+		case ZT_MAINT_LOOPSTOP:
+			t1_setreg(wc, 0x21, 0x40);	/* FMR5: Nothing but RBS mode */
+			break;
+		default:
+			module_printk("Unknown T1 maint command: %d\n", cmd);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int t1xxp_open(struct zt_chan *chan)
+{
+	struct t1 *wc = chan->pvt;
+
+	if (wc->dead)
+		return -ENODEV;
+	wc->usecount++;
+
+#ifndef LINUX26	
+	MOD_INC_USE_COUNT;
+#else
+	try_module_get(THIS_MODULE);
+#endif	
+
+	return 0;
+}
+
+static int t1xxp_close(struct zt_chan *chan)
+{
+	struct t1 *wc = chan->pvt;
+
+	wc->usecount--;
+
+#ifndef LINUX26	
+	MOD_DEC_USE_COUNT;
+#else
+	module_put(THIS_MODULE);
+#endif
+
+	/* If we're dead, release us now */
+	if (!wc->usecount && wc->dead) 
+		t1_release(wc);
+
+	return 0;
+}
+
+static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
+{
+	struct t4_regs regs;
+	unsigned int x;
+	struct t1 *wc = chan->pvt;
+
+	switch (cmd) {
+	case WCT4_GET_REGS:
+		wc = chan->pvt;
+		for (x = 0; x < sizeof(regs.pci) / sizeof(regs.pci[0]); x++)
+#if 1
+			regs.pci[x] = (inb(wc->iobase + (x << 2))) |
+				      (inb(wc->iobase + (x << 2) + 1) << 8) |
+				      (inb(wc->iobase + (x << 2) + 2) << 16) |
+				      (inb(wc->iobase + (x << 2) + 3) << 24);
+#else
+			regs.pci[x] = (inb(wc->iobase + x));
+#endif
+
+		for (x = 0; x < sizeof(regs.regs) / sizeof(regs.regs[0]); x++)
+			regs.regs[x] = t1_getreg(wc, x, 0);
+
+		if (copy_to_user((struct t4_regs *) data, &regs, sizeof(regs)))
+			return -EFAULT;
+		break;
+#ifdef VPM_SUPPORT
+	case ZT_TONEDETECT:
+		if (get_user(x, (int *) data))
+			return -EFAULT;
+		if (!wc->vpm150m)
+			return -ENOSYS;
+		if (wc->vpm150m && (x && !vpmdtmfsupport))
+			return -ENOSYS;
+		if (x & ZT_TONEDETECT_ON) {
+			set_bit(chan->chanpos - 1, &wc->dtmfmask);
+			module_printk("turning on tone detection\n");
+		} else {
+			clear_bit(chan->chanpos - 1, &wc->dtmfmask);
+			module_printk("turning off tone detection\n");
+		}
+		if (x & ZT_TONEDETECT_MUTE) {
+			if(wc->vpm150m)
+				set_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+		} else {
+			if(wc->vpm150m)
+				clear_bit(chan->chanpos - 1, &wc->vpm150m->desireddtmfmutestate);
+		}
+		return 0;
+#endif
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+#ifdef VPM_SUPPORT
+
+#include "adt_lec.c"
+
+static int t1xxp_echocan_with_params(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p)
+{
+	struct adt_lec_params params;
+	struct t1 *wc = chan->pvt;
+	struct vpm150m *vpm150m = wc->vpm150m;
+	unsigned int flags;
+	struct vpm150m_workentry *work;
+	unsigned int ret;
+
+	if (!wc->vpm150m)
+		return -ENODEV;
+
+	adt_lec_init_defaults(&params, 32);
+
+	if ((ret = adt_lec_parse_params(&params, ecp, p)))
+		return ret;
+
+	/* we can't really control the tap length, but the value is used
+	   to control whether the ec is on or off, so translate it */
+	params.tap_length = ecp->tap_length ? 1 : 0;
+
+	if (!(work = kmalloc(sizeof(*work), GFP_KERNEL)))
+		return -ENOMEM;
+
+	work->params = params;
+	work->wc = wc;
+	work->chan = chan; 
+	spin_lock_irqsave(&vpm150m->lock, flags);
+	list_add_tail(&work->list, &vpm150m->worklist);
+	spin_unlock_irqrestore(&vpm150m->lock, flags);
+	
+	/* we must do this later since we cannot sleep in the echocan function */
+	if (test_bit(VPM150M_ACTIVE, &vpm150m->control))
+		queue_work(vpm150m->wq, &vpm150m->work_echocan);
+
+	return 0; /* how do I return the status since it is done later by the workqueue? */
+}
+#endif
+
+static int t1_software_init(struct t1 *wc)
+{
+	int x;
+
+	/* Find position */
+	for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++) {
+		if (ifaces[x] == wc) {
+			debug_printk(1, "software init for card %d\n",x);
+			break;
+		}
+	}
+
+	if (x == sizeof(ifaces) / sizeof(ifaces[0]))
+		return -1;
+
+	t4_serial_setup(wc);
+
+	wc->num = x;
+	sprintf(wc->span.name, "WCT1/%d", wc->num);
+	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num);
+	wc->span.manufacturer = "Digium";
+	strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
+
+#if defined(VPM_SUPPORT)
+	if (wc->vpm150m)
+		strncat(wc->span.devicetype, " with VPMADT032", sizeof(wc->span.devicetype) - 1);
+#endif
+
+	snprintf(wc->span.location, sizeof(wc->span.location) - 1,
+		"PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+
+	wc->span.spanconfig = t1xxp_spanconfig;
+	wc->span.chanconfig = t1xxp_chanconfig;
+	wc->span.irq = wc->dev->irq;
+	wc->span.startup = t1xxp_startup;
+	wc->span.shutdown = t1xxp_shutdown;
+	wc->span.rbsbits = t1xxp_rbsbits;
+	wc->span.maint = t1xxp_maint;
+	wc->span.open = t1xxp_open;
+	wc->span.close = t1xxp_close;
+	wc->span.ioctl = t1xxp_ioctl;
+#ifdef VPM_SUPPORT
+	wc->span.echocan_with_params = t1xxp_echocan_with_params;
+#endif
+
+	if (wc->spantype == TYPE_E1) {
+		if (unchannelized)
+			wc->span.channels = 32;
+		else
+			wc->span.channels = 31;
+		wc->span.spantype = "E1";
+		wc->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
+		wc->span.deflaw = ZT_LAW_ALAW;
+	} else {
+		wc->span.channels = 24;
+		wc->span.spantype = "T1";
+		wc->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
+		wc->span.deflaw = ZT_LAW_MULAW;
+	}
+	wc->span.chans = wc->chans;
+	wc->span.flags = ZT_FLAG_RBS;
+	wc->span.pvt = wc;
+	init_waitqueue_head(&wc->span.maintq);
+	for (x = 0; x < wc->span.channels; x++) {
+		sprintf(wc->chans[x].name, "WCT1/%d/%d", wc->num, x + 1);
+		wc->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_EM_E1 | 
+				      ZT_SIG_FXSLS | ZT_SIG_FXSGS | 
+				      ZT_SIG_FXSKS | ZT_SIG_FXOLS | ZT_SIG_DACS_RBS |
+				      ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_SF;
+		wc->chans[x].pvt = wc;
+		wc->chans[x].chanpos = x + 1;
+	}
+	if (zt_register(&wc->span, 0)) {
+		module_printk("Unable to register span with Zaptel\n");
+		return -1;
+	}
+	wc->initialized = 1;
+
+	return 0;
+}
+
+#ifdef VPM_SUPPORT
+static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr) 
+{
+		return t1_getreg_full(wc, addr, 0, unit);
+}
+
+static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val) 
+{
+		return t1_setreg_full(wc, addr, val, 0, unit);
+}
+
+#endif
+
+static int t1_hardware_post_init(struct t1 *wc)
+{
+	unsigned int reg;
+	int x;
+
+	/* T1 or E1 */
+	if (t1e1override > -1) {
+		if (t1e1override)
+			wc->spantype = TYPE_E1;
+		else
+			wc->spantype = TYPE_T1;
+	} else {
+		if (t1_getpins(wc,0) & 0x01) /* returns 1 for T1 mode */
+			wc->spantype = TYPE_T1;
+		else	
+			wc->spantype = TYPE_E1;
+	}
+	debug_printk(1, "spantype: %s\n", wc->spantype==1 ? "T1" : "E1");
+	
+	if (wc->spantype == TYPE_E1) {
+		if (unchannelized)
+			wc->chanmap = chanmap_e1uc;
+		else
+			wc->chanmap = chanmap_e1;
+	} else
+		wc->chanmap = chanmap_t1;
+	/* what version of the FALC are we using? */
+	reg = t1_setreg(wc, 0x4a, 0xaa);
+	reg = t1_getreg(wc, 0x4a, 0);
+	debug_printk(1, "FALC version: %08x\n", reg);
+
+	/* make sure reads and writes work */
+	for (x = 0; x < 256; x++) {
+		t1_setreg(wc, 0x14, x);
+		if ((reg = t1_getreg(wc, 0x14, 0)) != x)
+			module_printk("Wrote '%x' but read '%x'\n", x, reg);
+	}
+
+	/* all LED's blank */
+	wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
+	wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg);
+	t1_setleds(wc, wc->ledtestreg, 0);
+
+#ifdef VPM_SUPPORT
+	t1_vpm150m_init(wc);
+	if (wc->vpm150m) {
+		module_printk("VPM present and operational (Firmware version %x)\n", wc->vpm150m->version);
+		wc->ctlreg |= 0x10; /* turn on vpm (RX audio from vpm module) */
+		if (vpmtsisupport) {
+			debug_printk(1, "enabling VPM TSI pin\n");
+			wc->ctlreg |= 0x01; /* turn on vpm timeslot interchange pin */
+		}
+	}
+#endif
+
+	return 0;
+}
+
+static inline void __t1_check_alarms_reads(struct t1 *wc)
+{
+	if (!(wc->span.flags & ZT_FLAG_RUNNING))
+		return;
+
+	if (t1_getreg(wc, 0x4c, 1))
+		wc->isrreaderrors++;
+	if (t1_getreg(wc, 0x20, 1))
+		wc->isrreaderrors++;
+	if (t1_getreg(wc, 0x4d, 1))
+		wc->isrreaderrors++;
+}
+
+static inline void __t1_check_alarms(struct t1 *wc)
+{
+	unsigned char c,d;
+	int alarms;
+	int x,j;
+	unsigned char fmr4; /* must read this always */
+
+	if (!(wc->span.flags & ZT_FLAG_RUNNING))
+		return;
+
+	c = t1_getreg_isr(wc, 0x4c);
+	fmr4 = t1_getreg_isr(wc, 0x20); /* must read this even if we don't use it */
+	d = t1_getreg_isr(wc, 0x4d);
+
+	/* Assume no alarms */
+	alarms = 0;
+
+	/* And consider only carrier alarms */
+	wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);
+
+	if (wc->spantype == TYPE_E1) {
+		if (c & 0x04) {
+			/* No multiframe found, force RAI high after 400ms only if
+			   we haven't found a multiframe since last loss
+			   of frame */
+			if (!wc->flags.nmf) {
+				t1_setreg_full(wc, 0x20, 0x9f | 0x20, 1, NOT_VPM);	/* LIM0: Force RAI High */
+				wc->flags.nmf = 1;
+				module_printk("NMF workaround on!\n");
+			}
+			t1_setreg_full(wc, 0x1e, 0xc3, 1, NOT_VPM);	/* Reset to CRC4 mode */
+			t1_setreg_full(wc, 0x1c, 0xf2, 1, NOT_VPM);	/* Force Resync */
+			t1_setreg_full(wc, 0x1c, 0xf0, 1, NOT_VPM);	/* Force Resync */
+		} else if (!(c & 0x02)) {
+			if (wc->flags.nmf) {
+				t1_setreg_full(wc, 0x20, 0x9f, 1, NOT_VPM);	/* LIM0: Clear forced RAI */
+				wc->flags.nmf = 0;
+				module_printk("NMF workaround off!\n");
+			}
+		}
+	} else {
+		/* Detect loopup code if we're not sending one */
+		if ((!wc->span.mainttimer) && (d & 0x08)) {
+			/* Loop-up code detected */
+			if ((wc->loopupcnt++ > 80)  && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) {
+				t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM);	/* LIM0: Disable any local loop */
+				t1_setreg_full(wc, 0x37, 0xf6, 1, NOT_VPM);	/* LIM1: Enable remote loop */
+				wc->span.maintstat = ZT_MAINT_REMOTELOOP;
+			}
+		} else
+			wc->loopupcnt = 0;
+		/* Same for loopdown code */
+		if ((!wc->span.mainttimer) && (d & 0x10)) {
+			/* Loop-down code detected */
+			if ((wc->loopdowncnt++ > 80)  && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) {
+				t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM);	/* LIM0: Disable any local loop */
+				t1_setreg_full(wc, 0x37, 0xf0, 1, NOT_VPM);	/* LIM1: Disable remote loop */
+				wc->span.maintstat = ZT_MAINT_NONE;
+			}
+		} else
+			wc->loopdowncnt = 0;
+	}
+
+	if (wc->span.lineconfig & ZT_CONFIG_NOTOPEN) {
+		for (x=0,j=0;x < wc->span.channels;x++)
+			if ((wc->span.chans[x].flags & ZT_FLAG_OPEN) ||
+			    (wc->span.chans[x].flags & ZT_FLAG_NETDEV))
+				j++;
+		if (!j)
+			alarms |= ZT_ALARM_NOTOPEN;
+	}
+
+	if (c & 0xa0) {
+		if (wc->alarmcount >= alarmdebounce) {
+			if (!unchannelized)
+				alarms |= ZT_ALARM_RED;
+		} else
+			wc->alarmcount++;
+	} else
+		wc->alarmcount = 0;
+	if (c & 0x4)
+		alarms |= ZT_ALARM_BLUE;
+
+	/* Keep track of recovering */
+	if ((!alarms) && wc->span.alarms) 
+		wc->alarmtimer = ZT_ALARMSETTLE_TIME;
+	if (wc->alarmtimer)
+		alarms |= ZT_ALARM_RECOVER;
+
+	/* If receiving alarms, go into Yellow alarm state */
+	if (alarms && !wc->flags.sendingyellow) {
+		module_printk("Setting yellow alarm\n");
+
+		/* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
+		t1_setreg_full(wc, 0x20, fmr4 | 0x20, 1, NOT_VPM);
+		wc->flags.sendingyellow = 1;
+	} else if (!alarms && wc->flags.sendingyellow) {
+		module_printk("Clearing yellow alarm\n");
+		/* We manually do yellow alarm to handle RECOVER  */
+		t1_setreg_full(wc, 0x20, fmr4 & ~0x20, 1, NOT_VPM);
+		wc->flags.sendingyellow = 0;
+	}
+	
+	if ((c & 0x10) && !unchannelized)
+		alarms |= ZT_ALARM_YELLOW;
+	if (wc->span.mainttimer || wc->span.maintstat) 
+		alarms |= ZT_ALARM_LOOPBACK;
+	wc->span.alarms = alarms;
+	spin_unlock(&wc->reglock);
+	zt_alarm_notify(&wc->span);
+	spin_lock(&wc->reglock);
+}
+
+static inline void __handle_leds(struct t1 *wc)
+{
+	if (wc->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE)) {
+		wc->blinktimer++;
+		if (wc->blinktimer == 160)
+			wc->ledtestreg = SET_LED_RED(wc->ledtestreg); 
+		if (wc->blinktimer == 480) {
+			wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg); 
+			wc->blinktimer = 0;
+		}
+	} else if (wc->span.alarms & ZT_ALARM_YELLOW) {
+		wc->yellowtimer++;
+		if (!(wc->yellowtimer % 2))
+			wc->ledtestreg = SET_LED_RED(wc->ledtestreg); 
+		else
+			wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg); 
+	} else {
+		if (wc->span.maintstat != ZT_MAINT_NONE)
+			wc->ledtestreg = SET_LED_ORANGE(wc->ledtestreg);
+		else
+			wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg);
+		if (wc->span.flags & ZT_FLAG_RUNNING)
+			wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg); 
+		else
+			wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg); 
+	}
+
+	if (wc->ledtestreg != wc->ledlastvalue) {
+		t1_setleds(wc, wc->ledtestreg, 1);
+		wc->ledlastvalue = wc->ledtestreg;
+	}
+}
+
+
+static void __t1_do_counters(struct t1 *wc)
+{
+	if (wc->alarmtimer) {
+		if (!--wc->alarmtimer) {
+			wc->span.alarms &= ~(ZT_ALARM_RECOVER);
+			zt_alarm_notify(&wc->span);
+		}
+	}
+}
+
+static inline void t1_isr_misc(struct t1 *wc)
+{
+	unsigned int x;
+
+	if (unlikely(!wc->initialized)) return;
+	
+	__handle_leds(wc);
+
+	__t1_do_counters(wc);
+
+	x = wc->intcount & 0xF;
+	switch (x) {
+		case 0:
+			__t1_check_sigbits_reads(wc);
+			break;
+		case 1:
+			if (!(wc->intcount & 0x30)) {
+				__t1_check_alarms_reads(wc);
+				wc->alarms_read=1;
+			}
+			break;
+		case 2:
+			break;
+		case 4:
+			break;
+		case 5:
+			break;
+		case 7:
+			__t1_check_sigbits(wc);
+			break;
+		case 8:
+			if (wc->alarms_read) {
+				__t1_check_alarms(wc);
+				wc->alarms_read=0;
+			}
+			break;
+		case 9:
+			clean_leftovers(wc);
+			break;
+	}
+}
+
+static inline void t1_transmitprep(struct t1 *wc, int dbl)
+{
+	volatile unsigned char *writechunk;
+	int x;
+	int y;
+	int chan;
+
+	dbl = dbl % 2;
+
+	writechunk = (volatile unsigned char *)(wc->writechunk);
+	if (dbl) 
+		/* Write is at interrupt address.  Start writing from normal offset */
+		writechunk += SFRAME_SIZE;
+
+	/* Calculate Transmission */
+	if (likely(wc->initialized)) {
+		spin_unlock(&wc->reglock);
+		zt_transmit(&wc->span);
+		spin_lock(&wc->reglock);
+	}
+
+	for (x = 0; x < ZT_CHUNKSIZE; x++) {
+		if (likely(wc->initialized)) {
+			for (chan = 0; chan < wc->span.channels; chan++)
+				writechunk[(chan+1)*2] = wc->chans[chan].writechunk[x];	
+		}
+
+		/* process the command queue */
+		for (y = 0; y < 7; y++) {
+			cmd_dequeue(wc, writechunk, x, y);
+		}
+#ifdef VPM_SUPPORT
+		if(likely(wc->vpm150m)) {
+			vpm150m_cmd_dequeue(wc, writechunk, x);
+		}
+#endif
+
+		if (x < ZT_CHUNKSIZE - 1) {
+			writechunk[EFRAME_SIZE] = wc->ctlreg;
+			writechunk[EFRAME_SIZE + 1] = wc->txident++;
+		}
+		writechunk += (EFRAME_SIZE + EFRAME_GAP);
+	}
+}
+
+static inline void cmd_retransmit(struct t1 *wc)
+{
+	unsigned int x;
+
+	for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) {
+		if (!(wc->cmdq.cmds[x].flags &  __CMD_FIN)) {
+			wc->cmdq.cmds[x].flags &= ~(__CMD_TX) ; /* clear __CMD_TX */
+			wc->cmdq.cmds[x].ident = 0;
+		}
+	}
+}
+
+static inline void t1_receiveprep(struct t1 *wc, int dbl)
+{
+	volatile unsigned char *readchunk;
+	int x,chan;
+	unsigned char expected;
+
+	dbl = dbl % 2;
+
+	readchunk = (volatile unsigned char *)wc->readchunk;
+	if (dbl)
+		readchunk += SFRAME_SIZE;
+	for (x = 0; x < ZT_CHUNKSIZE; x++) {
+		if (likely(wc->initialized)) {
+			for (chan = 0; chan < wc->span.channels; chan++) {
+				wc->chans[chan].readchunk[x]= readchunk[(chan+1)*2];
+			}
+		}
+		if (x < ZT_CHUNKSIZE - 1) {
+			expected = wc->rxident+1;
+			wc->rxident = readchunk[EFRAME_SIZE + 1];
+			wc->statreg = readchunk[EFRAME_SIZE + 2];
+			if (wc->rxident != expected) {
+				wc->span.irqmisses++;
+				cmd_retransmit(wc);
+				if (unlikely(debug && wc->initialized))
+					module_printk("oops: rxident=%d expected=%d\n", wc->rxident, expected);
+			}
+		}
+		cmd_decipher(wc, readchunk);
+#ifdef VPM_SUPPORT
+		if(wc->vpm150m)
+			vpm150m_cmd_decipher(wc, readchunk);
+#endif
+		readchunk += (EFRAME_SIZE + EFRAME_GAP);
+	}
+	
+	/* echo cancel */
+	if (likely(wc->initialized)) {
+		spin_unlock(&wc->reglock);
+		for (x = 0; x < wc->span.channels; x++) {
+			zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, wc->ec_chunk2[x]);
+			memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],ZT_CHUNKSIZE);
+			memcpy(wc->ec_chunk1[x],wc->chans[x].writechunk,ZT_CHUNKSIZE);
+		}
+		zt_receive(&wc->span);
+		spin_lock(&wc->reglock);
+	}
+
+	/* Wake up anyone sleeping to read/write a new register */
+	wake_up_interruptible(&wc->regq);
+}
+
+static inline int t1_check_descriptor(struct t1 *wc, int tx)
+{
+	int o2 = 0;
+
+	if (!tx) {
+		o2 += ERING_SIZE * 4;
+		o2 += wc->rdbl * 4;
+	} else {
+		o2 += wc->tdbl * 4;
+	}
+
+	if (!(wc->descripchunk[o2] & 0x80000000)) {
+		if (tx) {
+			wc->txints++;
+			t1_transmitprep(wc, wc->tdbl);
+			t1_reinit_descriptor(wc, tx, wc->tdbl, "txchk");
+			wc->tdbl = (wc->tdbl + 1) % ERING_SIZE;
+			wc->intcount++;
+			t1_isr_misc(wc);
+		} else {
+			wc->rxints++;
+			t1_receiveprep(wc, wc->rdbl);
+			t1_reinit_descriptor(wc, tx, wc->rdbl, "rxchk");
+			wc->rdbl = (wc->rdbl + 1) % ERING_SIZE;
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static int t1_hardware_init(struct t1 *wc)
+{
+	/* Hardware stuff */
+	unsigned int reg;
+	unsigned long newjiffies;
+
+	/* Initialize descriptors */
+	t1_init_descriptors(wc);
+	
+	/* Enable I/O Access */
+	pci_read_config_dword(wc->dev, PCI_COMMAND, &reg);
+	reg |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+	pci_write_config_dword(wc->dev, PCI_COMMAND, reg);
+	debug_printk(1, "PCI Config reg is %08x\n", reg);
+
+	t1_setctl(wc, 0x0000, 0xfff88001);
+
+	newjiffies = jiffies + HZ/10;
+	while(((reg = t1_getctl(wc,0x0000)) & 0x00000001) && ( time_after(newjiffies,jiffies) ));
+	debug_printk(1, "ctlreg 0x0000 now=%08x!\n", reg);
+
+	t1_setctl(wc, 0x0000, 0xfff88000);
+	
+	/* Configure watchdogs, access, etc */
+	t1_setctl(wc, 0x0030, 0x00280048);
+	t1_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */);
+
+	reg = t1_getctl(wc, 0x00fc);
+	t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); /* normal mode */
+	t1_setsdi(wc, 0x00, 0x0100);
+	t1_setsdi(wc, 0x16, 0x2100);
+	debug_printk(1, "Detected SDI REG0: %08x\n", t1_getsdi(wc, 0x00));
+	debug_printk(1, "Detected SDI REG1: %08x\n", t1_getsdi(wc, 0x01));
+	debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02));
+	
+	reg = t1_getctl(wc, 0x00fc);
+	debug_printk(1, "(pre) Reg fc is %08x\n", reg);
+
+	t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x4); /* mac only */
+	t1_setsdi(wc, 0x00, 0x0100); /* full duplex */
+	t1_setsdi(wc, 0x16, 0x2100);
+	reg = t1_getctl(wc, 0x00fc);
+	debug_printk(1, "(post) ctlreg 0xfc=%08x\n", reg);
+	debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02));
+	debug_printk(1, "ctlreg 0x0088=%08x\n", t1_getctl(wc, 0x0088));
+
+	return 0;
+}
+
+
+ZAP_IRQ_HANDLER(te12xp_interrupt)
+{
+	struct t1 *wc = dev_id;
+	unsigned int ints;
+	int res;
+
+	/* Read interrupts */
+	spin_lock(&wc->reglock);
+	ints = __t1_getctl(wc, 0x0028);
+
+	if (!ints) {
+		spin_unlock(&wc->reglock);
+#ifdef LINUX26
+		return IRQ_NONE;
+#else
+		return;
+#endif		
+	}
+
+	/* clear interrupts interrupts (we only get here if interrupt is for us) */
+	__t1_setctl(wc, 0x0028, ints);
+	ints &= wc->intmask;
+
+	if (ints & 0x00000041) { 
+		do {
+			res = t1_check_descriptor(wc, 0);
+			res |= t1_check_descriptor(wc, 1);
+		} while(res);
+	}
+	spin_unlock(&wc->reglock);
+
+#ifdef LINUX26
+	return IRQ_RETVAL(1);
+#endif		
+}
+
+static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct t1 *wc;
+	struct t1_desc *d = (struct t1_desc *) ent->driver_data;
+	unsigned int x;
+
+	for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++)
+		if (!ifaces[x]) break;
+
+	if (x >= sizeof(ifaces) / sizeof(ifaces[0])) {
+		module_printk("Too many interfaces\n");
+		return -EIO;
+	}
+	
+	if (pci_enable_device(pdev))
+		return -EIO;
+
+	wc = kmalloc(sizeof(*wc), GFP_KERNEL);
+	if (!wc)
+		return -ENOMEM;
+
+	ifaces[x] = wc;
+	memset(wc, 0, sizeof(*wc));
+	spin_lock_init(&wc->reglock);
+	wc->iobase = pci_resource_start(pdev, 0);
+	wc->dev = pdev;
+	wc->variety = d->name;
+	/* Keep track of whether we need to free the region */
+	if (request_region(wc->iobase, 0xff, te12xp_driver.name)) 
+		wc->freeregion = 1;
+	
+	/* Allocate enough memory for two zt chunks, receive and transmit.
+	 * Each sample uses 32 bits.  Allocate an extra set just for 
+	 * control too */
+	wc->writechunk = (int *) pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma);
+	if (!wc->writechunk) {
+		module_printk("Unable to allocate DMA-able memory\n");
+		if (wc->freeregion)
+			release_region(wc->iobase, 0xff);
+		kfree(wc);
+		return -ENOMEM;
+	}
+	
+	wc->readchunk = wc->writechunk + SFRAME_SIZE / 2;	/* in doublewords */
+	wc->readdma = wc->writedma + SFRAME_SIZE * 2;		/* in bytes */
+	
+	wc->descripchunk = wc->readchunk + SFRAME_SIZE / 2;	/* in doublewords */
+	wc->descripdma = wc->readdma + SFRAME_SIZE * 2;		/* in bytes */
+	
+	/* Initialize Write/Buffers to all blank data */
+	memset((void *)wc->writechunk, 0x00, SFRAME_SIZE * 2);
+	memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2);
+	
+	init_waitqueue_head(&wc->regq);
+	
+	/* Enable bus mastering */
+	pci_set_master(pdev);
+	
+	/* Keep track of which device we are */
+	pci_set_drvdata(pdev, wc);
+	
+	if (request_irq(pdev->irq, te12xp_interrupt, ZAP_IRQ_SHARED, te12xp_driver.name, wc)) {
+		module_printk("Unable to request IRQ %d\n", pdev->irq);
+		if (wc->freeregion)
+			release_region(wc->iobase, 0xff);
+		pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma);
+		pci_set_drvdata(pdev, NULL);
+		kfree(wc);
+		return -EIO;
+	}
+	
+	if (t1_hardware_init(wc)) {
+		/* Set Reset Low */
+		t1_stop_dma(wc);
+		/* Free Resources */
+		free_irq(pdev->irq, wc);
+		if (wc->freeregion)
+			release_region(wc->iobase, 0xff);
+		pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma);
+		pci_set_drvdata(pdev, NULL);
+		
+		kfree(wc);
+		return -EIO;
+		
+	}
+	
+	t1_enable_interrupts(wc);
+	t1_start_dma(wc);
+	t1_hardware_post_init(wc);
+	t1_software_init(wc);
+	module_printk("Found a %s\n", wc->variety);
+
+	return 0;
+}
+
+static void __devexit te12xp_remove_one(struct pci_dev *pdev)
+{
+	struct t1 *wc = pci_get_drvdata(pdev);
+#ifdef VPM_SUPPORT
+	unsigned long flags;
+	struct vpm150m *vpm150m = wc->vpm150m;
+#endif
+	if (!wc)
+		return;
+
+#ifdef VPM_SUPPORT
+	if(vpm150m) {
+		clear_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+		clear_bit(VPM150M_ACTIVE, &vpm150m->control);
+		flush_workqueue(vpm150m->wq);
+		destroy_workqueue(vpm150m->wq);
+	}
+#endif
+	/* Stop any DMA */
+	t1_stop_dma(wc);
+	
+	/* In case hardware is still there */
+	t1_disable_interrupts(wc);
+	
+	if (debug && wc->isrreaderrors)
+		debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors);
+
+	/* Immediately free resources */
+	free_irq(pdev->irq, wc);
+	pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma);
+
+#ifdef VPM_SUPPORT
+	if(vpm150m) {
+		spin_lock_irqsave(&wc->reglock, flags);
+		wc->vpm150m = NULL;
+		vpm150m->wc = NULL;
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		kfree(wc->vpm150m);
+	}
+#endif
+	/* Release span, possibly delayed */
+	if (!wc->usecount)
+		t1_release(wc);
+	else
+		wc->dead = 1;
+}
+
+static struct pci_device_id te12xp_pci_tbl[] = {
+	{ 0xd161, 0x0120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te120p},
+	{ 0xd161, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te121},
+	{ 0xd161, 0x8001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &te122},
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, te12xp_pci_tbl);
+
+struct pci_driver te12xp_driver = {
+	name: 	"wcte12x[p]",
+	probe: 	te12xp_init_one,
+#ifdef LINUX26
+	remove:	__devexit_p(te12xp_remove_one),
+#else
+	remove:	te12xp_remove_one,
+#endif
+	suspend: NULL,
+	resume:	NULL,
+	id_table: te12xp_pci_tbl,
+};
+
+static int __init te12xp_init(void)
+{
+	int res;
+
+	res = zap_pci_module(&te12xp_driver);
+
+	return res ? -ENODEV : 0;
+}
+
+
+static void __exit te12xp_cleanup(void)
+{
+	pci_unregister_driver(&te12xp_driver);
+}
+
+#ifdef LINUX26
+module_param(debug, int, S_IRUGO | S_IWUSR);
+module_param(loopback, int, S_IRUGO | S_IWUSR);
+module_param(t1e1override, int, S_IRUGO | S_IWUSR);
+module_param(j1mode, int, S_IRUGO | S_IWUSR);
+module_param(alarmdebounce, int, S_IRUGO | S_IWUSR);
+#ifdef VPM_SUPPORT
+module_param(vpmsupport, int, S_IRUGO | S_IWUSR);
+module_param(vpmdtmfsupport, int, S_IRUGO | S_IWUSR);
+module_param(vpmtsisupport, int, S_IRUGO | S_IWUSR);
+#endif
+#else
+MODULE_PARM(debug, "i");
+MODULE_PARM(loopback, "i");
+MODULE_PARM(t1e1override, "i");
+MODULE_PARM(j1mode, "i");
+MODULE_PARM(alarmdebounce, "i");
+#ifdef VPM_SUPPORT
+MODULE_PARM(vpmsupport, "i");
+MODULE_PARM(vpmdtmfsupport, "i");
+MODULE_PARM(vpmtsisupport, "i");
+MODULE_PARM(vpmnlptype, "i");
+MODULE_PARM(vpmnlpthresh, "i");
+MODULE_PARM(vpmnlpmaxsupp, "i");
+#endif
+#endif
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+module_init(te12xp_init);
+module_exit(te12xp_cleanup);
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/GpakApi.c.svn-base zaptel-1.4/wcte12xp/.svn/text-base/GpakApi.c.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/GpakApi.c.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/GpakApi.c.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,1613 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.c
+ *
+ * Description:
+ *   This file contains user API functions to communicate with DSPs executing
+ *   G.PAK software. The file is integrated into the host processor connected
+ *   to C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ *   06/15/05 - Initial release.
+ *   11/15/2006  - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc.  The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 "zaptel.h"
+
+#include "GpakHpi.h"
+#include "vpmadt032.h"
+#include "GpakApi.h"
+#include "gpakenum.h"
+
+#ifdef VPM_SUPPORT
+
+/* DSP to Host interface block offsets. */
+#define REPLY_MSG_PNTR_OFFSET 0     /* I/F blk offset to Reply Msg Pointer */
+#define CMD_MSG_PNTR_OFFSET 2       /* I/F blk offset to Command Msg Pointer */
+#define EVENT_MSG_PNTR_OFFSET 4     /* I/F blk offset to Event Msg Pointer */
+#define PKT_BUFR_MEM_OFFSET 6       /* I/F blk offset to Packet Buffer memory */
+#define DSP_STATUS_OFFSET 8         /* I/F blk offset to DSP Status */
+#define VERSION_ID_OFFSET 9         /* I/F blk offset to G.PAK Version Id */
+#define MAX_CMD_MSG_LEN_OFFSET 10   /* I/F blk offset to Max Cmd Msg Length */
+#define CMD_MSG_LEN_OFFSET 11       /* I/F blk offset to Command Msg Length */
+#define REPLY_MSG_LEN_OFFSET 12     /* I/F blk offset to Reply Msg Length */
+#define NUM_CHANNELS_OFFSET 13      /* I/F blk offset to Num Built Channels */
+#define NUM_PKT_CHANNELS_OFFSET 14  /* I/F blk offset to Num Pkt Channels */
+#define NUM_CONFERENCES_OFFSET 15   /* I/F blk offset to Num Conferences */
+//#define CPU_USAGE_OFFSET_1MS 16     /* I/F blk offset to CPU Usage statistics */
+#define CPU_USAGE_OFFSET 18         /* I/F blk offset to CPU Usage statistics */
+//#define CPU_USAGE_OFFSET_10MS 20    /* I/F blk offset to CPU Usage statistics */
+#define FRAMING_STATS_OFFSET 22     /* I/F blk offset to Framing statistics */
+
+//#define GPAK_RELEASE_Rate rate10ms
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
+// Macro to reconstruct a 32-bit value from two 16-bit values.
+// Parameter p32: 32-bit-wide destination
+// Parameter p16: 16-bit-wide source array of length 2 words
+#define RECONSTRUCT_LONGWORD(p32, p16) p32 = (DSP_ADDRESS)p16[0]<<16; \
+								       p32 |= (unsigned long)p16[1]
+// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 
+
+/* DSP Status value definitions. */
+#define DSP_INIT_STATUS 0x5555		/* DSP Initialized status value */
+#define HOST_INIT_STATUS 0xAAAA		/* Host Initialized status value */
+
+/* Circular packet buffer information structure offsets. */
+#define CB_BUFR_BASE 0              /* pointer to base of circular buffer */
+#define CB_BUFR_SIZE 2              /* size of buffer (words) */
+#define CB_BUFR_PUT_INDEX 3         /* offset in buffer for next write */
+#define CB_BUFR_TAKE_INDEX 4        /* offset in buffer for next read */
+#define CIRC_BUFFER_INFO_STRUCT_SIZE 6 
+
+/* Miscellaneous definitions. */
+#define MSG_BUFFER_SIZE 100 /* size (words) of Host msg buffer */
+#define WORD_BUFFER_SIZE 84  /* size of DSP Word buffer (words) */
+
+#ifdef __TMS320C55XX__ // debug sections if not on host
+#pragma DATA_SECTION(pDspIfBlk,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxCmdMsgLen,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(MaxChannels,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlByteBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(DlWordBufr,"GPAKAPIDEBUG_SECT")
+#pragma DATA_SECTION(pEventFifoAddress,"GPAKAPIDEBUG_SECT")
+#endif
+
+/* Host variables related to Host to DSP interface. */
+static DSP_ADDRESS pDspIfBlk[MAX_DSP_CORES];    /* DSP address of I/F block */
+static DSP_WORD MaxCmdMsgLen[MAX_DSP_CORES]; /* max Cmd msg length (octets) */
+static unsigned short int MaxChannels[MAX_DSP_CORES];    /* max num channels */
+
+//static unsigned short int MaxPktChannels[MAX_DSP_CORES]; /* max num pkt channels */
+//static unsigned short int MaxConfs[MAX_DSP_CORES];    /* max num conferences */
+//static DSP_ADDRESS pPktInBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS];  /* Pkt In buffer */
+//static DSP_ADDRESS pPktOutBufr[MAX_DSP_CORES][MAX_PKT_CHANNELS]; /* Pkt Out buffer */
+static DSP_ADDRESS pEventFifoAddress[MAX_DSP_CORES]; /* event fifo */
+
+static unsigned char DlByteBufr[DOWNLOAD_BLOCK_SIZE * 2]; /* Dowload byte buf */
+static DSP_WORD DlWordBufr[DOWNLOAD_BLOCK_SIZE];      /* Dowload word buffer */
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CheckDspReset - Check if the DSP was reset.
+ *
+ * FUNCTION
+ *  This function determines if the DSP was reset and is ready. If reset
+ *  occurred, it reads interface parameters and calculates DSP addresses.
+ *
+ * RETURNS
+ *  -1 = DSP is not ready.
+ *   0 = Reset did not occur.
+ *   1 = Reset occurred.
+ *
+ */
+static int CheckDspReset(
+    int DspId               /* DSP Identifier (0 to MaxDSPCores-1) */
+    )
+{
+    DSP_ADDRESS IfBlockPntr; /* Interface Block pointer */
+    DSP_WORD DspStatus;      /* DSP Status */
+    DSP_WORD DspChannels;    /* number of DSP channels */
+    //DSP_WORD DspConfs;       /* number of DSP conferences */
+    //DSP_ADDRESS PktBufrMem;  /* address of Packet Buffer */
+    DSP_WORD  Temp[2];
+    //unsigned short int i;    /* loop index / counter */
+
+    /* Read the pointer to the Interface Block. */
+    gpakReadDspMemory(DspId, DSP_IFBLK_ADDRESS, 2, Temp);
+    RECONSTRUCT_LONGWORD(IfBlockPntr, Temp);
+
+    /* If the pointer is zero, return with an indication the DSP is not
+       ready. */
+    if (IfBlockPntr == 0)
+        return (-1);
+
+    /* Read the DSP's Status. */
+    gpakReadDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1, &DspStatus);
+
+    /* If status indicates the DSP was reset, read the DSP's interface
+       parameters and calculate DSP addresses. */
+    if (DspStatus == DSP_INIT_STATUS ||
+        ((DspStatus == HOST_INIT_STATUS) && (pDspIfBlk[DspId] == 0))) 
+    {
+        /* Save the address of the DSP's Interface Block. */
+        pDspIfBlk[DspId] = IfBlockPntr;
+
+        /* Read the DSP's interface parameters. */
+        gpakReadDspMemory(DspId, IfBlockPntr + MAX_CMD_MSG_LEN_OFFSET, 1,
+                          &(MaxCmdMsgLen[DspId]));
+
+        /* read the number of configured DSP channels */
+        gpakReadDspMemory(DspId, IfBlockPntr + NUM_CHANNELS_OFFSET, 1,
+                          &DspChannels);
+        if (DspChannels > MAX_CHANNELS)
+            MaxChannels[DspId] = MAX_CHANNELS;
+        else
+            MaxChannels[DspId] = (unsigned short int) DspChannels;
+#if 0
+        /* read the number of configured DSP conferences */
+        gpakReadDspMemory(DspId, IfBlockPntr + NUM_CONFERENCES_OFFSET, 1,
+                          &DspConfs);
+        if (DspConfs > MAX_CONFS)
+            MaxConfs[DspId] = MAX_CONFS;
+        else
+            MaxConfs[DspId] = (unsigned short int) DspConfs;
+
+
+        /* read the number of configured DSP packet channels */
+        gpakReadDspMemory(DspId, IfBlockPntr + NUM_PKT_CHANNELS_OFFSET, 1,
+                          &DspChannels);
+        if (DspChannels > MAX_PKT_CHANNELS)
+            MaxPktChannels[DspId] = MAX_PKT_CHANNELS;
+        else
+            MaxPktChannels[DspId] = (unsigned short int) DspChannels;
+
+
+        /* read the pointer to the circular buffer infor struct table */
+        gpakReadDspMemory(DspId, IfBlockPntr + PKT_BUFR_MEM_OFFSET, 2, Temp);
+        RECONSTRUCT_LONGWORD(PktBufrMem, Temp);
+
+
+        /* Determine the addresses of each channel's Packet buffers. */
+        for (i = 0; i < MaxPktChannels[DspId]; i++)
+        {
+            pPktInBufr[DspId][i] = PktBufrMem;
+            pPktOutBufr[DspId][i] = PktBufrMem + CIRC_BUFFER_INFO_STRUCT_SIZE;
+            PktBufrMem += (CIRC_BUFFER_INFO_STRUCT_SIZE*2);
+        }
+#endif
+
+        /* read the pointer to the event fifo info struct */
+        gpakReadDspMemory(DspId, IfBlockPntr + EVENT_MSG_PNTR_OFFSET, 2, Temp);
+        RECONSTRUCT_LONGWORD(pEventFifoAddress[DspId], Temp);
+
+        /* Set the DSP Status to indicate the host recognized the reset. */
+        DspStatus = HOST_INIT_STATUS;
+        gpakWriteDspMemory(DspId, IfBlockPntr + DSP_STATUS_OFFSET, 1,
+                           &DspStatus);
+
+        /* Return with an indication that a reset occurred. */
+        return (1);
+    }
+
+    /* If status doesn't indicate the host recognized a reset, return with an
+       indication the DSP is not ready. */
+    if ((DspStatus != HOST_INIT_STATUS) || (pDspIfBlk[DspId] == 0))
+        return (-1);
+
+    /* Return with an indication that a reset did not occur. */
+    return (0);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * WriteDspCmdMessage - Write a Host Command/Request message to DSP.
+ *
+ * FUNCTION
+ *  This function writes a Host Command/Request message into DSP memory and
+ *  informs the DSP of the presence of the message.
+ *
+ * RETURNS
+ *  -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ *   0 = Temporarily unable to write message (previous Cmd Msg busy)
+ *   1 = Message written successfully
+ *
+ */
+static int WriteDspCmdMessage(
+    int DspId,                      /* DSP Identifier (0 to MaxDSPCores-1) */
+    DSP_WORD *pMessage,          /* pointer to Command message */
+    DSP_WORD MsgLength              /* length of message (octets) */
+    )
+{
+    DSP_WORD CmdMsgLength;      /* current Cmd message length */
+    DSP_WORD Temp[2];
+    DSP_ADDRESS BufferPointer;     /* message buffer pointer */
+
+    /* Check if the DSP was reset and is ready. */
+    if (CheckDspReset(DspId) == -1)
+        return (-1);
+
+    /* Make sure the message length is valid. */
+    if ((MsgLength < 1) || (MsgLength > MaxCmdMsgLen[DspId]))
+        return (-1);
+
+    /* Make sure a previous Command message is not in use by the DSP. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+                      &CmdMsgLength);
+    if (CmdMsgLength != 0)
+        return (0);
+
+    /* Purge any previous Reply message that wasn't read. */
+    gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+                       &CmdMsgLength);
+
+    /* Copy the Command message into DSP memory. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_PNTR_OFFSET, 2, Temp);
+    RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+    gpakWriteDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+    /* Store the message length in DSP's Command message length (flags DSP that
+       a Command message is ready). */
+    CmdMsgLength = MsgLength;
+    gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + CMD_MSG_LEN_OFFSET, 1,
+                       &CmdMsgLength);
+
+    /* Return with an indication the message was written. */
+    return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadDspReplyMessage - Read a DSP Reply message from DSP.
+ *
+ * FUNCTION
+ *  This function reads a DSP Reply message from DSP memory.
+ *
+ * RETURNS
+ *  -1 = Unable to write message (msg len or DSP Id invalid or DSP not ready)
+ *   0 = No message available (DSP Reply message empty)
+ *   1 = Message read successfully (message and length stored in variables)
+ *
+ */
+static int ReadDspReplyMessage(
+    int DspId,                      /* DSP Identifier (0 to MaxDSPCores-1) */
+    DSP_WORD *pMessage,             /* pointer to Reply message buffer */
+    DSP_WORD *pMsgLength            /* pointer to msg length var (octets) */
+    )
+{
+    DSP_WORD MsgLength;         /* message length */
+    DSP_ADDRESS BufferPointer;  /* message buffer pointer */
+    DSP_WORD Temp[2];
+
+    /* Check if the DSP was reset and is ready. */
+    if (CheckDspReset(DspId) == -1)
+        return (-1);
+
+    /* Check if a Reply message is ready. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+                      &MsgLength);
+    if (MsgLength == 0)
+        return (0);
+
+    /* Make sure the message length is valid. */
+    if (MsgLength > *pMsgLength)
+        return (-1);
+
+    /* Copy the Reply message from DSP memory. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_PNTR_OFFSET, 2, Temp);
+    RECONSTRUCT_LONGWORD(BufferPointer, Temp);
+    gpakReadDspMemory(DspId, BufferPointer, (MsgLength + 1) / 2, pMessage);
+
+    /* Store the message length in the message length variable. */
+    *pMsgLength = MsgLength;
+
+    /* Indicate a Reply message is not ready. */
+    MsgLength = 0;
+    gpakWriteDspMemory(DspId, pDspIfBlk[DspId] + REPLY_MSG_LEN_OFFSET, 1,
+                       &MsgLength);
+
+    /* Return with an indication the message was read. */
+    return (1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * ReadCircBuffer - Read from a DSP circular buffer.
+ *
+ * FUNCTION
+ *  This function reads a block of words from a DSP circular buffer. The Take
+ *  address is incremented by the number of words read adjusting for buffer
+ *  wrap.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+static void ReadCircBuffer(
+    int DspId,                  /* DSP Identifier (0 to MaxDSPCores-1) */
+    DSP_ADDRESS BufrBaseAddress,   /* address of base of circular buffer */
+    DSP_ADDRESS BufrLastAddress,   /* address of last word in buffer */
+    DSP_ADDRESS *TakeAddress,      /* pointer to address in buffer for read */
+    DSP_WORD *pWordBuffer,      /* pointer to buffer for words read */
+    DSP_WORD NumWords           /* number of words to read */
+    )
+{
+    DSP_WORD WordsTillEnd;      /* number of words until end of buffer */
+
+    /* Determine the number of words from the start address until the end of the
+       buffer. */
+    WordsTillEnd = BufrLastAddress - *TakeAddress + 1;
+
+    /* If a buffer wrap will occur, read the first part at the end of the
+       buffer followed by the second part at the beginning of the buffer. */
+    if (NumWords > WordsTillEnd)
+    {
+        gpakReadDspMemory(DspId, *TakeAddress, WordsTillEnd, pWordBuffer);
+        gpakReadDspMemory(DspId, BufrBaseAddress, NumWords - WordsTillEnd,
+                           &(pWordBuffer[WordsTillEnd]));
+        *TakeAddress = BufrBaseAddress + NumWords - WordsTillEnd;
+    }
+
+    /* If a buffer wrap will not occur, read all words starting at the current
+       take address in the buffer. */
+    else
+    {
+        gpakReadDspMemory(DspId, *TakeAddress, NumWords, pWordBuffer);
+        if (NumWords == WordsTillEnd)
+            *TakeAddress = BufrBaseAddress;
+        else
+            *TakeAddress = *TakeAddress + NumWords;
+    }
+    return;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * VerifyReply - Verify the reply message is correct for the command sent.
+ *
+ * FUNCTION
+ *  This function verifies correct reply message content for the command that
+ *  was just sent.
+ *
+ * RETURNS
+ *  0 = Incorrect
+ *  1 = Correct
+ *
+ */
+static int VerifyReply(
+    DSP_WORD *pMsgBufr,     /* pointer to Reply message buffer */
+    int CheckType,          /* reply check type */
+    DSP_WORD CheckValue     /* reply check value */
+    )
+{
+
+    /* Verify Channel or Conference Id. */
+    if (CheckType == 1)
+    {
+        if (((pMsgBufr[1] >> 8) & 0xFF) != CheckValue)
+            return (0);
+    }
+
+    /* Verify Test Mode Id. */
+    else if (CheckType == 2)
+    {
+        if (pMsgBufr[1] != CheckValue)
+            return (0);
+    }
+
+    /* Return with an indication of correct reply. */
+    return (1);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * TransactCmd - Send a command to the DSP and receive it's reply.
+ *
+ * FUNCTION
+ *  This function sends the specified command to the DSP and receives the DSP's
+ *  reply.
+ *
+ * RETURNS
+ *  Length of reply message (0 = Failure)
+ *
+ */
+static unsigned int TransactCmd(
+    int DspId,                  /* DSP Identifier (0 to MaxDSPCores-1) */
+    DSP_WORD *pMsgBufr,         /* pointer to Cmd/Reply message buffer */
+    DSP_WORD CmdLength,         /* length of command message (octets) */
+    DSP_WORD ReplyType,         /* required type of reply message */
+    DSP_WORD ReplyLength,       /* required length of reply message (octets) */
+    int ReplyCheckType,         /* reply check type */
+    DSP_WORD ReplyCheckValue    /* reply check value */
+    )
+{
+    int FuncStatus;             /* function status */
+    int LoopCount;              /* wait loop counter */
+    DSP_WORD RcvReplyLength;    /* received Reply message length */
+    DSP_WORD RcvReplyType;      /* received Reply message type code */
+    DSP_WORD RetValue;          /* return value */
+
+    /* Default the return value to indicate a failure. */
+    RetValue = 0;
+
+    /* Lock access to the DSP. */
+    gpakLockAccess(DspId);
+
+    /* Attempt to write the command message to the DSP. */
+    LoopCount = 0;
+    while ((FuncStatus = WriteDspCmdMessage(DspId, pMsgBufr, CmdLength)) != 1)
+    {
+        if (FuncStatus == -1)
+            break;
+        if (++LoopCount > MAX_WAIT_LOOPS)
+            break;
+        gpakHostDelay();
+    }
+
+    /* Attempt to read the reply message from the DSP if the command message was
+       sent successfully. */
+    if (FuncStatus == 1)
+    {
+        for (LoopCount = 0; LoopCount < MAX_WAIT_LOOPS; LoopCount++)
+        {
+            RcvReplyLength = MSG_BUFFER_SIZE * 2;
+            FuncStatus = ReadDspReplyMessage(DspId, pMsgBufr, &RcvReplyLength);
+            if (FuncStatus == 1)
+            {
+                RcvReplyType = (pMsgBufr[0] >> 8) & 0xFF;
+                if ((RcvReplyLength >= ReplyLength) &&
+                    (RcvReplyType == ReplyType) &&
+                    VerifyReply(pMsgBufr, ReplyCheckType, ReplyCheckValue))
+                {
+                    RetValue = RcvReplyLength;
+                    break;
+                }
+                else if (RcvReplyType == MSG_NULL_REPLY)
+                    break;
+            }
+            else if (FuncStatus == -1)
+                break;
+            gpakHostDelay();
+        }
+    }
+
+    /* Unlock access to the DSP. */
+    gpakUnlockAccess(DspId);
+
+    /* Return the length of the reply message (0 = failure). */
+    return (RetValue);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ *  This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakConfigPortStatus_t gpakConfigurePorts(
+    unsigned short int DspId,       /* DSP Id (0 to MaxDSPCores-1) */
+    GpakPortConfig_t *pPortConfig,  /* pointer to Port Config info */
+    GPAK_PortConfigStat_t *pStatus  /* pointer to Port Config Status */
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (CpsInvalidDsp);
+
+    /* Build the Configure Serial Ports message. */
+    MsgBuffer[0] = MSG_CONFIGURE_PORTS << 8;
+    MsgBuffer[1] = (DSP_WORD)
+                   ((pPortConfig->SlotsSelect1 << 12) |
+                    ((pPortConfig->FirstBlockNum1 << 8) & 0x0F00) |
+                    ((pPortConfig->SecBlockNum1 << 4) & 0x00F0));
+    MsgBuffer[2] = (DSP_WORD) pPortConfig->FirstSlotMask1;
+    MsgBuffer[3] = (DSP_WORD) pPortConfig->SecSlotMask1;
+    MsgBuffer[4] = (DSP_WORD)
+                   ((pPortConfig->SlotsSelect2 << 12) |
+                    ((pPortConfig->FirstBlockNum2 << 8) & 0x0F00) |
+                    ((pPortConfig->SecBlockNum2 << 4) & 0x00F0));
+    MsgBuffer[5] = (DSP_WORD) pPortConfig->FirstSlotMask2;
+    MsgBuffer[6] = (DSP_WORD) pPortConfig->SecSlotMask2;
+    MsgBuffer[7] = (DSP_WORD)
+                   ((pPortConfig->SlotsSelect3 << 12) |
+                    ((pPortConfig->FirstBlockNum3 << 8) & 0x0F00) |
+                    ((pPortConfig->SecBlockNum3 << 4) & 0x00F0));
+    MsgBuffer[8] = (DSP_WORD) pPortConfig->FirstSlotMask3;
+    MsgBuffer[9] = (DSP_WORD) pPortConfig->SecSlotMask3;
+
+    MsgBuffer[10] = (DSP_WORD)
+                   (((pPortConfig->DxDelay1 << 11) & 0x0800) |
+                    ((pPortConfig->RxDataDelay1 << 9) & 0x0600) |
+                    ((pPortConfig->TxDataDelay1 << 7) & 0x0180) |
+                    ((pPortConfig->RxClockPolarity1 << 6) & 0x0040) |
+                    ((pPortConfig->TxClockPolarity1 << 5) & 0x0020) |
+                    ((pPortConfig->RxFrameSyncPolarity1 << 4) & 0x0010) |
+                    ((pPortConfig->TxFrameSyncPolarity1 << 3) & 0x0008) |
+                    ((pPortConfig->CompandingMode1 << 1) & 0x0006) |
+                    (pPortConfig->SerialWordSize1 & 0x0001));
+
+    MsgBuffer[11] = (DSP_WORD)
+                   (((pPortConfig->DxDelay2 << 11) & 0x0800) |
+                    ((pPortConfig->RxDataDelay2 << 9) & 0x0600) |
+                    ((pPortConfig->TxDataDelay2 << 7) & 0x0180) |
+                    ((pPortConfig->RxClockPolarity2 << 6) & 0x0040) |
+                    ((pPortConfig->TxClockPolarity2 << 5) & 0x0020) |
+                    ((pPortConfig->RxFrameSyncPolarity2 << 4) & 0x0010) |
+                    ((pPortConfig->TxFrameSyncPolarity2 << 3) & 0x0008) |
+                    ((pPortConfig->CompandingMode2 << 1) & 0x0006) |
+                    (pPortConfig->SerialWordSize1 & 0x0001));
+
+    MsgBuffer[12] = (DSP_WORD)
+                   (((pPortConfig->DxDelay3 << 11) & 0x0800) |
+                    ((pPortConfig->RxDataDelay3 << 9) & 0x0600) |
+                    ((pPortConfig->TxDataDelay3 << 7) & 0x0180) |
+                    ((pPortConfig->RxClockPolarity3 << 6) & 0x0040) |
+                    ((pPortConfig->TxClockPolarity3 << 5) & 0x0020) |
+                    ((pPortConfig->RxFrameSyncPolarity3 << 4) & 0x0010) |
+                    ((pPortConfig->TxFrameSyncPolarity3 << 3) & 0x0008) |
+                    ((pPortConfig->CompandingMode3 << 1) & 0x0006) |
+                    (pPortConfig->SerialWordSize3 & 0x0001));
+
+    MsgBuffer[13] = (DSP_WORD) pPortConfig->ThirdSlotMask1;
+    MsgBuffer[14] = (DSP_WORD) pPortConfig->FouthSlotMask1;
+    MsgBuffer[15] = (DSP_WORD) pPortConfig->FifthSlotMask1;
+    MsgBuffer[16] = (DSP_WORD) pPortConfig->SixthSlotMask1;
+    MsgBuffer[17] = (DSP_WORD) pPortConfig->SevenSlotMask1;
+    MsgBuffer[18] = (DSP_WORD) pPortConfig->EightSlotMask1;
+    
+    MsgBuffer[19] = (DSP_WORD) pPortConfig->ThirdSlotMask2;;
+    MsgBuffer[20] = (DSP_WORD) pPortConfig->FouthSlotMask2;            
+    MsgBuffer[21] = (DSP_WORD) pPortConfig->FifthSlotMask2;;             
+    MsgBuffer[22] = (DSP_WORD) pPortConfig->SixthSlotMask2;            
+    MsgBuffer[23] = (DSP_WORD) pPortConfig->SevenSlotMask2;;             
+    MsgBuffer[24] = (DSP_WORD) pPortConfig->EightSlotMask2;            
+
+    MsgBuffer[25] = (DSP_WORD) pPortConfig->ThirdSlotMask3;;
+    MsgBuffer[26] = (DSP_WORD) pPortConfig->FouthSlotMask3;            
+    MsgBuffer[27] = (DSP_WORD) pPortConfig->FifthSlotMask3;;             
+    MsgBuffer[28] = (DSP_WORD) pPortConfig->SixthSlotMask3;            
+    MsgBuffer[29] = (DSP_WORD) pPortConfig->SevenSlotMask3;;             
+    MsgBuffer[30] = (DSP_WORD) pPortConfig->EightSlotMask3;            
+
+
+    /* Attempt to send the Configure Serial Ports message to the DSP and receive
+       it's reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 62, MSG_CONFIG_PORTS_REPLY, 4, 0, 0))
+        return (CpsDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    *pStatus = (GPAK_PortConfigStat_t) (MsgBuffer[1] & 0xFF);
+    if (*pStatus == Pc_Success)
+        return (CpsSuccess);
+    else
+        return (CpsParmError);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ *  This function configures a DSP's Channel.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakConfigChanStatus_t gpakConfigureChannel(
+    unsigned short int DspId,           /* DSP Id (0 to MaxDSPCores-1) */
+    unsigned short int ChannelId,       /* Channel Id (0 to MaxChannels-1) */
+    GpakChanType ChannelType,           /* Channel Type */
+    GpakChannelConfig_t *pChanConfig,   /* pointer to Channel Config info */
+    GPAK_ChannelConfigStat_t *pStatus   /* pointer to Channel Config Status */
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD MsgLength;                     /* message length */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (CcsInvalidDsp);
+
+    /* Make sure the Channel Id is valid. */
+    if (ChannelId >= MaxChannels[DspId])
+        return (CcsInvalidChannel);
+
+    /* Build the Configure Channel message based on the Channel Type. */
+    switch (ChannelType)
+    {
+
+    /* PCM to Packet channel type. */
+    case tdmToTdm:
+
+        MsgBuffer[2] = (DSP_WORD)
+                       ((pChanConfig->PcmInPortA << 8) |
+                        (pChanConfig->PcmInSlotA & 0xFF));
+        MsgBuffer[3] = (DSP_WORD)
+                       ((pChanConfig->PcmOutPortA << 8) |
+                        (pChanConfig->PcmOutSlotA & 0xFF));
+
+        MsgBuffer[4] = (DSP_WORD)
+                       ((pChanConfig->PcmInPortB << 8) |
+                        (pChanConfig->PcmInSlotB & 0xFF));
+        MsgBuffer[5] = (DSP_WORD)
+                       ((pChanConfig->PcmOutPortB << 8) |
+                        (pChanConfig->PcmOutSlotB & 0xFF));
+
+        MsgBuffer[6] = (DSP_WORD)
+                       (
+                       ((pChanConfig->FaxCngDetB <<11) & 0x0800)  |
+                       ((pChanConfig->FaxCngDetA <<10) & 0x0400)  |
+                       ((pChanConfig->MuteToneB << 9) & 0x0200)  |
+                       ((pChanConfig->MuteToneA << 8) & 0x0100)  |
+                       ((pChanConfig->FrameRate << 6)  & 0x00C0) |  
+                       ((pChanConfig->ToneTypesB << 5) & 0x0020) |
+                       ((pChanConfig->ToneTypesA << 4) & 0x0010) |
+                       ((pChanConfig->SoftwareCompand & 3) << 2) |
+                        (pChanConfig->EcanEnableB << 1) | 
+                        (pChanConfig->EcanEnableA & 1)
+						);
+                        
+        MsgBuffer[7]   = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanTapLength;       
+        MsgBuffer[8]   = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNlpType;         
+        MsgBuffer[9]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanAdaptEnable;     
+        MsgBuffer[10]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanG165DetEnable;   
+        MsgBuffer[11]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanDblTalkThresh;   
+        MsgBuffer[12]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNlpThreshold;    
+        MsgBuffer[13]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNlpConv;    
+        MsgBuffer[14]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNlpUnConv;    
+        MsgBuffer[15]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNlpMaxSuppress;    
+
+        MsgBuffer[16]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanCngThreshold;    
+        MsgBuffer[17]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanAdaptLimit;      
+        MsgBuffer[18]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanCrossCorrLimit;  
+        MsgBuffer[19]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanNumFirSegments;  
+        MsgBuffer[20]  = (DSP_WORD)
+                         pChanConfig->EcanParametersA.EcanFirSegmentLen;   
+
+        MsgBuffer[21]   = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanTapLength;       
+        MsgBuffer[22]   = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNlpType;         
+        MsgBuffer[23]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanAdaptEnable;     
+        MsgBuffer[24]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanG165DetEnable;   
+        MsgBuffer[25]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanDblTalkThresh;   
+        MsgBuffer[26]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNlpThreshold;    
+        MsgBuffer[27]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNlpConv;    
+        MsgBuffer[28]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNlpUnConv;    
+        MsgBuffer[29]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNlpMaxSuppress;    
+        MsgBuffer[30]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanCngThreshold;    
+        MsgBuffer[31]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanAdaptLimit;      
+        MsgBuffer[32]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanCrossCorrLimit;  
+        MsgBuffer[33]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanNumFirSegments;  
+        MsgBuffer[34]  = (DSP_WORD)
+                         pChanConfig->EcanParametersB.EcanFirSegmentLen;   
+
+        MsgLength = 70; // byte number == 35*2 
+        break;
+
+
+    /* Unknown (invalid) channel type. */
+    default:
+        *pStatus = Cc_InvalidChannelType;
+        return (CcsParmError);
+    }
+
+    MsgBuffer[0] = MSG_CONFIGURE_CHANNEL << 8;
+    MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ChannelType & 0xFF));
+
+    /* Attempt to send the Configure Channel message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, MsgLength, MSG_CONFIG_CHAN_REPLY, 4, 1,
+                     (DSP_WORD) ChannelId))
+        return (CcsDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    *pStatus = (GPAK_ChannelConfigStat_t) (MsgBuffer[1] & 0xFF);
+    if (*pStatus == Cc_Success)
+        return (CcsSuccess);
+    else
+        return (CcsParmError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ *  This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakTearDownStatus_t gpakTearDownChannel(
+    unsigned short int DspId,           /* DSP Id (0 to MaxDSPCores-1) */
+    unsigned short int ChannelId,       /* Channel Id (0 to MaxChannels-1) */
+    GPAK_TearDownChanStat_t *pStatus    /* pointer to Tear Down Status */
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (TdsInvalidDsp);
+
+    /* Make sure the Channel Id is valid. */
+    if (ChannelId >= MaxChannels[DspId])
+        return (TdsInvalidChannel);
+
+    /* Build the Tear Down Channel message. */
+    MsgBuffer[0] = MSG_TEAR_DOWN_CHANNEL << 8;
+    MsgBuffer[1] = (DSP_WORD) (ChannelId << 8);
+
+    /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 3, MSG_TEAR_DOWN_REPLY, 4, 1,
+	                 (DSP_WORD) ChannelId))
+        return (TdsDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    *pStatus = (GPAK_TearDownChanStat_t) (MsgBuffer[1] & 0xFF);
+    if (*pStatus == Td_Success)
+        return (TdsSuccess);
+    else
+        return (TdsError);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ *  This function controls an Algorithm
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakAlgControlStat_t gpakAlgControl(
+    unsigned short int  DspId,          // DSP identifier
+    unsigned short int  ChannelId,		// channel identifier
+    GpakAlgCtrl_t       ControlCode,    // algorithm control code
+    GPAK_AlgControlStat_t *pStatus      // pointer to return status
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (AcInvalidDsp);
+
+    /* Make sure the Channel Id is valid. */
+    if (ChannelId >= MaxChannels[DspId])
+        return (AcInvalidChannel);
+
+    MsgBuffer[0] = MSG_ALG_CONTROL << 8;
+    MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (ControlCode & 0xFF));
+
+    /* Attempt to send the Tear Down Channel message to the DSP and receive it's
+       reply. */
+	//need_reply_len;       
+	if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ALG_CONTROL_REPLY, 4, 1,  
+	                 (DSP_WORD) ChannelId))
+        return (AcDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    *pStatus = (GPAK_AlgControlStat_t) (MsgBuffer[1] & 0xFF);
+    if (*pStatus == Ac_Success)
+        return (AcSuccess);
+    else
+        return (AcParmError);
+
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ * 
+ * FUNCTION
+ *  This function reads a single event from the event fifo if one is available
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ *
+ * Notes: This function should be called in a loop until the return status 
+ *        indicates that the fifo is empty.
+ *      
+ *        If the event code equals "EventLoopbackTeardownComplete", then the 
+ *        contents of *pChannelId hold the coderBlockId that was assigned to
+ *        the loopback coder that was torn down.
+ */
+gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      *pChannelId,    // pointer to channel identifier
+    GpakAsyncEventCode_t    *pEventCode,    // pointer to Event Code
+    GpakAsyncEventData_t    *pEventData     // pointer to Event Data Struct
+    )
+{
+    DSP_WORD WordBuffer[WORD_BUFFER_SIZE];  /* DSP words buffer */
+    GpakAsyncEventCode_t EventCode;         /* DSP's event code */
+    DSP_WORD EventDataLength;               /* Length of event to read */
+    DSP_WORD ChannelId;                     /* DSP's channel Id */
+    DSP_ADDRESS EventInfoAddress;     /* address of EventFIFO info structure */
+    DSP_ADDRESS BufrBaseAddress;      /* base address of EventFIFO buffer */
+    DSP_ADDRESS BufrLastAddress;      /* last address of EventFIFO buffer */
+    DSP_ADDRESS TakeAddress;          /* current take address in fifo buffer */
+    DSP_WORD BufrSize;      /* size (in words) of event FIFO buffer */
+    DSP_WORD PutIndex;      /* event fifo put index */
+    DSP_WORD TakeIndex;     /* event fifo take index */
+    DSP_WORD WordsReady;    /* number words ready for read out of event fifo */
+    DSP_WORD EventError;    /* flag indicating error with event fifo msg  */
+    //DSP_WORD *pDebugData;   /* debug data buffer pointer in event data struct */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RefInvalidDsp);
+
+    /* Lock access to the DSP. */
+    gpakLockAccess(DspId);
+
+    /* Check if the DSP was reset and is ready. */
+    if (CheckDspReset(DspId) == -1)
+    {
+        gpakUnlockAccess(DspId);
+        return (RefDspCommFailure);
+    }
+
+    /* Check if an event message is ready in the DSP. */
+    EventInfoAddress = pEventFifoAddress[DspId];
+    gpakReadDspMemory(DspId, EventInfoAddress, CIRC_BUFFER_INFO_STRUCT_SIZE, 
+                                                                 WordBuffer);
+	RECONSTRUCT_LONGWORD(BufrBaseAddress, ((DSP_WORD *)&WordBuffer[CB_BUFR_BASE]));
+    BufrSize = WordBuffer[CB_BUFR_SIZE];
+    PutIndex = WordBuffer[CB_BUFR_PUT_INDEX];
+    TakeIndex = WordBuffer[CB_BUFR_TAKE_INDEX];
+    if (PutIndex >= TakeIndex)
+        WordsReady = PutIndex - TakeIndex;
+    else
+        WordsReady = PutIndex + BufrSize - TakeIndex;
+
+    if (WordsReady < 2)
+    {
+        gpakUnlockAccess(DspId);
+        return (RefNoEventAvail);
+    }
+
+    /* Read the event header from the DSP's Event FIFO. */
+    TakeAddress = BufrBaseAddress + TakeIndex;
+    BufrLastAddress = BufrBaseAddress + BufrSize - 1;
+    ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+                   WordBuffer, 2);
+    TakeIndex += 2;
+    if (TakeIndex >= BufrSize)
+        TakeIndex -= BufrSize;
+
+    ChannelId = (WordBuffer[0] >> 8) & 0xFF;
+    EventCode = (GpakAsyncEventCode_t)(WordBuffer[0] & 0xFF);
+    EventDataLength = WordBuffer[1];
+    EventError = 0;
+
+    switch (EventCode)
+    {
+        case EventToneDetect:
+            if (EventDataLength > WORD_BUFFER_SIZE)
+            {
+                gpakUnlockAccess(DspId);
+                return (RefInvalidEvent);
+            }
+            ReadCircBuffer(DspId, BufrBaseAddress, BufrLastAddress, &TakeAddress,
+                   WordBuffer, EventDataLength);
+            pEventData->toneEvent.ToneCode = (GpakToneCodes_t)
+                                                (WordBuffer[0] & 0xFF);
+            pEventData->toneEvent.ToneDuration = WordBuffer[1];
+            pEventData->toneEvent.Direction = WordBuffer[2];
+            pEventData->toneEvent.DebugToneStatus = WordBuffer[3];
+            TakeIndex += EventDataLength;
+            if (TakeIndex >= BufrSize)
+                TakeIndex -= BufrSize;
+            if (EventDataLength != 4)
+                EventError = 1;
+            break;
+
+        default:
+            EventError = 1;
+            break;
+    };
+
+    /* Update the Take index in the DSP's Packet Out buffer information. */
+    gpakWriteDspMemory(DspId, EventInfoAddress + CB_BUFR_TAKE_INDEX, 1,
+                       &TakeIndex);
+
+    /* Unlock access to the DSP. */
+    gpakUnlockAccess(DspId);
+
+    if (EventError)
+        return(RefInvalidEvent);
+
+    *pChannelId = ChannelId;
+    *pEventCode = EventCode;
+    return(RefEventAvail);
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ * 
+ * FUNCTION
+ *  This function checks if the DSP is still communicating with the host
+ *  and returns the DSP SW version
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakPingDspStat_t gpakPingDsp(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      *pDspSwVersion  // DSP software version
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (PngInvalidDsp);
+
+    /* send value of 1, DSP increments it */
+    MsgBuffer[0] = (MSG_PING << 8);
+
+    /* Attempt to send the ping message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 1, MSG_PING_REPLY, 6, 0, 0))
+        return (PngDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+    {
+        *pDspSwVersion = MsgBuffer[2];
+        return (PngSuccess);
+    }
+    else
+        return (PngDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ * 
+ * FUNCTION
+ *  This function controls transmission of a fixed value out onto a serial 
+ *  port's timeslot.
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      ChannelId,      // channel identifier
+    GpakSerialPort_t        PcmOutPort,     // PCM Output Serial Port Id
+    unsigned short int      PcmOutSlot,     // PCM Output Time Slot
+    unsigned short int      Value,          // 16-bit value 
+    GpakActivation          State 		    // activation state
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (TfvInvalidDsp);
+
+    /* Make sure the Channel Id is valid. */
+    if (ChannelId >= MaxChannels[DspId])
+        return (TfvInvalidChannel);
+
+
+    /* Build the message. */
+    MsgBuffer[0] = MSG_SERIAL_TXVAL << 8;
+    MsgBuffer[1] = (DSP_WORD) ((ChannelId << 8) | (State & 0xFF));
+    MsgBuffer[2] = (DSP_WORD) ((PcmOutPort << 8) | (PcmOutSlot & 0xFF));
+    MsgBuffer[3] = (DSP_WORD) Value;
+
+    /* Attempt to send the message to the DSP and receive it's
+       reply. */
+    //need_reply_len;
+	if (!TransactCmd(DspId, MsgBuffer, 8, MSG_SERIAL_TXVAL_REPLY, 4,
+	                                                    1, ChannelId))
+        return (TfvDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+        return (TfvSuccess);
+    else
+        return (TfvDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ * 
+ * FUNCTION
+ *  This function enables/disables the tdm input to output looback mode on a
+ *  serial port
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+    unsigned short int      DspId,          // DSP identifier
+    GpakSerialPort_t        SerialPort,     // Serial Port Id
+    GpakActivation          LoopBackState   // Loopback State
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (ClbInvalidDsp);
+
+    /* Build the message. */
+    MsgBuffer[0] = MSG_TDM_LOOPBACK << 8;
+    MsgBuffer[1] = (DSP_WORD) ((SerialPort << 8) | (LoopBackState & 0xFF));
+
+    /* Attempt to send the message to the DSP and receive it's
+       reply. */
+    //need_reply_len;
+	if (!TransactCmd(DspId, MsgBuffer, 4, MSG_TDM_LOOPBACK_REPLY, 4, 0, 0))
+        return (ClbDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+        return (ClbSuccess);
+    else
+        return (ClbDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ *  This function reads the CPU usage statistics from a DSP's memory. The
+ *  average CPU usage in units of .1 percent are obtained for each of the frame
+ *  rates.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakReadCpuUsageStat_t gpakReadCpuUsage(
+    unsigned short int  DspId,              // Dsp Identifier
+    unsigned short int  *pPeakUsage,        // pointer to peak usage variable
+    unsigned short int  *pPrev1SecPeakUsage // peak usage over previous 1 second   
+    )
+{
+    DSP_WORD ReadBuffer[2];     /* DSP read buffer */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RcuInvalidDsp);
+
+    /* Lock access to the DSP. */
+    gpakLockAccess(DspId);
+
+    /* Check if the DSP was reset and is ready. */
+    if (CheckDspReset(DspId) == -1)
+        return (RcuDspCommFailure);
+
+    /* Read the CPU Usage statistics from the DSP. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + CPU_USAGE_OFFSET, 2,
+                      ReadBuffer);
+
+    /* Unlock access to the DSP. */
+    gpakUnlockAccess(DspId);
+
+    /* Store the usage statistics in the specified variables. */
+    *pPrev1SecPeakUsage = ReadBuffer[0];
+    *pPeakUsage = ReadBuffer[1];
+    
+    /* Return with an indication the usage staistics were read successfully. */
+    return (RcuSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ * 
+ * FUNCTION
+ *  This function resets the cpu utilization statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+    unsigned short int  DspId              // DSP identifier
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RstcInvalidDsp);
+
+    MsgBuffer[0] = (MSG_RESET_USAGE_STATS << 8);
+
+    /* Attempt to send the message to the DSP and receive it's reply. */
+    //need_reply_len;
+	if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_USAGE_STATS_REPLY, 4, 0, 0))
+        return (RstcDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+        return (RstcSuccess);
+    else
+        return (RstcDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ * 
+ * FUNCTION
+ *  This function reads a DSP's framing interrupt statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakReadFramingStatsStatus_t gpakReadFramingStats(
+    unsigned short int  DspId,                // DSP identifier
+    unsigned short int  *pFramingError1Count, // port 1 Framing error count
+    unsigned short int  *pFramingError2Count, // port 2 Framing error count
+    unsigned short int  *pFramingError3Count, // port 3 Framing error count
+    unsigned short int  *pDmaStopErrorCount,   // DMA-stoppage error count
+    unsigned short int  *pDmaSlipStatsBuffer   // DMA slips count
+    )
+{
+    DSP_WORD ReadBuffer[10];     /* DSP read buffer */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RfsInvalidDsp);
+
+    /* Lock access to the DSP. */
+    gpakLockAccess(DspId);
+
+    /* Check if the DSP was reset and is ready. */
+    if (CheckDspReset(DspId) == -1)
+        return (RfsDspCommFailure);
+
+    /* Read the framing interrupt statistics from the DSP. */
+    gpakReadDspMemory(DspId, pDspIfBlk[DspId] + FRAMING_STATS_OFFSET, 10,
+                      ReadBuffer);
+
+    /* Unlock access to the DSP. */
+    gpakUnlockAccess(DspId);
+
+    /* Store the framing statistics in the specified variables. */
+    *pFramingError1Count = ReadBuffer[0];
+    *pFramingError2Count = ReadBuffer[1];
+    *pFramingError3Count = ReadBuffer[2];
+    *pDmaStopErrorCount  = ReadBuffer[3];
+    
+    if(pDmaSlipStatsBuffer != 0) 
+    // If users want to get the DMA slips count
+    {
+	    pDmaSlipStatsBuffer[0] = ReadBuffer[4];
+    	pDmaSlipStatsBuffer[1] = ReadBuffer[5];
+    	pDmaSlipStatsBuffer[2] = ReadBuffer[6];
+    	pDmaSlipStatsBuffer[3] = ReadBuffer[7];
+    	pDmaSlipStatsBuffer[4] = ReadBuffer[8];
+    	pDmaSlipStatsBuffer[5] = ReadBuffer[9];
+    
+    }
+    /* Return with an indication the statistics were read successfully. */
+    return (RfsSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ * 
+ * FUNCTION
+ *  This function resets a DSP's framing interrupt statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakResetFramingStatsStatus_t gpakResetFramingStats(
+    unsigned short int      DspId          // DSP identifier
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RstfInvalidDsp);
+
+    MsgBuffer[0] = (MSG_RESET_FRAME_STATS << 8);
+
+    /* Attempt to send the message to the DSP and receive it's reply. */
+    //need_reply_len;
+	if (!TransactCmd(DspId, MsgBuffer, 2, MSG_RESET_FRAME_STATS_REPLY, 4, 0, 0))
+        return (RstfDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+        return (RstfSuccess);
+    else
+        return (RstfDspCommFailure);
+}
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ *  This function reads a DSP's Program and Data memory image from the
+ *  specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakDownloadStatus_t gpakDownloadDsp(
+    unsigned short DspId,   /* DSP Identifier (0 to MaxDSPCores-1) */
+    GPAK_FILE_ID FileId     /* G.PAK Download File Identifier */
+    )
+{
+    gpakDownloadStatus_t RetStatus;     /* function return status */
+    int NumRead;                        /* number of file bytes read */
+    DSP_ADDRESS Address;                /* DSP address */
+    unsigned int WordCount;             /* number of words in record */
+    unsigned int NumWords;              /* number of words to read/write */
+    unsigned int i;                     /* loop index / counter */
+    unsigned int j;                     /* loop index */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (GdlInvalidDsp);
+
+    /* Lock access to the DSP. */
+    gpakLockAccess(DspId);
+
+    RetStatus = GdlSuccess;
+    while (RetStatus == GdlSuccess)
+    {
+
+        /* Read a record header from the file. */
+        NumRead = gpakReadFile(FileId, DlByteBufr, 6);
+        if (NumRead == -1)
+        {
+            RetStatus = GdlFileReadError;
+            break;
+        }
+        if (NumRead != 6)
+        {
+            RetStatus = GdlInvalidFile;
+            break;
+        }
+        Address = (((DSP_ADDRESS) DlByteBufr[1]) << 16) |
+                  (((DSP_ADDRESS) DlByteBufr[2]) << 8) |
+                  ((DSP_ADDRESS) DlByteBufr[3]);
+        WordCount = (((unsigned int) DlByteBufr[4]) << 8) |
+                    ((unsigned int) DlByteBufr[5]);
+
+        /* Check for the End Of File record. */
+        if (DlByteBufr[0] == 0xFF)
+            break;
+
+        /* Verify the record is for a valid memory type. */
+        if ((DlByteBufr[0] != 0x00) && (DlByteBufr[0] != 0x01))
+        {
+            RetStatus = GdlInvalidFile;
+            break;
+        }
+
+        /* Read a block of words at a time from the file and write to the
+           DSP's memory .*/
+        while (WordCount != 0)
+        {
+            if (WordCount < DOWNLOAD_BLOCK_SIZE)
+                NumWords = WordCount;
+            else
+                NumWords = DOWNLOAD_BLOCK_SIZE;
+            WordCount -= NumWords;
+            NumRead = gpakReadFile(FileId, DlByteBufr, NumWords * 2);
+            if (NumRead == -1)
+            {
+                RetStatus = GdlFileReadError;
+                break;
+            }
+            if (NumRead != (NumWords * 2))
+            {
+                RetStatus = GdlInvalidFile;
+                break;
+            }
+            for (i = 0, j = 0; i < NumWords; i++, j += 2)
+                DlWordBufr[i] = (((DSP_WORD) DlByteBufr[j]) << 8) |
+                                ((DSP_WORD) DlByteBufr[j + 1]);
+            gpakWriteDspMemory(DspId, Address, NumWords, DlWordBufr);
+            Address += ((DSP_ADDRESS) NumWords);
+        }
+    }
+
+    /* Unlock access to the DSP. */
+    gpakUnlockAccess(DspId);
+
+    /* Return with an indication of success or failure. */
+    return (RetStatus);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - Read CPU usage statistics from a DSP.
+ *
+ * FUNCTION
+ *  This function reads the memory map register section of DSP memory. 
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+    unsigned short int  DspId,         // Dsp Identifier
+    unsigned short int  *pDest,        // Buffer on host to hold DSP memory map
+	DSP_ADDRESS BufrBaseAddress,       // DSP memory users want to read out
+    unsigned short int   MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP reply's status */
+    int i;                                  /* loop index / counter */
+
+    
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RmmInvalidDsp);
+
+    /* Verify the message buffer is large enough  */
+    if (MSG_BUFFER_SIZE < MemoryLength_Word16 )
+        return (RmmSizeTooBig);
+
+    MsgBuffer[0] = MSG_READ_DSP_MEMORY << 8;
+    MsgBuffer[1] = (DSP_WORD) ((BufrBaseAddress >> 16) & 0xFFFF);
+    MsgBuffer[2] = (DSP_WORD) (BufrBaseAddress & 0xFFFF);
+    MsgBuffer[3] = (DSP_WORD) MemoryLength_Word16;
+
+    /* Attempt to send the Read memory section message to the DSP and receive it's
+       reply. */
+	//need_reply_len;       
+	if (!TransactCmd(DspId, MsgBuffer, 8, MSG_READ_DSP_MEMORY_REPLY, 
+			(MemoryLength_Word16+2)*2, 0,  0) )
+        return (RmmInvalidAddress);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus != 0)
+        return (RmmFailure);
+
+	for (i = 0; i < MemoryLength_Word16; i++)
+        pDest[i] = (short int) MsgBuffer[2 + i];
+
+
+    return (RmmSuccess);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAccessGPIO - change Direction/read/write the GPIO on DSP 
+ * 
+ * FUNCTION
+ *  This function read/write GPIO and change the GPIO direction
+ *  
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+gpakAccessGPIOStat_t gpakAccessGPIO(
+    unsigned short int      DspId,          // DSP identifier
+	GpakGPIOCotrol_t        gpakControlGPIO,// select oeration, changeDIR/write/read
+    unsigned short int      *pGPIOValue  // DSP software version
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (GPIOInvalidDsp);
+
+    /* send value of 1, DSP increments it */
+    MsgBuffer[0] = (MSG_ACCESSGPIO << 8);
+	MsgBuffer[1] = (DSP_WORD) ((gpakControlGPIO << 8) | (*pGPIOValue & 0xFF) );
+    /* Attempt to send the ping message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 4, MSG_ACCESSGPIO_REPLY, 6, 0, 0))
+        return (GPIODspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+    {
+        *pGPIOValue = MsgBuffer[2];
+        return (GPIOSuccess);
+    }
+    else
+        return (GPIODspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteSystemParms - Write a DSP's System Parameters.
+ *
+ * FUNCTION
+ *  This function writes a DSP's System Parameters information.
+ *
+ *    Note:
+ *      Or-together the desired bit-mask #defines that are listed below. Only
+ *      those algorithm parameters whose bit-mask is selected in the UpdateBits
+ *      function parameter will be updated.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+
+gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+    unsigned short int      DspId,  // DSP identifier
+    GpakSystemParms_t *pSysParms,   /* pointer to System Parms info var */
+    unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+    GPAK_SysParmsStat_t *pStatus    /* pointer to Write System Parms Status */
+    )
+{
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+    DSP_WORD DspStatus;                     /* DSP's reply status */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (WspInvalidDsp);
+
+    /* Build the Write System Parameters message. */
+    MsgBuffer[0] = MSG_WRITE_SYS_PARMS << 8;
+
+    if (UpdateBits & DTMF_UPDATE_MASK)
+    {
+        MsgBuffer[1] |= DTMF_UPDATE_MASK;
+        MsgBuffer[8] = (DSP_WORD) pSysParms->MinSigLevel;
+        MsgBuffer[9] = (DSP_WORD) (pSysParms->FreqDeviation & 0xff);
+        if (pSysParms->SNRFlag)
+            MsgBuffer[9] |= (1<<8);
+    }
+
+    MsgBuffer[10] = (DSP_WORD) 0;
+    if (UpdateBits & DTMF_TWIST_UPDATE_MASK)
+    {
+        MsgBuffer[1] |= DTMF_TWIST_UPDATE_MASK;
+        MsgBuffer[10] |= (DSP_WORD) (pSysParms->DtmfFwdTwist & 0x000f);
+        MsgBuffer[10] |= (DSP_WORD) ((pSysParms->DtmfRevTwist << 4) & 0x00f0);
+    }
+
+
+    if (UpdateBits & DTMF_VALID_MASK)
+    {
+        MsgBuffer[1] |= DTMF_VALID_MASK;
+	    MsgBuffer[11] = (DSP_WORD) (pSysParms->DtmfValidityMask & 0x00ff);
+	}
+
+    /* Attempt to send the ping message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 24, MSG_WRITE_SYS_PARMS_REPLY, 6, 0, 0))
+        return (WspDspCommFailure);
+
+    /* Return with an indication of success or failure based on the return
+       status in the reply message. */
+    *pStatus = (GPAK_SysParmsStat_t) (MsgBuffer[2] );
+
+    DspStatus = (MsgBuffer[1] & 0xFF);
+    if (DspStatus == 0)
+        return (WspSuccess);
+    else
+        return (WspDspCommFailure);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadSystemParms - Read a DSP's System Parameters.
+ *
+ * FUNCTION
+ *  This function reads a DSP's System Parameters information.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+gpakReadSysParmsStatus_t gpakReadSystemParms(
+    unsigned short int      DspId,  // DSP identifier
+    GpakSystemParms_t *pSysParms    /* pointer to System Parms info var */
+    )
+{
+
+    DSP_WORD MsgBuffer[MSG_BUFFER_SIZE];    /* message buffer */
+
+    /* Make sure the DSP Id is valid. */
+    if (DspId >= MAX_DSP_CORES)
+        return (RspInvalidDsp);
+
+    /* Build the Read System Parameters message. */
+    MsgBuffer[0] = MSG_READ_SYS_PARMS << 8;
+
+    /* Attempt to send the ping message to the DSP and receive it's
+       reply. */
+	if (!TransactCmd(DspId, MsgBuffer, 2, MSG_READ_SYS_PARMS_REPLY, 22, 0, 0))
+        return (RspDspCommFailure);
+
+    /* Extract the System Parameters information from the message. */
+    pSysParms->DtmfValidityMask = (short int)(MsgBuffer[7]) ;
+
+    pSysParms->MinSigLevel   =  (short int)MsgBuffer[8];
+    pSysParms->SNRFlag       = (short int)((MsgBuffer[9]>>8) & 0x1);
+    pSysParms->FreqDeviation =  (short int)(MsgBuffer[9] & 0xff);
+    pSysParms->DtmfFwdTwist  = (short int)MsgBuffer[10] & 0x000f;
+    pSysParms->DtmfRevTwist  = (short int)(MsgBuffer[10] >> 4) & 0x000f;
+
+    /* Return with an indication that System Parameters info was obtained. */
+    return (RspSuccess);
+}
+#endif
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/GpakApi.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/GpakApi.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/GpakApi.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/GpakApi.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2005 , Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakApi.h
+ *
+ * Description:
+ *   This file contains the function prototypes and data types for the user
+ *   API functions that communicate with DSPs executing G.PAK software. The
+ *   file is used by application software in the host processor connected to
+ *   C55X G.PAK DSPs via a Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ *   06/15/05 - Initial release.
+ *   11/15/2006  - 24 TDM-TDM Channels EC release
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc.  The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _GPAKAPI_H  /* prevent multiple inclusion */
+#define _GPAKAPI_H
+#include "GpakErrs.h"
+#include "gpakenum.h"
+
+// Bit masks to select which algorithm's parameters to update: Or-together the
+// desired masks into the UpdateBits function parameter.
+#define DTMF_UPDATE_MASK        0x0010   // update DTMF params, MinLevel, SNRFlag and Freq
+#define DTMF_TWIST_UPDATE_MASK  0x0020   // update DTMF TWIST system params
+#define DTMF_VALID_MASK         0x0080   // update DTMF ValidMask params
+
+#define DSP_DEBUG_BUFF_SIZE 42      // units of 16-bit words
+
+/* Definition of an Asynchronous Event Data Structure */
+typedef union
+{
+    struct
+    {
+        GpakToneCodes_t    ToneCode;       // detected tone code
+        unsigned short int ToneDuration;   // tone duration
+        GpakTdmDirection   Direction;      // detected on A r B side
+        short int          DebugToneStatus;// reserved for debug info
+    } toneEvent;
+
+} GpakAsyncEventData_t;
+
+/* Definition of an Echo Canceller Parameters information structure. */
+typedef struct
+{
+    short int EcanTapLength;       // Echo Can Num Taps (tail length) 
+    short int EcanNlpType;         // Echo Can NLP Type 
+    short int EcanAdaptEnable;     // Echo Can Adapt Enable flag 
+    short int EcanG165DetEnable;   // Echo Can G165 Detect Enable flag 
+    short int EcanDblTalkThresh;   // Echo Can Double Talk threshold 
+    short int EcanNlpThreshold;    // Echo Can NLP threshold 
+    short int EcanNlpConv;  // Dynamic NLP control, NLP limit when EC about to converged
+    short int EcanNlpUnConv;// Dynamic NLP control, NLP limit when EC not converged yet
+    short int EcanNlpMaxSuppress; // suppression level for NLP_SUPP mode
+    short int EcanCngThreshold;    // Echo Can CNG Noise threshold 
+    short int EcanAdaptLimit;      // Echo Can Max Adapts per frame 
+    short int EcanCrossCorrLimit;  // Echo Can Cross Correlation limit 
+    short int EcanNumFirSegments;  // Echo Can Num FIR Segments 
+    short int EcanFirSegmentLen;   // Echo Can FIR Segment Length 
+} GpakEcanParms_t;
+
+/* Definition of a Channel Configuration information structure. */
+typedef struct
+{
+    GpakSerialPort_t    PcmInPortA;         // A side PCM Input Serial Port Id 
+    unsigned short int  PcmInSlotA;         // A side PCM Input Time Slot 
+    GpakSerialPort_t    PcmOutPortA;        // A side PCM Output Serial Port Id 
+    unsigned short int  PcmOutSlotA;        // A side PCM Output Time Slot 
+    GpakSerialPort_t    PcmInPortB;         // B side PCM Input Serial Port Id 
+    unsigned short int  PcmInSlotB;         // B side PCM Input Time Slot 
+    GpakSerialPort_t    PcmOutPortB;        // B side PCM Output Serial Port Id 
+    unsigned short int  PcmOutSlotB;        // B side PCM Output Time Slot 
+    GpakToneTypes       ToneTypesA;         // A side Tone Detect Types
+    GpakToneTypes       ToneTypesB;         // B side Tone Detect Types
+    GpakActivation      EcanEnableA;        // Echo Cancel A Enabled
+    GpakActivation      EcanEnableB;        // Echo Cancel B Enabled
+    GpakEcanParms_t     EcanParametersA;    // Echo Cancel parameters 
+    GpakEcanParms_t     EcanParametersB;    // Echo Cancel parameters 
+    GpakCompandModes    SoftwareCompand;    // software companding
+    GpakRate_t          FrameRate;          // Gpak Frame Rate 
+    GpakActivation      MuteToneA;          // A side mute DTMF Enabled
+    GpakActivation      MuteToneB;          // B side mute DTMF Enabled
+    GpakActivation      FaxCngDetA;         // A side FaxCng Tone Detector Enabled
+    GpakActivation      FaxCngDetB;         // B side FaxCng Tone Detector Enabled
+
+} GpakChannelConfig_t;
+
+
+/* Definition of a Serial Port Configuration Structure */
+typedef struct
+{
+    GpakSlotCfg_t SlotsSelect1;         // port 1 Slot selection
+    unsigned short int FirstBlockNum1;  // port 1 first group Block Number
+    unsigned short int FirstSlotMask1;  // port 1 first group Slot Mask
+    unsigned short int SecBlockNum1;    // port 1 second group Block Number
+    unsigned short int SecSlotMask1;    // port 1 second group Slot Mask
+
+    GpakSerWordSize_t  SerialWordSize1; // port 1 serial word size 
+    GpakCompandModes   CompandingMode1; // port 1 companding mode
+    GpakSerFrameSyncPol_t TxFrameSyncPolarity1; // port 1 Tx Frame Sync Polarity
+    GpakSerFrameSyncPol_t RxFrameSyncPolarity1; // port 1 Rx Frame Sync Polarity
+    GpakSerClockPol_t  TxClockPolarity1;        // port 1 Tx Clock Polarity
+    GpakSerClockPol_t  RxClockPolarity1;        // port 1 Rx Clock Polarity
+    GpakSerDataDelay_t TxDataDelay1;            // port 1 Tx data delay
+    GpakSerDataDelay_t RxDataDelay1;            // port 1 Rx data delay
+    GpakActivation     DxDelay1;                // port 1 DX Delay
+
+    unsigned short int ThirdSlotMask1;  // port 1 3rd group Slot Mask
+    unsigned short int FouthSlotMask1;  // port 1 4th group Slot Mask
+    unsigned short int FifthSlotMask1;  // port 1 5th group Slot Mask
+    unsigned short int SixthSlotMask1;  // port 1 6th group Slot Mask
+    unsigned short int SevenSlotMask1;  // port 1 7th group Slot Mask
+    unsigned short int EightSlotMask1;  // port 1 8th group Slot Mask
+
+
+    GpakSlotCfg_t SlotsSelect2;         // port 2 Slot selection
+    unsigned short int FirstBlockNum2;  // port 2 first group Block Number
+    unsigned short int FirstSlotMask2;  // port 2 first group Slot Mask
+    unsigned short int SecBlockNum2;    // port 2 second group Block Number
+    unsigned short int SecSlotMask2;    // port 2 second group Slot Mask
+    GpakSerWordSize_t  SerialWordSize2; // port 2 serial word size 
+    GpakCompandModes   CompandingMode2; // port 2 companding mode
+    GpakSerFrameSyncPol_t TxFrameSyncPolarity2; // port 2 Tx Frame Sync Polarity
+    GpakSerFrameSyncPol_t RxFrameSyncPolarity2; // port 2 Rx Frame Sync Polarity
+    GpakSerClockPol_t  TxClockPolarity2;        // port 2 Tx Clock Polarity
+    GpakSerClockPol_t  RxClockPolarity2;        // port 2 Rx Clock Polarity
+    GpakSerDataDelay_t TxDataDelay2;            // port 2 Tx data delay
+    GpakSerDataDelay_t RxDataDelay2;            // port 2 Rx data delay
+    GpakActivation     DxDelay2;                // port 2 DX Delay
+    
+    unsigned short int ThirdSlotMask2;  // port 2 3rd group Slot Mask
+    unsigned short int FouthSlotMask2;  // port 2 4th group Slot Mask
+    unsigned short int FifthSlotMask2;  // port 2 5th group Slot Mask
+    unsigned short int SixthSlotMask2;  // port 2 6th group Slot Mask
+    unsigned short int SevenSlotMask2;  // port 2 7th group Slot Mask
+    unsigned short int EightSlotMask2;  // port 2 8th group Slot Mask
+
+    GpakSlotCfg_t SlotsSelect3;         // port 3 Slot selection
+    unsigned short int FirstBlockNum3;  // port 3 first group Block Number
+    unsigned short int FirstSlotMask3;  // port 3 first group Slot Mask
+    unsigned short int SecBlockNum3;    // port 3 second group Block Number
+    unsigned short int SecSlotMask3;    // port 3 second group Slot Mask
+    GpakSerWordSize_t  SerialWordSize3; // port 3 serial word size 
+    GpakCompandModes   CompandingMode3; // port 3 companding mode
+    GpakSerFrameSyncPol_t TxFrameSyncPolarity3; // port 3 Tx Frame Sync Polarity
+    GpakSerFrameSyncPol_t RxFrameSyncPolarity3; // port 3 Rx Frame Sync Polarity
+    GpakSerClockPol_t  TxClockPolarity3;        // port 3 Tx Clock Polarity
+    GpakSerClockPol_t  RxClockPolarity3;        // port 3 Rx Clock Polarity
+    GpakSerDataDelay_t TxDataDelay3;            // port 3 Tx data delay
+    GpakSerDataDelay_t RxDataDelay3;            // port 3 Rx data delay
+    GpakActivation     DxDelay3;                // port 3 DX Delay
+
+    unsigned short int ThirdSlotMask3;  // port 3 3rd group Slot Mask
+    unsigned short int FouthSlotMask3;  // port 3 4th group Slot Mask
+    unsigned short int FifthSlotMask3;  // port 3 5th group Slot Mask
+    unsigned short int SixthSlotMask3;  // port 3 6th group Slot Mask
+    unsigned short int SevenSlotMask3;  // port 3 7th group Slot Mask
+    unsigned short int EightSlotMask3;  // port 3 8th group Slot Mask
+
+} GpakPortConfig_t;
+
+/* Definition of a Tone Generation Parameter Structure */
+/*
+typedef struct
+{
+    GpakToneGenType_t ToneType;         // Tone Type
+    unsigned short int Frequency[4];    // Frequency (Hz)
+    short int Level[4];                 // Frequency's Level (1 dBm)
+    unsigned short int OnTime[4];       // On Times (msecs)
+    unsigned short int OffTime[4];      // Off Times (msecs)
+} GpakToneGenParms_t;
+*/
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigureChannel return status. */
+typedef enum
+{
+    CcsSuccess = 0,           /* Channel Configured successfully */
+    CcsParmError = 1,         /* Channel Config Parameter error */
+    CcsInvalidChannel = 2,    /* invalid channel */
+    CcsInvalidDsp = 3,        /* invalid DSP */
+    CcsDspCommFailure = 4     /* failed to communicate with DSP */
+} gpakConfigChanStatus_t;
+
+/*
+ * gpakConfigureChannel - Configure a DSP's Channel.
+ *
+ * FUNCTION
+ *  This function configures a DSP's Channel.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigChanStatus_t gpakConfigureChannel(
+    unsigned short int      DspId,       // DSP identifier
+    unsigned short int      ChannelId,   // channel identifier
+    GpakChanType            ChannelType, // channel type
+    GpakChannelConfig_t     *pChanConfig, // pointer to channel config info 
+    GPAK_ChannelConfigStat_t *pStatus    // pointer to Channel Config Status
+    );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakTearDownChannel return status. */
+typedef enum
+{
+    TdsSuccess = 0,         /* Channel Tear Down successful */
+    TdsError = 1,           /* Channel Tear Down error */
+    TdsInvalidChannel = 2,  /* invalid channel */
+    TdsInvalidDsp = 3,      /* invalid DSP */
+    TdsDspCommFailure = 4   /* failed to communicate with DSP */
+} gpakTearDownStatus_t;
+
+/*
+ * gpakTearDownChannel - Tear Down a DSP's Channel.
+ *
+ * FUNCTION
+ *  This function tears down a DSP's Channel.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+
+extern gpakTearDownStatus_t gpakTearDownChannel(
+    unsigned short int      DspId,      // DSP identifier
+    unsigned short int      ChannelId,  // channel identifier
+    GPAK_TearDownChanStat_t *pStatus    // pointer to Tear Down Status
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakAlgControl return status. */
+typedef enum
+{
+    AcSuccess = 0,         /* control successful */
+    AcInvalidChannel = 1,  /* invalid channel identifier */
+    AcInvalidDsp = 2,      /* invalid DSP */
+    AcParmError = 3,       /* invalid control parameter */
+    AcDspCommFailure = 4   /* failed to communicate with DSP */
+} gpakAlgControlStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakAlgControl - Control an Algorithm.
+ *
+ * FUNCTION
+ *  This function controls an Algorithm
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+extern gpakAlgControlStat_t gpakAlgControl(
+    unsigned short int  DspId,          // DSP identifier
+    unsigned short int  ChannelId,		// channel identifier
+    GpakAlgCtrl_t       ControlCode,    // algorithm control code
+    GPAK_AlgControlStat_t *pStatus      // pointer to return status
+    );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakConfigurePorts return status. */
+typedef enum
+{
+    CpsSuccess = 0,         /* Serial Ports configured successfully */
+    CpsParmError = 1,       /* Configure Ports Parameter error */
+    CpsInvalidDsp = 2,      /* invalid DSP */
+    CpsDspCommFailure = 3   /* failed to communicate with DSP */
+} gpakConfigPortStatus_t;
+
+/*
+ * gpakConfigurePorts - Configure a DSP's serial ports.
+ *
+ * FUNCTION
+ *  This function configures a DSP's serial ports.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+extern gpakConfigPortStatus_t gpakConfigurePorts(
+    unsigned short int DspId,           // DSP identifier
+    GpakPortConfig_t   *pPortConfig,     // pointer to Port Config info
+    GPAK_PortConfigStat_t *pStatus      // pointer to Port Config Status
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakDownloadDsp return status. */
+typedef enum
+{
+    GdlSuccess = 0,         /* DSP download successful */
+    GdlFileReadError = 1,   /* error reading Download file */
+    GdlInvalidFile = 2,     /* invalid Download file content */
+    GdlInvalidDsp = 3       /* invalid DSP */
+} gpakDownloadStatus_t;
+
+/*
+ * gpakDownloadDsp - Download a DSP's Program and initialized Data memory.
+ *
+ * FUNCTION
+ *  This function reads a DSP's Program and Data memory image from the
+ *  specified file and writes the image to the DSP's memory.
+ *
+ * RETURNS
+ *  Status code indicating success or a specific error.
+ *
+ */
+extern gpakDownloadStatus_t gpakDownloadDsp(
+    unsigned short int  DspId,  // DSP identifier
+    GPAK_FILE_ID        FileId	// G.PAK download file identifier
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* gpakReadEventFIFOMessage return status */
+typedef enum
+{
+    RefEventAvail = 0,       /* an event was successfully read from the fifo */
+    RefNoEventAvail = 1,     /* no event was in the fifo */
+    RefInvalidDsp = 2,       /* invalid DSP identifier */
+    RefInvalidEvent = 3,     /* invalid event */
+    RefDspCommFailure = 4    /* error communicating with DSP */
+} gpakReadEventFIFOMessageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadEventFIFOMessage - read from the event fifo
+ * 
+ * FUNCTION
+ *  This function reads a single event from the event fifo if one is available
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ *
+ * Note: This function should be called in a loop until the return status 
+ *       indicates that the fifo is empty.
+ */
+extern gpakReadEventFIFOMessageStat_t gpakReadEventFIFOMessage(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      *pChannelId,    // pointer to channel identifier
+    GpakAsyncEventCode_t    *pEventCode,    // pointer to Event Code
+    GpakAsyncEventData_t    *pEventData     // pointer to Event Data Struct
+    );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakPingDsp return status values */
+typedef enum
+{
+    PngSuccess = 0,          /* DSP responded successfully */
+    PngInvalidDsp = 1,       /* invalid DSP identifier */
+    PngDspCommFailure = 2       /* error communicating with DSP */
+} gpakPingDspStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakPingDsp - ping the DSP to see if it's alive
+ * 
+ * FUNCTION
+ *  This function checks if the DSP is still communicating with the host
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakPingDspStat_t gpakPingDsp(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      *pDspSwVersion  // DSP software version
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakSerialTxFixedValue return status values */
+typedef enum
+{
+    TfvSuccess = 0,         /* operation successful */
+    TfvInvalidChannel = 1,  /* invalid channel identifier */
+    TfvInvalidDsp = 2,      /* invalid DSP identifier */
+    TfvDspCommFailure = 3   /* failed to communicate with DSP */
+} gpakSerialTxFixedValueStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakSerialTxFixedValue - transmit a fixed value on a timeslot
+ * 
+ * FUNCTION
+ *  This function controls transmission of a fixed value out onto a serial 
+ *  port's timeslot.
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakSerialTxFixedValueStat_t gpakSerialTxFixedValue(
+    unsigned short int      DspId,          // DSP identifier
+    unsigned short int      ChannelId,      // channel identifier
+    GpakSerialPort_t        PcmOutPort,     // PCM Output Serial Port Id
+    unsigned short int      PcmOutSlot,     // PCM Output Time Slot
+    unsigned short int      Value,          // 16-bit value 
+    GpakActivation          State 		    // activation state
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakControlTdmLoopBack return status values */
+typedef enum
+{
+    ClbSuccess = 0,         /* operation successful */
+    ClbSerPortInactive = 1, /* serial port is inactive */
+    ClbInvalidDsp = 2,      /* invalid DSP identifier */
+    ClbDspCommFailure = 3   /* failed to communicate with DSP */
+} gpakControlTdmLoopBackStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakControlTdmLoopBack - control a serial port's loopback state
+ * 
+ * FUNCTION
+ *  This function enables/disables the tdm input to output looback mode on a
+ *  serial port
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+gpakControlTdmLoopBackStat_t gpakControlTdmLoopBack(
+    unsigned short int      DspId,          // DSP identifier
+    GpakSerialPort_t        SerialPort,     // Serial Port Id
+    GpakActivation          LoopBackState   // Loopback State
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadCpuUsage return status values */
+typedef enum
+{
+    RcuSuccess = 0,         /* operation successful */
+    RcuInvalidDsp = 1,      /* invalid DSP identifier */
+    RcuDspCommFailure = 2   /* communication failure */
+} gpakReadCpuUsageStat_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadCpuUsage - read the cpu usage statistics
+ * 
+ * FUNCTION
+ *  This function reads cpu utilization from the DSP.
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakReadCpuUsageStat_t gpakReadCpuUsage(
+    unsigned short int  DspId,              // DSP identifier
+    unsigned short int  *pPeakUsage,        // pointer to peak usage variable
+    unsigned short int  *pPrev1SecPeakUsage // peak usage over previous 1 second
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetCpuUsageStats return status values */
+typedef enum
+{
+    RstcSuccess = 0,         /* operation successful */
+    RstcInvalidDsp = 1,      /* invalid DSP identifier */
+    RstcDspCommFailure = 2   /* communication failure */
+} gpakResetCpuUsageStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetCpuUsageStats - reset the cpu usage statistics
+ * 
+ * FUNCTION
+ *  This function resets the cpu utilization statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakResetCpuUsageStat_t gpakResetCpuUsageStats(
+    unsigned short int  DspId              // DSP identifier
+    );
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakReadFramingStats return status values */
+typedef enum
+{
+    RfsSuccess = 0,         /* operation successful */
+    RfsInvalidDsp = 1,      /* invalid DSP identifier */
+    RfsDspCommFailure = 2   /* communication failure */
+} gpakReadFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFramingStats
+ * 
+ * FUNCTION
+ *  This function reads a DSP's framing interrupt statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakReadFramingStatsStatus_t gpakReadFramingStats(
+    unsigned short int  DspId,                // DSP identifier
+    unsigned short int  *pFramingError1Count, // port 1 Framing error count
+    unsigned short int  *pFramingError2Count, // port 2 Framing error count
+    unsigned short int  *pFramingError3Count, // port 3 Framing error count
+    unsigned short int  *pDmaStopErrorCount,   // DMA-stoppage error count
+    unsigned short int  *pDmaSlipStatsBuffer   // DMA slips count
+    );
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* gpakResetFramingStats return values */
+typedef enum
+{
+    RstfSuccess = 0,         /* operation successful */
+    RstfInvalidDsp = 1,      /* invalid DSP identifier */
+    RstfDspCommFailure = 2   /* communication failure */
+} gpakResetFramingStatsStatus_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - reset a DSP's framing interrupt statistics
+ * 
+ * FUNCTION
+ *  This function resets a DSP's framing interrupt statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+extern gpakResetFramingStatsStatus_t gpakResetFramingStats(
+    unsigned short int      DspId          // DSP identifier
+    );
+
+
+typedef enum
+{
+	RmmSuccess =0,
+	RmmInvalidDsp = 1,
+	RmmSizeTooBig = 2,
+	RmmFailure = 3,
+	RmmInvalidAddress = 4
+	
+} gpakReadDSPMemoryStat_t;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakResetFramingStats - read a section of DSP memory
+ *                         to get access DSP registers, since 0x00--0x60 not HPI-accessable
+ * 
+ * FUNCTION
+ *  This function resets a DSP's framing interrupt statistics
+ * 
+ * RETURNS
+ *  Status  code indicating success or a specific error.
+ */
+
+extern gpakReadDSPMemoryStat_t gpakReadDSPMemoryMap(
+    unsigned short int  DspId,         // Dsp Identifier
+    unsigned short int  *pDest,        // Buffer on host to hold DSP memory map
+	DSP_ADDRESS BufrBaseAddress,       // DSP memory users want to read out
+    unsigned short int   MemoryLength_Word16 // Length of memory section read out, unit is 16-bit word
+    );
+
+typedef enum
+{
+	GPIOSuccess =0,
+	GPIOInvalidDsp = 1,
+	GPIODspCommFailure = 2
+}gpakAccessGPIOStat_t;
+
+extern gpakAccessGPIOStat_t gpakAccessGPIO(
+    unsigned short int      DspId,          // DSP identifier
+	GpakGPIOCotrol_t        gpakControlGPIO,// select oeration, changeDIR/write/read
+    unsigned short int      *pGPIOValue  // pointer for the read/write value or DIR mask
+    );
+
+/* gpakWriteSystemParms return status. */
+typedef enum
+{
+    WspSuccess = 0,         /* System Parameters written successfully */
+    WspParmError = 1,       /* Write System Parms's Parameter error */
+    WspInvalidDsp = 2,      /* invalid DSP */
+    WspDspCommFailure = 3   /* failed to communicate with DSP */
+} gpakWriteSysParmsStatus_t;
+
+/* Definition of a System Parameters information structure. */
+typedef struct
+{
+    /* DTMF Parameters */
+    short int MinSigLevel;      /* 0 = Disabled, Min Sig Power Level for detection */
+    short int SNRFlag;          /* 0 = Disabled, relax SNR tolerances */
+    short int FreqDeviation;    /* 0 = Disabled, X Percent Deviation times 10 (e.g. 1.7% is entered as 17) */
+    short int DtmfFwdTwist;     /* 0 to 8 db */
+    short int DtmfRevTwist;     /* 0 to 8 db */
+
+	short int DtmfValidityMask; /* This flag allows users to relax the trailing conditions of the tone */
+
+} GpakSystemParms_t;
+/* gpakReadSystemParms return status. */
+typedef enum
+{
+    RspSuccess = 0,         /* System Parameters read successfully */
+    RspInvalidDsp = 1,      /* invalid DSP */
+    RspDspCommFailure = 2   /* failed to communicate with DSP */
+} gpakReadSysParmsStatus_t;
+
+extern gpakReadSysParmsStatus_t gpakReadSystemParms(
+    unsigned short int      DspId,  // DSP identifier
+    GpakSystemParms_t *pSysParms    /* pointer to System Parms info var */
+    );
+
+extern gpakWriteSysParmsStatus_t gpakWriteSystemParms(
+    unsigned short int      DspId,  // DSP identifier
+    GpakSystemParms_t *pSysParms,   /* pointer to System Parms info var */
+    unsigned short int UpdateBits, /* input: flags indicating which parms to update */
+    GPAK_SysParmsStat_t *pStatus    /* pointer to Write System Parms Status */
+    );
+
+#endif // end multiple inclusion
+
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/gpakenum.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/gpakenum.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/gpakenum.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/gpakenum.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2005, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: gpakenum.h
+ *
+ * Description:
+ *   This file contains common enumerations related to G.PAK application
+ *   software.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ *   06/15/05 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc.  The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _GPAKENUM_H  /* prevent multiple inclusion */
+#define _GPAKENUM_H
+
+/* G.PAK Serial Port Word Size */
+typedef enum
+{
+    SerWordSize8 = 0,       // 8-bit seial word
+    SerWordSize16 = 1       // 16-bit serial word
+} GpakSerWordSize_t;
+
+/* G.PAK Serial Port FrameSync Polarity */
+typedef enum
+{
+    FrameSyncActLow = 0,    // active low frame sync signal
+    FrameSyncActHigh = 1    // active high frame sync signal
+} GpakSerFrameSyncPol_t;
+
+/* G.PAK Serial Port Clock Polarity */
+typedef enum
+{
+    SerClockActLow = 0,     // active low serial clock
+    SerClockActHigh = 1     // active high serial clock
+} GpakSerClockPol_t;
+
+/* G.PAK Serial Port Data Delay */
+typedef enum
+{
+    DataDelay0 = 0,         // no data delay
+    DataDelay1 = 1,         // 1-bit data delay
+    DataDelay2 = 2          // 2-bit data delay
+} GpakSerDataDelay_t;
+
+/* G.PAK Serial Port Ids. */
+typedef enum
+{
+    SerialPortNull = 0,     // null serial port 
+    SerialPort1 = 1,        // first PCM serial stream port (McBSP0) 
+    SerialPort2 = 2,        // second PCM serial stream port (McBSP1) 
+    SerialPort3 = 3         // third PCM serial stream port (McBSP2) 
+} GpakSerialPort_t;
+
+/* G.PAK serial port Slot Configuration selection codes. */
+typedef enum
+{
+    SlotCfgNone = 0,        // no time slots used 
+    SlotCfg2Groups = 2,     // 2 groups of 16 time slots used, 32 Channels system
+    SlotCfg8Groups = 8      // 8-partition mode for 128-channel system
+} GpakSlotCfg_t;
+
+/* G.PAK serial port Companding Mode codes. */
+typedef enum 
+{ 
+    cmpPCMU=0,              // u-Law 
+    cmpPCMA=1,              // A-Law 
+    cmpNone=2               // none 
+} GpakCompandModes;
+
+/* G.PAK Active/Inactive selection codes. */
+typedef enum
+{
+    Disabled=0,             // Inactive 
+    Enabled=1               // Active 
+} GpakActivation;
+
+/* G.PAK Channel Type codes. */
+typedef enum
+{
+    inactive=0,          // channel inactive 
+    tdmToTdm=1           // tdmToTdm
+} GpakChanType;
+
+/* G.PAK Algorithm control commands */
+typedef enum
+{
+    EnableEcanA          = 0,    // Enable A side echo canceller
+    BypassEcanA          = 1,    // Bypass A side echo canceller
+    ResetEcanA           = 2,    // Reset A side echo canceller
+    EnableEcanB          = 3,    // Enable B side echo canceller
+    BypassEcanB          = 4,    // Bypass B side echo canceller
+    ResetEcanB           = 5,    // Reset B side echo canceller
+
+    EnableMuLawSwCompanding  = 6,// Enable Mu-law Software companding
+    EnableALawSwCompanding  = 7, // Enable Mu-law Software companding
+    BypassSwCompanding  = 8,     // Bypass Software companding
+	EnableDTMFMuteA       = 9,   // Mute A side Dtmf digit after tone detected
+	DisableDTMFMuteA      = 10,  // Do not mute A side Dtmf digit once tone detected
+	EnableDTMFMuteB       = 11,  // Mute B side Dtmf digit after tone detected
+	DisableDTMFMuteB      = 12,  // Do not mute B side Dtmf digit once tone detected
+	EnableFaxCngDetectA   = 13,  // Enable A side Fax CNG detector, channel must be configed already
+	DisableFaxCngDetectA  = 14,  // Disable A side Fax CNG detector, channel must be configed already
+	EnableFaxCngDetectB   = 15,  // Enable B side Fax CNG detector, channel must be configed already
+	DisableFaxCngDetectB  = 16  // Disable B side Fax CNG detector, channel must be configed already
+} GpakAlgCtrl_t;
+
+/* G.PAK Tone types. */
+typedef enum
+{
+    Null_tone = 0,        // no tone detection 
+    DTMF_tone = 1         // DTMF tone 
+} GpakToneTypes;
+
+/* G.PAK direction. */
+typedef enum
+{
+    TDMAToB = 0,        // A to B 
+    TDMBToA = 1         // B to A
+} GpakTdmDirection;
+
+
+typedef enum
+{
+    rate1ms=0,
+    rate2ms=1,
+    rate10ms=2
+} GpakRate_t;
+
+/* G.PAK Asynchronous Event Codes */
+typedef enum
+{
+    EventToneDetect = 0,            // Tone detection event
+    EventDSPDebug = 7               // DSP debug data event
+} GpakAsyncEventCode_t;
+
+/* G.PAK MF Tone Code Indices */
+typedef enum
+{
+    DtmfDigit1   = 0,     // DTMF Digit 1 
+    DtmfDigit2   = 1,     // DTMF Digit 2 
+    DtmfDigit3   = 2,     // DTMF Digit 3 
+    DtmfDigitA   = 3,     // DTMF Digit A 
+    DtmfDigit4   = 4,     // DTMF Digit 4 
+    DtmfDigit5   = 5,     // DTMF Digit 5 
+    DtmfDigit6   = 6,     // DTMF Digit 6 
+    DtmfDigitB   = 7,     // DTMF Digit B 
+    DtmfDigit7   = 8,     // DTMF Digit 7 
+    DtmfDigit8   = 9,     // DTMF Digit 8 
+    DtmfDigit9   = 10,    // DTMF Digit 9 
+    DtmfDigitC   = 11,    // DTMF Digit C 
+    DtmfDigitSt  = 12,    // DTMF Digit * 
+    DtmfDigit0   = 13,    // DTMF Digit 0 
+    DtmfDigitPnd = 14,    // DTMF Digit # 
+    DtmfDigitD   = 15,    // DTMF Digit D 
+
+	FaxCngDigit  = 90,    // Fax Calling Tone (1100 Hz)
+
+    EndofMFDigit = 100,     // End of MF digit 
+    EndofCngDigit = 101     // End of Cng Digit
+} GpakToneCodes_t;
+
+/* GPIO control code*/
+typedef enum
+{
+	GPIO_READ = 0,
+	GPIO_WRITE = 1,
+	GPIO_DIR = 2
+} GpakGPIOCotrol_t;
+
+#endif // end multiple inclusion
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/GpakErrs.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/GpakErrs.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/GpakErrs.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/GpakErrs.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2002 - 2004, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakErrs.h
+ *
+ * Description:
+ *   This file contains DSP reply status codes used by G.PAK API functions to
+ *   indicate specific errors.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ *   10/17/01 - Initial release.
+ *   07/03/02 - Updates for conferencing.
+ *   06/15/04 - Tone type updates.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc.  The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _GPAKERRS_H  /* prevent multiple inclusion */
+#define _GPAKERRS_H
+
+/* Configure Serial Ports reply status codes. */
+typedef enum
+{
+    Pc_Success = 0,             /* serial ports configured successfully */
+    Pc_ChannelsActive = 1,      /* unable to configure while channels active  */
+    Pc_TooManySlots1 = 2,       /* too many slots selected for port 1 */
+    Pc_InvalidBlockCombo1 = 3,  /* invalid combination of blocks for port 1 */
+    Pc_NoSlots1 = 4,            /* no slots selected for port 1 */
+    Pc_InvalidSlots1 = 5,       /* invalid slot (> max) selected for port 1 */
+    Pc_TooManySlots2 = 6,       /* too many slots selected for port 2 */
+    Pc_InvalidBlockCombo2 = 7,  /* invalid combination of blocks for port 2 */
+    Pc_NoSlots2 = 8,            /* no slots selected for port 2 */
+    Pc_InvalidSlots2 = 9,       /* invalid slot (> max) selected for port 2 */
+    Pc_TooManySlots3 = 10,      /* too many slots selected for port 3 */
+    Pc_InvalidBlockCombo3 = 11, /* invalid combination of blocks for port 3 */
+    Pc_NoSlots3 = 12,           /* no slots selected for port 3 */
+    Pc_InvalidSlots3 = 13       /* invalid slot (> max) selected for port 3 */
+} GPAK_PortConfigStat_t;
+
+/* Configure Channel reply status codes. */
+typedef enum
+{
+    Cc_Success = 0,                 /* channel configured successfully */
+    Cc_InvalidChannelType = 1,      /* invalid Channel Type */
+    Cc_InvalidChannel  = 2,         /* invalid Channel A Id */
+    Cc_ChannelActiveA = 3,          /* Channel A is currently active */
+    Cc_InvalidInputPortA = 4,       /* invalid Input A Port */
+    Cc_InvalidInputSlotA = 5,       /* invalid Input A Slot */
+    Cc_BusyInputSlotA = 6,          /* busy Input A Slot */
+    Cc_InvalidOutputPortA = 7,      /* invalid Output A Port */
+    Cc_InvalidOutputSlotA = 8,      /* invalid Output A Slot */
+    Cc_BusyOutputSlotA = 9,         /* busy Output A Slot */
+    Cc_InvalidInputPortB = 10,      /* invalid Input B Port */
+    Cc_InvalidInputSlotB = 11,      /* invalid Input B Slot */
+    Cc_BusyInputSlotB = 12,         /* busy Input B Slot */
+    Cc_InvalidPktInCodingA = 13,    /* invalid Packet In A Coding */
+    Cc_InvalidPktOutCodingA = 14,   /* invalid Packet Out A Coding */
+    Cc_InvalidPktInSizeA = 15,      /* invalid Packet In A Frame Size */
+    Cc_InvalidPktOutSizeA = 16,     /* invalid Packet Out A Frame Size */
+
+    Cc_ChanTypeNotConfigured = 21,  /* channel type was not configured */
+    Cc_InsuffECResources = 22,      /* insufficient ecan resources avail. */
+    Cc_InsuffTDMResources = 23,     /* insufficient tdm block resources avail. */
+
+    Cc_InsuffPktBufResources = 25,  /* insufficient pkt buffer resources avail. */
+    Cc_InsuffPcmBufResources = 26,  /* insufficient pcm buffer resources avail. */
+
+    Cc_BadPcmEcNlpType = 30,        /* invalid EC Nlp type */
+    Cc_BadPcmEcTapLength = 31,      /* invalid EC tap length */
+    Cc_BadPcmEcDblTalkThresh = 32,  /* invalid EC double-talk threshold */
+    Cc_BadPcmEcNlpThreshold = 33,   /* invalid EC Nlp threshold */
+    Cc_BadPcmEcCngThreshold = 34,   /* invalid EC Cng threshold */
+    Cc_BadPcmEcAdaptLimit = 35,     /* invalid EC Adapt Limit */
+    Cc_BadPcmEcCrossCorrLim = 36,   /* invalid EC Cross Correlation Limit */
+    Cc_BadPcmEcNumFirSegs = 37,     /* invalid EC Number of FirSegments */
+    Cc_BadPcmEcFirSegLen = 38,      /* invalid EC Fir Segment Length */
+
+    /*Cc_InvalidNumEcsEnabled = 48, */   /* more than 1 Ec enabled on channel */
+    Cc_InvalidFrameRate = 49,        /* invalid gpak frame rate */
+    Cc_InvalidSoftCompand = 50,      /* invalid softCompanding type */
+
+	Cc_InvalidMuteToneA = 51,        /* invalid MuteToneA set, no detector */
+	Cc_InvalidMuteToneB = 52,         /* invalid MuteToneB set, no detector */
+    Cc_InsuffFaxCngDetResources = 53     /* insufficient tdm block resources avail. */
+
+} GPAK_ChannelConfigStat_t;
+
+/* Tear Down Channel reply status codes. */
+typedef enum
+{
+    Td_Success = 0,                 /* channel torn down successfully */
+    Td_InvalidChannel = 1,          /* invalid Channel Id */
+    Td_ChannelNotActive = 2         /* channel is not active */
+} GPAK_TearDownChanStat_t;
+
+
+typedef enum
+{
+    Ac_Success = 0,           /* algorithm control is successfull */
+    Ac_InvalidChannel = 1,    /* invalid channel identifier */
+    Ac_InvalidCode = 2,       /* invalid algorithm control code */
+    Ac_ECNotEnabled = 3,      /* echo canceller was not allocated */ 
+    Ac_InvalidSoftComp = 4,   /* invalid softcompanding, 'cause serial port not in companding mode */
+	Ac_InvalidDTMFMuteA = 5,  /* A side invalid Mute, since no dtmf detector */
+	Ac_InvalidDTMFMuteB = 6,  /* B side invalid Mute, since no dtmf detector */
+	Ac_InvalidFaxCngA = 7,    /* A side FAXCNG detector not available */
+	Ac_InvalidFaxCngB = 8,     /* B side FAXCNG detector not available */
+	Ac_InvalidSysConfig = 9    /* No new system parameters (DTMF config) wrriten yet */
+} GPAK_AlgControlStat_t;
+
+/* Write System Parameters reply status codes. */
+typedef enum
+{
+    Sp_Success = 0,             /* System Parameters written successfully */
+    Sp_BadTwistThresh = 29        /* invalid twist threshold */
+
+} GPAK_SysParmsStat_t;
+
+#endif  /* prevent multiple inclusion */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/GpakHpi.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/GpakHpi.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/GpakHpi.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/GpakHpi.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2001, Adaptive Digital Technologies, Inc.
+ *
+ * File Name: GpakHpi.h
+ *
+ * Description:
+ *   This file contains common definitions related to the G.PAK interface
+ *   between a host processor and a DSP processor via the Host Port Interface.
+ *
+ * Version: 1.0
+ *
+ * Revision History:
+ *   10/17/01 - Initial release.
+ *
+ * This program has been released under the terms of the GPL version 2 by
+ * permission of Adaptive Digital Technologies, Inc.  The standard
+ * GPL disclaimer is given inline below for your convenience.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _GPAKHPI_H  /* prevent multiple inclusion */
+#define _GPAKHPI_H
+
+
+/* Definition of G.PAK Command/Reply message type codes. */
+#define MSG_NULL_REPLY 0            /* Null Reply (unsupported Command) */
+#define MSG_SYS_CONFIG_RQST 1       /* System Configuration Request */
+#define MSG_SYS_CONFIG_REPLY 2      /* System Configuration Reply */
+#define MSG_READ_SYS_PARMS 3        /* Read System Parameters */
+#define MSG_READ_SYS_PARMS_REPLY 4  /* Read System Parameters Reply */
+#define MSG_WRITE_SYS_PARMS 5       /* Write System Parameters */
+#define MSG_WRITE_SYS_PARMS_REPLY 6 /* Write System Parameters Reply */
+#define MSG_CONFIGURE_PORTS 7       /* Configure Serial Ports */
+#define MSG_CONFIG_PORTS_REPLY 8    /* Configure Serial Ports Reply */
+#define MSG_CONFIGURE_CHANNEL 9     /* Configure Channel */
+#define MSG_CONFIG_CHAN_REPLY 10    /* Configure Channel Reply */
+#define MSG_TEAR_DOWN_CHANNEL 11    /* Tear Down Channel */
+#define MSG_TEAR_DOWN_REPLY 12      /* Tear Down Channel Reply */
+#define MSG_CHAN_STATUS_RQST 13     /* Channel Status Request */
+#define MSG_CHAN_STATUS_REPLY 14    /* Channel Status Reply */
+
+#define MSG_TEST_MODE 17            /* Configure/Perform Test Mode */
+#define MSG_TEST_REPLY 18           /* Configure/Perform Test Mode Reply */
+
+#define MSG_ALG_CONTROL 27             /* algorithm control */
+#define MSG_ALG_CONTROL_REPLY 28       /* algorithm control reply */
+#define MSG_GET_TXCID_ADDRESS 29       /* get tx cid buffer start address */
+#define MSG_GET_TXCID_ADDRESS_REPLY 30 /* get tx cid buffer start addr reply */
+
+#define MSG_PING 35                    /* ping command */
+#define MSG_PING_REPLY 36              /* ping command reply */
+#define MSG_SERIAL_TXVAL 37            /* transmit serial fixed value */
+#define MSG_SERIAL_TXVAL_REPLY 38      /* transmit serial fixed value reply */
+#define MSG_TDM_LOOPBACK 39            /* tdm loopback control */
+#define MSG_TDM_LOOPBACK_REPLY 40      /* tdm loopback control reply */
+#define MSG_RESET_USAGE_STATS 41       /* reset cpu usage stats */
+#define MSG_RESET_USAGE_STATS_REPLY 42 /* reset cpu usage stats reply */
+
+#define MSG_RESET_FRAME_STATS 47       /* reset framing stats */
+#define MSG_RESET_FRAME_STATS_REPLY 48 /* reset framing stats reply */
+
+#define MSG_READ_DSP_MEMORY         49 /* read small section of DSP's memory */
+#define MSG_READ_DSP_MEMORY_REPLY   50 /* read memory reply */
+
+#define MSG_ACCESSGPIO				51
+#define MSG_ACCESSGPIO_REPLY		52
+#endif  /* prevent multiple inclusion */
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/Kbuild.svn-base zaptel-1.4/wcte12xp/.svn/text-base/Kbuild.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/Kbuild.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/Kbuild.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,23 @@
+obj-m += wcte12xp.o
+
+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
+
+ifeq ($(HOTPLUG_FIRMWARE),yes)
+  EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
+endif
+
+wcte12xp-objs := base.o vpmadt032.o GpakApi.o
+
+ifneq ($(HOTPLUG_FIRMWARE),yes)
+wcte12xp-objs += ../firmware/zaptel-fw-vpmadt032.o
+endif
+
+$(obj)/../firmware/zaptel-fw-vpmadt032.o: $(obj)/base.o
+	$(MAKE) -C $(obj)/../firmware zaptel-fw-vpmadt032.o
+
+$(obj)/base.o: $(src)/vpmadt032.h $(src)/wcte12xp.h
+$(obj)/base.o: $(src)/../zaptel.h
+
+$(obj)/vpmadt032.o: $(src)/vpmadt032.h
+
+$(obj)/GpakApi.o: $(src)/GpakApi.h
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/Makefile.svn-base zaptel-1.4/wcte12xp/.svn/text-base/Makefile.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/Makefile.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/Makefile.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,25 @@
+ifneq ($(KBUILD_EXTMOD),)
+# We only get here on kernels 2.6.0-2.6.9 .
+# For newer kernels, Kbuild will be included directly by the kernel
+# build system.
+include $(src)/Kbuild
+
+else
+
+# building for 2.4 kernels means no VPM support, so none of the VPM support
+# modules are included in the Makefile rules
+
+all: wcte12xp.o
+
+%.o: %.c
+	$(CC) $(KFLAGS) -o $@ -c $<
+
+base.o: ../zaptel.h
+
+wcte12xp.o: base.o
+	$(LD) -r -o $@ $^
+
+clean:
+	rm -f *.o
+
+endif
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/vpmadt032.c.svn-base zaptel-1.4/wcte12xp/.svn/text-base/vpmadt032.c.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/vpmadt032.c.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/vpmadt032.c.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,1385 @@
+/*
+ * Digium, Inc.  Wildcard TE12xP T1/E1 card Driver
+ *
+ * Written by Michael Spiceland <mspiceland@digium.com>
+ *
+ * Adapted from the wctdm24xxp and wcte11xp drivers originally
+ * written by Mark Spencer <markster@digium.com>
+ *            Matthew Fredrickson <creslin@digium.com>
+ *            William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 <linux/delay.h>
+#include <asm/semaphore.h>
+#include <linux/pci.h> 
+#include <linux/firmware.h> 
+#include <linux/list.h> 
+
+#include "zaptel.h"
+
+#include "wcte12xp.h"
+#include "vpmadt032.h"
+#include "GpakApi.h"
+
+extern struct t1 *ifaces[WC_MAX_IFACES];
+
+extern int vpmnlptype;
+extern int vpmnlpthresh;
+extern int vpmnlpmaxsupp;
+
+#ifdef VPM_SUPPORT
+
+inline void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int whichframe)
+{
+	struct vpm150m_cmd *curcmd = NULL;
+	struct vpm150m *vpm150m = wc->vpm150m;
+	int x;
+	unsigned char leds = ~((wc->intcount / 1000) % 8) & 0x7;
+
+	/* Skip audio */
+	writechunk += 66;
+
+	if (test_bit(VPM150M_SPIRESET, &vpm150m->control) || test_bit(VPM150M_HPIRESET, &vpm150m->control)) {
+		debug_printk(1, "HW Resetting VPMADT032 ...\n");
+		for (x = 0; x < 4; x++) {
+			if (!x) {
+				if (test_and_clear_bit(VPM150M_SPIRESET, &vpm150m->control))
+					writechunk[CMD_BYTE(x, 0, 1)] = 0x08;
+				else if (test_and_clear_bit(VPM150M_HPIRESET, &vpm150m->control))
+					writechunk[CMD_BYTE(x, 0, 1)] = 0x0b;
+			} else
+				writechunk[CMD_BYTE(x, 0, 1)] = 0x00 | leds;
+			writechunk[CMD_BYTE(x, 1, 1)] = 0;
+			writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+		}
+		return;
+	}
+
+	/* Search for something waiting to transmit */
+	for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+		if ((vpm150m->cmdq[x].flags & (__VPM150M_RD | __VPM150M_WR)) && 
+		   !(vpm150m->cmdq[x].flags & (__VPM150M_FIN | __VPM150M_TX))) {
+		   	curcmd = &vpm150m->cmdq[x];
+			curcmd->ident = wc->txident;
+			curcmd->flags |= __VPM150M_TX;
+			break;
+		}
+	}
+	if (curcmd) {
+#if 0
+		printk("Found command txident = %d, desc = 0x%x, addr = 0x%x, data = 0x%x\n", curcmd->txident, curcmd->desc, curcmd->addr, curcmd->data);
+#endif
+		if (curcmd->flags & __VPM150M_RWPAGE) {
+			/* Set CTRL access to page*/
+			writechunk[CMD_BYTE(0, 0, 1)] = (0x8 << 4);
+			writechunk[CMD_BYTE(0, 1, 1)] = 0;
+			writechunk[CMD_BYTE(0, 2, 1)] = 0x20;
+
+			/* Do a page write */
+			if (curcmd->flags & __VPM150M_WR)
+				writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4) << 4);
+			else
+				writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4);
+			writechunk[CMD_BYTE(1, 1, 1)] = 0;
+			if (curcmd->flags & __VPM150M_WR)
+				writechunk[CMD_BYTE(1, 2, 1)] = curcmd->data[0] & 0xf;
+			else
+				writechunk[CMD_BYTE(1, 2, 1)] = 0;
+
+			if (curcmd->flags & __VPM150M_WR) {
+				/* Fill in buffer to size */
+				writechunk[CMD_BYTE(2, 0, 1)] = 0;
+				writechunk[CMD_BYTE(2, 1, 1)] = 0;
+				writechunk[CMD_BYTE(2, 2, 1)] = 0;
+			} else {
+				/* Do reads twice b/c of vpmadt032 bug */
+				writechunk[CMD_BYTE(2, 0, 1)] = ((0x8 | 0x4 | 0x1) << 4);
+				writechunk[CMD_BYTE(2, 1, 1)] = 0;
+				writechunk[CMD_BYTE(2, 2, 1)] = 0;
+			}
+
+			/* Clear XADD */
+			writechunk[CMD_BYTE(3, 0, 1)] = (0x8 << 4);
+			writechunk[CMD_BYTE(3, 1, 1)] = 0;
+			writechunk[CMD_BYTE(3, 2, 1)] = 0;
+
+			/* Fill in buffer to size */
+			writechunk[CMD_BYTE(4, 0, 1)] = 0;
+			writechunk[CMD_BYTE(4, 1, 1)] = 0;
+			writechunk[CMD_BYTE(4, 2, 1)] = 0;
+
+		} else {
+			/* Set address */
+			writechunk[CMD_BYTE(0, 0, 1)] = ((0x8 | 0x4) << 4);
+			writechunk[CMD_BYTE(0, 1, 1)] = (curcmd->address >> 8) & 0xff;
+			writechunk[CMD_BYTE(0, 2, 1)] = curcmd->address & 0xff;
+
+			/* Send/Get our data */
+			if (curcmd->flags & __VPM150M_WR) {
+				if (curcmd->datalen > 1)
+					writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+				else
+					writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1)) << 4);
+			} else
+				if (curcmd->datalen > 1)
+					writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+				else
+					writechunk[CMD_BYTE(1, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4);
+			writechunk[CMD_BYTE(1, 1, 1)] = (curcmd->data[0] >> 8) & 0xff;
+			writechunk[CMD_BYTE(1, 2, 1)] = curcmd->data[0] & 0xff;
+
+			if (curcmd->flags & __VPM150M_WR) {
+				/* Fill in */
+				writechunk[CMD_BYTE(2, 0, 1)] = 0;
+				writechunk[CMD_BYTE(2, 1, 1)] = 0;
+				writechunk[CMD_BYTE(2, 2, 1)] = 0;
+			} else {
+				/* Do this again for reads b/c of the bug in vpmadt032 */
+				writechunk[CMD_BYTE(2, 0, 1)] = ((0x8 | (0x3 << 1) | 0x1) << 4);
+				writechunk[CMD_BYTE(2, 1, 1)] = (curcmd->data[0] >> 8) & 0xff;
+				writechunk[CMD_BYTE(2, 2, 1)] = curcmd->data[0] & 0xff;
+			}
+			
+			if (curcmd->datalen > 1) {
+				if (curcmd->flags & __VPM150M_WR)
+					writechunk[CMD_BYTE(3, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+				else
+					writechunk[CMD_BYTE(3, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+				writechunk[CMD_BYTE(3, 1, 1)] = (curcmd->data[1] >> 8) & 0xff;
+				writechunk[CMD_BYTE(3, 2, 1)] = curcmd->data[1] & 0xff;
+			} else {
+				/* Fill in the rest */
+				writechunk[CMD_BYTE(3, 0, 1)] = 0;
+				writechunk[CMD_BYTE(3, 1, 1)] = 0;
+				writechunk[CMD_BYTE(3, 2, 1)] = 0;
+			}
+
+			if (curcmd->datalen > 2) {
+				if (curcmd->flags & __VPM150M_WR)
+					writechunk[CMD_BYTE(4, 0, 1)] = ((0x8 | (0x1 << 1)) << 4);
+				else
+					writechunk[CMD_BYTE(4, 0, 1)] = ((0x8 | (0x1 << 1) | 0x1) << 4);
+				writechunk[CMD_BYTE(4, 1, 1)] = (curcmd->data[2] >> 8) & 0xff;
+				writechunk[CMD_BYTE(4, 2, 1)] = curcmd->data[2] & 0xff;
+			} else {
+				/* Fill in the rest */
+				writechunk[CMD_BYTE(4, 0, 1)] = 0;
+				writechunk[CMD_BYTE(4, 1, 1)] = 0;
+				writechunk[CMD_BYTE(4, 2, 1)] = 0;
+			}
+		}
+	} else if (test_and_clear_bit(VPM150M_SWRESET, &vpm150m->control)) {
+		debug_printk(1, "Booting  VPMADT032\n");
+		for (x = 0; x < 7; x++) {
+			if (x == 0)
+				writechunk[CMD_BYTE(x, 0, 1)] = (0x8 << 4);
+			else
+				writechunk[CMD_BYTE(x, 0, 1)] = 0x00;
+			writechunk[CMD_BYTE(x, 1, 1)] = 0;
+			if (x == 0)
+				writechunk[CMD_BYTE(x, 2, 1)] = 0x01;
+			else
+				writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+		}
+	} else {
+		for (x = 0; x < 7; x++) {
+			writechunk[CMD_BYTE(x, 0, 1)] = 0x00;
+			writechunk[CMD_BYTE(x, 1, 1)] = 0x00;
+			writechunk[CMD_BYTE(x, 2, 1)] = 0x00;
+		}
+	}
+
+	/* Add our leds in */
+	for (x = 0; x < 7; x++)
+		writechunk[CMD_BYTE(x, 0, 1)] |= leds;
+
+#if 0
+	int y;
+	for (x = 0; x < 7; x++) {
+		for (y = 0; y < 3; y++) {
+			if (writechunk[CMD_BYTE(x, y, 1)] & 0x2) {
+				module_printk("the test bit is high for byte %d\n", y);
+			}
+		}
+	}
+#endif
+
+	/* Now let's figure out if we need to check for DTMF */
+	/* polling */
+	if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 100))
+		queue_work(vpm150m->wq, &vpm150m->work_dtmf);
+
+#if 0
+	/* This may be needed sometime in the future to troubleshoot ADT related issues. */
+	if (test_bit(VPM150M_ACTIVE, &vpm150m->control) && !whichframe && !(wc->intcount % 10000))
+		queue_work(vpm150m->wq, &vpm150m->work_debug);
+#endif 
+}
+
+inline void vpm150m_cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk)
+{
+	unsigned char ident;
+	int x, i;
+
+	/* Skip audio */
+	readchunk += 66;
+	/* Search for any pending results */
+	for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+		if ((wc->vpm150m->cmdq[x].flags & (__VPM150M_RD | __VPM150M_WR)) && 
+		    (wc->vpm150m->cmdq[x].flags & (__VPM150M_TX)) && 
+		   !(wc->vpm150m->cmdq[x].flags & (__VPM150M_FIN))) {
+		   	ident = wc->vpm150m->cmdq[x].ident;
+		   	if (ident == wc->rxident) {
+				/* Store result */
+				for (i = 0; i < wc->vpm150m->cmdq[x].datalen; i++) {
+					wc->vpm150m->cmdq[x].data[i] = (0xff & readchunk[CMD_BYTE((2 + i), 1, 1)]) << 8;
+					wc->vpm150m->cmdq[x].data[i] |= readchunk[CMD_BYTE((2 + i), 2, 1)];
+				}
+				if (wc->vpm150m->cmdq[x].flags & __VPM150M_WR) {
+					/* Go ahead and clear out writes since they need no acknowledgement */
+					wc->vpm150m->cmdq[x].flags = 0;
+				} else
+					wc->vpm150m->cmdq[x].flags |= __VPM150M_FIN;
+				break;
+			}
+		}
+	}
+}
+
+static inline struct t1 * wc_find_iface(unsigned short dspid)
+{
+	int i;
+	struct t1 *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ifacelock, flags);
+	for (i = 0; i < WC_MAX_IFACES; i++)
+		if (ifaces[i] && ifaces[i]->vpm150m && (ifaces[i]->vpm150m->dspid == dspid))
+			ret = ifaces[i];
+	spin_unlock_irqrestore(&ifacelock, flags);
+
+	return ret;
+}
+
+static struct vpm150m_cmd * vpm150m_empty_slot(struct t1 *wc)
+{
+	unsigned int x;
+
+	for (x = 0; x < VPM150M_MAX_COMMANDS; x++) {
+		if (!wc->vpm150m->cmdq[x].flags) {
+			return &wc->vpm150m->cmdq[x];
+		}
+	}
+	return NULL;
+}
+
+/* Wait for any outstanding commands to be completed. */
+static inline int vpm150m_io_wait(struct t1 *wc)
+{
+	int x;
+	int ret=0;
+	for (x=0; x < VPM150M_MAX_COMMANDS;) {
+		if (wc->vpm150m->cmdq[x].flags) {
+			if ((ret=schluffen(&wc->regq))) {
+				return ret;
+			}
+			x=0;
+		}
+		else {
+			++x;
+		}
+	}
+	return ret;
+}
+
+int t1_vpm150m_getreg_full_async(struct t1 *wc, int pagechange, unsigned int len, 
+	unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+	int ret=0;
+	unsigned long flags;
+	BUG_ON(!hit_p);
+	spin_lock_irqsave(&wc->reglock, flags);
+	(*hit_p) = vpm150m_empty_slot(wc);
+	if (*hit_p) {
+		(*hit_p)->flags = __VPM150M_RD;
+		if (pagechange) {
+			(*hit_p)->flags |= __VPM150M_RWPAGE;
+		}
+		(*hit_p)->datalen = len;
+		(*hit_p)->address = addr;
+		memset((*hit_p)->data, 0, len*sizeof(outbuf[0]));
+	}
+	else {
+		ret = -EBUSY;
+	}
+	spin_unlock_irqrestore(&wc->reglock, flags);
+	return ret;
+}
+
+int t1_vpm150m_getreg_full_return(struct t1 *wc, int pagechange, unsigned int len,
+	unsigned short addr, unsigned short *outbuf, struct vpm150m_cmd **hit_p)
+{
+	int ret = 0;
+	unsigned long flags;
+	BUG_ON(!hit_p);
+	spin_lock_irqsave(&wc->reglock, flags);
+	do {
+		if ((*hit_p)->flags & __VPM150M_FIN) {
+			memcpy(outbuf, (*hit_p)->data, len*(sizeof(outbuf[0])));
+			(*hit_p)->flags = 0;
+			(*hit_p) = NULL;
+			ret = 0;
+		}
+		else {
+			spin_unlock_irqrestore(&wc->reglock, flags);
+			if ((ret=schluffen(&wc->regq))) {
+				return ret;
+			}
+			spin_lock_irqsave(&wc->reglock, flags);
+			ret = -EBUSY;
+		}
+	} while (-EBUSY == ret);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+	return ret;
+}
+
+int t1_vpm150m_getreg_full(struct t1 *wc, int pagechange, unsigned int len, unsigned short addr, unsigned short *outbuf)
+{
+	struct vpm150m_cmd *hit = 0;
+	int ret = 0;
+	do {
+		ret = t1_vpm150m_getreg_full_async(wc, pagechange, len, addr, outbuf, &hit);
+		if (!hit) {
+			if ( -EBUSY == ret ) {
+				if ((ret = schluffen(&wc->regq))) 
+					return ret;
+			}
+			BUG_ON( 0 != ret);
+		}
+	} while (!hit);
+
+	ret = t1_vpm150m_getreg_full_return(wc, pagechange, len, addr, outbuf, &hit);
+	return ret;
+}
+
+int t1_vpm150m_setreg_full(struct t1 *wc, int pagechange, unsigned int len, unsigned int addr, unsigned short *data)
+{
+	unsigned long flags;
+	struct vpm150m_cmd *hit;
+	int ret, i;
+	do {
+		spin_lock_irqsave(&wc->reglock, flags);
+		hit = vpm150m_empty_slot(wc);
+		if (hit) {
+			hit->flags = __VPM150M_WR;
+			if (pagechange)
+				hit->flags |= __VPM150M_RWPAGE;
+			hit->address = addr;
+			hit->datalen = len;
+			for (i = 0; i < len; i++)
+				hit->data[i] = data[i];
+		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		if (!hit) {
+			if ((ret = schluffen(&wc->regq)))
+				return ret;
+		}
+	} while (!hit);
+	return (hit) ? 0 : -1;
+}
+
+int t1_vpm150m_setpage(struct t1 *wc, unsigned short addr)
+{
+	addr &= 0xf;
+	/* Let's optimize this a little bit */
+	if (wc->vpm150m->curpage == addr)
+		return 0;
+	else {
+		wc->vpm150m->curpage = addr;
+	}
+
+	return t1_vpm150m_setreg_full(wc, 1, 1, 0, &addr);
+}
+
+unsigned char t1_vpm150m_getpage(struct t1 *wc)
+{
+	unsigned short res;
+	t1_vpm150m_getreg_full(wc, 1, 1, 0, &res);
+	return res;
+}
+
+int t1_vpm150m_setreg(struct t1 *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+	int res;
+	t1_vpm150m_setpage(wc, addr >> 16);
+	if ((addr >> 16) != ((addr + len) >> 16))
+		module_printk("setreg: You found it!\n");
+	res = t1_vpm150m_setreg_full(wc, 0, len, addr & 0xffff, data);
+	return res;
+}
+
+unsigned short t1_vpm150m_getreg(struct t1 *wc, unsigned int len, unsigned int addr, unsigned short *data)
+{
+	unsigned short res;
+	t1_vpm150m_setpage(wc, addr >> 16);
+	if ((addr >> 16) != ((addr + len) >> 16))
+		module_printk("getreg: You found it!\n");
+	res = t1_vpm150m_getreg_full(wc, 0, len, addr & 0xffff, data);
+	return res;
+}
+
+static char vpm150mtone_to_zaptone(GpakToneCodes_t tone)
+{
+	switch (tone) {
+		case DtmfDigit0:
+			return '0';
+		case DtmfDigit1:
+			return '1';
+		case DtmfDigit2:
+			return '2';
+		case DtmfDigit3:
+			return '3';
+		case DtmfDigit4:
+			return '4';
+		case DtmfDigit5:
+			return '5';
+		case DtmfDigit6:
+			return '6';
+		case DtmfDigit7:
+			return '7';
+		case DtmfDigit8:
+			return '8';
+		case DtmfDigit9:
+			return '9';
+		case DtmfDigitPnd:
+			return '#';
+		case DtmfDigitSt:
+			return '*';
+		case DtmfDigitA:
+			return 'A';
+		case DtmfDigitB:
+			return 'B';
+		case DtmfDigitC:
+			return 'C';
+		case DtmfDigitD:
+			return 'D';
+		case EndofCngDigit:
+			return 'f';
+		default:
+			return 0;
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_echocan_bh(void *data)
+{
+	struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_echocan_bh(struct work_struct *data)
+{
+	struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_echocan);
+#endif
+	struct t1 *wc = vpm150m->wc;
+	struct list_head *task;
+	struct list_head *next_task;
+	unsigned long flags;
+
+	list_for_each_safe(task, next_task, &vpm150m->worklist) {
+		struct vpm150m_workentry *we = list_entry(task, struct vpm150m_workentry, list);
+		struct zt_chan *chan = we->chan;
+		int deflaw;
+		int res;
+		GPAK_AlgControlStat_t pstatus;
+
+		if (we->params.tap_length) {
+			/* configure channel for the ulaw/alaw */
+			unsigned int start = wc->intcount;
+
+			if (memcmp(&we->params, &vpm150m->chan_params[chan->chanpos - 1], sizeof(we->params))) {
+				/* set parameters */
+				vpm150m->chan_params[chan->chanpos - 1] = we->params;
+			}
+
+			deflaw = chan->span->deflaw;
+			debug_printk(1, "Enabling EC on channel %d (law %d)\n", chan->chanpos, deflaw);
+			if (deflaw == 2) /* alaw */
+				res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableALawSwCompanding, &pstatus);
+			else if (deflaw == 1) /* alaw */
+				res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableMuLawSwCompanding, &pstatus);
+			else {
+				module_printk("Undefined law for channel %d.\n", chan->chanpos);
+				res = -1;
+			}
+
+			if (res) {
+				module_printk("Unable to set SW Companding on channel %d (reason %d)\n", chan->chanpos, res);
+			}
+
+			res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, EnableEcanA, &pstatus);
+			debug_printk(2, "Echo can enable took %d ms\n", wc->intcount - start);
+		} else {
+			unsigned int start = wc->intcount;
+			debug_printk(1, "Disabling EC on channel %d\n", chan->chanpos);
+			res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassSwCompanding, &pstatus);
+			if (res)
+				module_printk("Unable to disable sw companding on echo cancellation  channel %d (reason %d)\n", chan->chanpos, res);
+			res = gpakAlgControl(vpm150m->dspid, chan->chanpos - 1, BypassEcanA, &pstatus);
+			if (res)
+				module_printk("Unable to disable echo can on channel %d (reason %d)\n", chan->chanpos, res);
+			debug_printk(2, "Echocan disable took %d ms\n", wc->intcount - start);
+		}
+		if (res) {
+			module_printk("Unable to toggle echo cancellation on channel %d (reason %d)\n", chan->chanpos, res);
+		}
+
+		spin_lock_irqsave(&vpm150m->lock, flags);
+		list_del(task);
+		spin_unlock_irqrestore(&vpm150m->lock, flags);
+		kfree(we);
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_debug_bh(void *data)
+{
+	struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_debug_bh(struct work_struct *data)
+{
+	struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_debug);
+#endif
+	unsigned short int FrammingError1Count, FramingError2Count, FramingError3Count,
+				   		DmaStopErrorCount, DmaSlipStatsBuffer;
+
+	if (gpakReadFramingStats(vpm150m->dspid, &FrammingError1Count, &FramingError2Count, &FramingError3Count,
+				   		&DmaStopErrorCount, &DmaSlipStatsBuffer)) 
+	{
+		module_printk("There was an error getting framing stats.\n");
+	}
+	if (FrammingError1Count||FramingError2Count||FramingError3Count||DmaStopErrorCount||DmaSlipStatsBuffer)
+	{
+		module_printk("FramingStats Error: %d %d %d %d %d\n",
+		FrammingError1Count, FramingError2Count, FramingError3Count, DmaStopErrorCount, DmaSlipStatsBuffer);
+	}
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void vpm150m_dtmf_bh(void *data)
+{
+	struct vpm150m *vpm150m = data;
+#else
+static void vpm150m_dtmf_bh(struct work_struct *data)
+{
+	struct vpm150m *vpm150m = container_of(data, struct vpm150m, work_dtmf);
+#endif
+	struct t1 *wc = vpm150m->wc;
+	int i;
+
+	for (i = 0; i < wc->span.channels; i++) {
+		int enable = -1;
+		if (test_bit(i, &vpm150m->desireddtmfmutestate)) {
+			if (!test_bit(i, &vpm150m->curdtmfmutestate)) {
+				enable = 1;
+			}
+		} else {
+			if (test_bit(i, &vpm150m->curdtmfmutestate)) {
+				enable = 0;
+			}
+		}
+		if (enable > -1) {
+			unsigned int start = wc->intcount;
+			GPAK_AlgControlStat_t pstatus;
+			int res;
+
+			if (enable) {
+				res = gpakAlgControl(vpm150m->dspid, i, EnableDTMFMuteA, &pstatus);
+				debug_printk(2, "DTMF mute enable took %d ms\n", wc->intcount - start);
+			} else {
+				res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &pstatus);
+				debug_printk(2, "DTMF mute disable took %d ms\n", wc->intcount - start);
+			}
+			if (!res)
+				change_bit(i, &vpm150m->curdtmfmutestate);
+		}
+	}
+
+	if (test_bit(VPM150M_DTMFDETECT, &vpm150m->control)) {
+		unsigned short channel;
+		GpakAsyncEventCode_t eventcode;
+		GpakAsyncEventData_t eventdata;
+		gpakReadEventFIFOMessageStat_t  res;
+		unsigned int start = wc->intcount;
+
+		do {
+			res = gpakReadEventFIFOMessage(vpm150m->dspid, &channel, &eventcode, &eventdata);
+			debug_printk(3, "ReadEventFIFOMessage took %d ms\n", wc->intcount - start);
+
+			if (res == RefInvalidEvent || res == RefDspCommFailure) {
+				module_printk("Uh oh (%d)\n", res);
+				continue;
+			}
+
+			if (eventcode == EventToneDetect) {
+				GpakToneCodes_t tone = eventdata.toneEvent.ToneCode;
+				int duration = eventdata.toneEvent.ToneDuration;
+				char zaptone = vpm150mtone_to_zaptone(tone);
+
+				debug_printk(1, "Channel %d: Detected DTMF tone %d of duration %d\n", channel + 1, tone, duration);
+
+				if (test_bit(channel, &wc->dtmfmask) && (eventdata.toneEvent.ToneDuration > 0)) {
+					struct zt_chan *chan = &wc->chans[channel];
+
+					module_printk("DTMF detected channel=%d tone=%d duration=%d\n", channel + 1, tone, duration);
+
+					if ((tone != EndofMFDigit) && (zaptone != 0)) {
+						vpm150m->curtone[channel] = tone;
+
+						if (test_bit(channel, &vpm150m->curdtmfmutestate)) {
+							unsigned long flags;
+							int y;
+
+							/* Mute the audio data buffers */
+							spin_lock_irqsave(&chan->lock, flags);
+							for (y = 0; y < chan->numbufs; y++) {
+								if ((chan->inreadbuf > -1) && (chan->readidx[y]))
+									memset(chan->readbuf[chan->inreadbuf], ZT_XLAW(0, chan), chan->readidx[y]);
+							}
+							spin_unlock_irqrestore(&chan->lock, flags);
+						}
+						if (!test_bit(channel, &wc->dtmfactive)) {
+							debug_printk(1,"Queuing DTMFDOWN %c\n", zaptone);
+							set_bit(channel, &wc->dtmfactive);
+							zt_qevent_lock(chan, (ZT_EVENT_DTMFDOWN | zaptone));
+						}
+					} else if ((tone == EndofMFDigit) && test_bit(channel, &wc->dtmfactive)) {
+						debug_printk(1,"Queuing DTMFUP %c\n", vpm150mtone_to_zaptone(vpm150m->curtone[channel]));
+						zt_qevent_lock(chan, (ZT_EVENT_DTMFUP | vpm150mtone_to_zaptone(vpm150m->curtone[channel])));
+						clear_bit(channel, &wc->dtmfactive);
+					}
+				}
+			}
+		} while ((res == RefEventAvail));
+	}
+	
+	return;
+}
+
+void t1_vpm150m_init(struct t1 *wc) {	
+	struct vpm150m *vpm150m;
+	unsigned short i;
+	unsigned short reg;
+	unsigned long flags;
+	gpakPingDspStat_t pingstatus;
+	gpakDownloadStatus_t downloadstatus;
+	struct t1_firmware fw;
+	struct firmware embedded_firmware;
+	const struct firmware *firmware = &embedded_firmware;
+#if !defined(HOTPLUG_FIRMWARE)
+	extern void _binary_zaptel_fw_vpmadt032_bin_size;
+	extern u8 _binary_zaptel_fw_vpmadt032_bin_start[];
+#else
+	static const char vpmadt032_firmware[] = "zaptel-fw-vpmadt032.bin";
+#endif
+
+#if 0
+	unsigned short omsg[4] = { 0xdead, 0xbeef, 0x1111, 0x2222};
+	unsigned short imsg[4];
+#endif
+
+	if (!vpmsupport) {
+		module_printk("VPM Support Disabled\n");
+		wc->vpm150m = NULL;
+		return;
+	}
+
+	vpm150m = kmalloc(sizeof(struct vpm150m), GFP_KERNEL);
+
+	if (!vpm150m) {
+		module_printk("Unable to allocate VPMADT032!\n");
+		return;
+	}
+	memset(vpm150m, 0, sizeof(struct vpm150m));
+	
+	/* Init our vpm150m struct */
+	sema_init(&vpm150m->sem, 1);
+	vpm150m->curpage = 0x80;
+
+	for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) {
+		if (ifaces[i] == wc)
+			vpm150m->dspid = i;
+	}
+
+	debug_printk(1, "Setting VPMADT032 DSP ID to %d\n", vpm150m->dspid);
+	spin_lock_irqsave(&wc->reglock, flags);
+	wc->vpm150m = vpm150m;
+	spin_unlock_irqrestore(&wc->reglock, flags);
+
+	for (i = 0; i < 10; i++)
+		schluffen(&wc->regq);
+
+	debug_printk(1, "Looking for VPMADT032 by testing page access: ");
+	for (i = 0; i < 0xf; i++) {
+		int x;
+		for (x = 0; x < 3; x++) {
+			t1_vpm150m_setpage(wc, i);
+			reg = t1_vpm150m_getpage(wc);
+			if (reg != i) {
+				/* If they have debug turned on we want them to be able to 
+				 * report where in the code the module failed to come up. */
+				debug_printk(1, "Either no VPMADT032 module present or the module failed VPM page access test (%x != %x)\n", i, reg);
+				goto failed_exit;
+			}
+		}
+	}
+	debug_printk(1, "Passed\n");
+
+	set_bit(VPM150M_HPIRESET, &vpm150m->control);
+	msleep(2000);
+
+	/* Set us up to page 0 */
+	t1_vpm150m_setpage(wc, 0);
+	debug_printk(1, "VPMADT032 now doing address test: ");
+	for (i = 0; i < 16; i++) {
+		int x;
+		for (x = 0; x < 2; x++) {
+			t1_vpm150m_setreg(wc, 1, 0x1000, &i);
+			t1_vpm150m_getreg(wc, 1, 0x1000, &reg);
+			if (reg != i) { 
+				module_printk("VPMADT032 Failed address test: sent %x != %x on try %d\n", i, reg, x);
+				goto failed_exit;
+			}
+		}
+	}
+	debug_printk(1, "Passed\n");
+	
+#if 0
+	/* begin short test */
+#define TEST_SIZE 1
+	{
+	 	int i;
+		unsigned short msg[TEST_SIZE];
+
+		set_bit(VPM150M_HPIRESET, &vpm150m->control);
+		msleep(2000);
+
+		/* lets see whats in there to start with*/
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		printk("at first :");
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%04x ", msg[i]);
+		printk("\n");
+
+		/* what if we put dead in there*/
+		for (i = 0; i< TEST_SIZE; i++)
+			msg[i] = 0xdead;
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		printk("now      :");
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%04x ", msg[i]);
+		printk("\n");
+
+		/* lets see if its in there now */
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		printk("try again:");
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%04x ", msg[i]);
+		printk("\n");
+	}
+		
+	goto failed_exit;
+#endif
+
+#define TEST_SIZE 2
+	if (debug) {
+		int i;
+		unsigned short msg[TEST_SIZE];
+
+		set_bit(VPM150M_HPIRESET, &vpm150m->control);
+		msleep(2000);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		for (i = 0; i< TEST_SIZE; i++)
+			msg[i] = 0xdead;
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		for (i = 0; i< TEST_SIZE; i++)
+			msg[i] = 0xbeef;
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		for (i = 0; i< TEST_SIZE; i++)
+			msg[i] = 0x1111;
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		for (i = 0; i< TEST_SIZE; i++)
+			msg[i] = 0x2222;
+		gpakWriteDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+		gpakReadDspMemory(vpm150m->dspid, 0x1000, TEST_SIZE, msg);
+		for (i = 0; i< TEST_SIZE; i++)
+			printk("%x ", msg[i]);
+		printk("\n");
+	}
+#if 0
+	printk("Sending\n");
+
+	for (i = 0; i < 4; i++) {
+		unsigned short x = 0xffff;
+		t1_vpm150m_setreg(wc, 1, 0x1000 + i, &x);
+	}
+
+	gpakReadDspMemory(vpm150m->dspid, 0x1000, 4, imsg);
+
+	printk("Read back:\n");
+	for (i = 0; i < 4; i++)
+		printk("%x ", imsg[i]);
+	printk("\n");
+
+	printk("Sending\n");
+	gpakWriteDspMemory(vpm150m->dspid, 0x1000, 4, omsg);
+	for (i = 0; i < 4; i++)
+		t1_vpm150m_getreg(wc, 1, 0x1000 + i, &imsg[i]);
+
+	printk("Read back\n");
+	for (i = 0; i < 4; i++)
+		printk("%x ", imsg[i]);
+	printk("\n");
+
+#endif
+
+#if 0
+	/* Load the firmware */
+	set_bit(VPM150M_SPIRESET, &vpm150m->control);
+
+	/* Wait for it to boot */
+	msleep(7000);
+
+	pingstatus = gpakPingDsp(vpm150m->dspid, &version);
+
+	if (pingstatus) {
+			module_printk("Pingstatus %d, you failed!!! Ha ha ha ha\n", pingstatus);
+	} else 
+			module_printk("version is 0x%08x\n", version);
+
+	if (pingstatus || (version != 0x106)) {
+#endif
+#if defined(HOTPLUG_FIRMWARE)
+		if ((request_firmware(&firmware, vpmadt032_firmware, &wc->dev->dev) != 0) ||
+		    !firmware) {
+			printk("VPMADT032: firmware %s not available from userspace\n", vpmadt032_firmware);
+			goto failed_exit;
+		}
+#else
+		embedded_firmware.data = _binary_zaptel_fw_vpmadt032_bin_start;
+		embedded_firmware.size = (size_t) &_binary_zaptel_fw_vpmadt032_bin_size;
+#endif
+		fw.fw = firmware;
+		fw.offset = 0;
+
+		set_bit(VPM150M_HPIRESET, &vpm150m->control);
+
+		while (test_bit(VPM150M_HPIRESET, &vpm150m->control))
+			schluffen(&wc->regq);
+
+		module_printk("VPMADT032 Loading firwmare... ");
+		downloadstatus = gpakDownloadDsp(vpm150m->dspid, &fw);
+
+		if (firmware != &embedded_firmware)
+			release_firmware(firmware);
+
+		if (downloadstatus != 0) {
+			module_printk("Unable to download firmware to VPMADT032 with cause %d\n", downloadstatus);
+			goto failed_exit;
+		} else {
+			module_printk("Success\n");
+		}
+
+		set_bit(VPM150M_SWRESET, &vpm150m->control);
+
+		while (test_bit(VPM150M_SWRESET, &vpm150m->control))
+			schluffen(&wc->regq);
+
+		msleep(700);
+#if 0
+	}
+#endif
+
+	pingstatus = gpakPingDsp(vpm150m->dspid, &vpm150m->version);
+
+	if (!pingstatus) {
+		debug_printk(1, "Version of DSP is %x\n", vpm150m->version);
+	} else {
+		module_printk("Unable to ping the DSP (%d)!\n", pingstatus);
+		goto failed_exit;
+	}
+
+	/* workqueue for DTMF and wc->span functions that cannot sleep */
+	spin_lock_init(&vpm150m->lock);
+	vpm150m->wq = create_singlethread_workqueue("wcte12xp");
+	vpm150m->wc = wc;
+	if (!vpm150m->wq) {
+		module_printk("Unable to create work queue!\n");
+		goto failed_exit;
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+	INIT_WORK(&vpm150m->work_echocan, vpm150m_echocan_bh, vpm150m);
+	INIT_WORK(&vpm150m->work_dtmf, vpm150m_dtmf_bh, vpm150m);
+	INIT_WORK(&vpm150m->work_debug, vpm150m_debug_bh, vpm150m);
+#else
+	INIT_WORK(&vpm150m->work_echocan, vpm150m_echocan_bh);
+	INIT_WORK(&vpm150m->work_dtmf, vpm150m_dtmf_bh);
+	INIT_WORK(&vpm150m->work_debug, vpm150m_debug_bh);
+#endif
+	INIT_LIST_HEAD(&wc->vpm150m->worklist); /* list of echocan tasks */
+
+	if (vpm150m_config_hw(wc)) {
+		goto failed_exit;
+	}
+
+	return;
+
+failed_exit:
+	if (vpm150m->wq) {
+		destroy_workqueue(vpm150m->wq);
+	}
+	spin_lock_irqsave(&wc->reglock, flags);
+	wc->vpm150m = NULL;
+	spin_unlock_irqrestore(&wc->reglock, flags);
+	kfree(vpm150m);
+
+	return;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadDspMemory - Read DSP memory.
+ *
+ * FUNCTION
+ *  This function reads a contiguous block of words from DSP memory starting at
+ *  the specified address.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+void gpakReadDspMemory(
+    unsigned short int DspId,   /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    DSP_ADDRESS DspAddress,     /* DSP's memory address of first word */
+    unsigned int NumWords,      /* number of contiguous words to read */
+    DSP_WORD *pWordValues       /* pointer to array of word values variable */
+    )
+{
+	struct t1 *wc = wc_find_iface(DspId);
+	int i;
+	int transcount;
+	int ret;
+
+	vpm150m_io_wait(wc);
+	if ( NumWords < VPM150M_MAX_COMMANDS ) {
+		struct vpm150m_cmd* cmds[VPM150M_MAX_COMMANDS] = {0};
+		t1_vpm150m_setpage(wc, DspAddress >> 16);
+		DspAddress &= 0xffff;
+		for (i=0; i < NumWords; ++i) {
+			ret = t1_vpm150m_getreg_full_async(wc,0,1,DspAddress+i,&pWordValues[i],
+				&cmds[i]);
+			if (0 != ret) {
+				return;
+			}
+		}
+		for (i=NumWords-1; i >=0; --i) {
+			ret = t1_vpm150m_getreg_full_return(wc,0,1,DspAddress+i,&pWordValues[i],
+				&cmds[i]);
+			if (0 != ret) {
+				return;
+			}
+		}
+	}
+	else {
+		for (i = 0; i < NumWords;) {
+			if ((NumWords - i) > VPM150M_MAX_DATA)
+				transcount = VPM150M_MAX_DATA;
+			else
+				transcount = NumWords - i;
+			t1_vpm150m_getreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+			i += transcount;
+		}
+	}
+	return;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakWriteDspMemory - Write DSP memory.
+ *
+ * FUNCTION
+ *  This function writes a contiguous block of words to DSP memory starting at
+ *  the specified address.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+void gpakWriteDspMemory(
+    unsigned short int DspId,   /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    DSP_ADDRESS DspAddress,     /* DSP's memory address of first word */
+    unsigned int NumWords,      /* number of contiguous words to write */
+    DSP_WORD *pWordValues       /* pointer to array of word values to write */
+    )
+{
+
+	struct t1 *wc = wc_find_iface(DspId);
+	int i;
+	int transcount;
+
+	if (wc && wc->vpm150m) {
+		for (i = 0; i < NumWords;) {
+			if ((NumWords - i) > VPM150M_MAX_DATA)
+					transcount = VPM150M_MAX_DATA;
+			else
+					transcount = NumWords - i;
+			t1_vpm150m_setreg(wc, transcount, DspAddress + i, &pWordValues[i]);
+			i += transcount;
+		}
+	}
+	return;
+
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakHostDelay - Delay for a fixed time interval.
+ *
+ * FUNCTION
+ *  This function delays for a fixed time interval before returning. The time
+ *  interval is the Host Port Interface sampling period when polling a DSP for
+ *  replies to command messages.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+void gpakHostDelay(void)
+{
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakLockAccess - Lock access to the specified DSP.
+ *
+ * FUNCTION
+ *  This function aquires exclusive access to the specified DSP.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+void gpakLockAccess(unsigned short DspId)
+{
+	struct t1 *wc;
+
+	wc = wc_find_iface(DspId);
+
+	if (wc) {
+		struct vpm150m *vpm = wc->vpm150m;
+
+		if (vpm)
+			down_interruptible(&vpm->sem);
+	}
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakUnlockAccess - Unlock access to the specified DSP.
+ *
+ * FUNCTION
+ *  This function releases exclusive access to the specified DSP.
+ *
+ * RETURNS
+ *  nothing
+ *
+ */
+void gpakUnlockAccess(unsigned short DspId)
+{
+	struct t1 *wc;
+
+	wc = wc_find_iface(DspId);
+
+	if (wc) {
+		struct vpm150m *vpm = wc->vpm150m;
+
+		if (vpm)
+			up(&vpm->sem);
+	}
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * gpakReadFile - Read a block of bytes from a G.PAK Download file.
+ *
+ * FUNCTION
+ *  This function reads a contiguous block of bytes from a G.PAK Download file
+ *  starting at the current file position.
+ *
+ * RETURNS
+ *  The number of bytes read from the file.
+ *   -1 indicates an error occurred.
+ *    0 indicates all bytes have been read (end of file)
+ *
+ */
+int gpakReadFile(
+    GPAK_FILE_ID FileId,        /* G.PAK Download File Identifier */
+    unsigned char *pBuffer,	/* pointer to buffer for storing bytes */
+    unsigned int NumBytes       /* number of bytes to read */
+    )
+{
+	struct t1_firmware *fw = FileId;
+	unsigned int i, count;
+
+	if (!fw || !fw->fw)
+		return -1;
+
+	if (NumBytes > (fw->fw->size - fw->offset))
+		count = fw->fw->size - fw->offset;
+	else
+		count = NumBytes;
+
+	for (i = 0; i < count; i++)
+		pBuffer[i] = fw->fw->data[fw->offset + i];
+
+	fw->offset += count;
+
+	return count;
+}
+
+int vpm150m_config_hw(struct t1 *wc)
+{
+	struct vpm150m *vpm150m = wc->vpm150m;
+	gpakConfigPortStatus_t configportstatus;
+	GpakPortConfig_t portconfig;
+	GPAK_PortConfigStat_t pstatus;
+	GpakChannelConfig_t chanconfig;
+	GPAK_ChannelConfigStat_t cstatus;
+	GPAK_AlgControlStat_t algstatus;
+
+	int res, i;
+
+	memset(&portconfig, 0, sizeof(GpakPortConfig_t));
+
+	/* First Serial Port config */
+	portconfig.SlotsSelect1 = SlotCfgNone;
+	portconfig.FirstBlockNum1 = 0;
+	portconfig.FirstSlotMask1 = 0x0000;
+	portconfig.SecBlockNum1 = 1;
+	portconfig.SecSlotMask1 = 0x0000;
+	portconfig.SerialWordSize1 = SerWordSize8;
+	portconfig.CompandingMode1 = cmpNone;
+	portconfig.TxFrameSyncPolarity1 = FrameSyncActHigh;
+	portconfig.RxFrameSyncPolarity1 = FrameSyncActHigh;
+	portconfig.TxClockPolarity1 = SerClockActHigh;
+	portconfig.RxClockPolarity1 = SerClockActHigh;
+	portconfig.TxDataDelay1 = DataDelay0;
+	portconfig.RxDataDelay1 = DataDelay0;
+	portconfig.DxDelay1 = Disabled;
+	portconfig.ThirdSlotMask1 = 0x0000;
+	portconfig.FouthSlotMask1 = 0x0000;
+	portconfig.FifthSlotMask1 = 0x0000;
+	portconfig.SixthSlotMask1 = 0x0000;
+	portconfig.SevenSlotMask1 = 0x0000;
+	portconfig.EightSlotMask1 = 0x0000;
+
+	/* Second Serial Port config */
+	portconfig.SlotsSelect2 = SlotCfg8Groups;
+	portconfig.FirstBlockNum2 = 0;
+	portconfig.FirstSlotMask2 = 0x5554;
+	portconfig.SecBlockNum2 = 1;
+	portconfig.SecSlotMask2 = 0x5555;
+	portconfig.ThirdSlotMask2 = 0x5555;
+	portconfig.FouthSlotMask2 = 0x5555;
+	portconfig.SerialWordSize2 = SerWordSize8;
+	portconfig.CompandingMode2 = cmpNone;
+	portconfig.TxFrameSyncPolarity2 = FrameSyncActHigh;
+	portconfig.RxFrameSyncPolarity2 = FrameSyncActHigh;
+	portconfig.TxClockPolarity2 = SerClockActHigh;
+	portconfig.RxClockPolarity2 = SerClockActHigh;
+	portconfig.TxDataDelay2 = DataDelay0;
+	portconfig.RxDataDelay2 = DataDelay0;
+	portconfig.DxDelay2 = Disabled;
+	portconfig.FifthSlotMask2 = 0x0001;
+	portconfig.SixthSlotMask2 = 0x0000;
+	portconfig.SevenSlotMask2 = 0x0000;
+	portconfig.EightSlotMask2 = 0x0000;
+
+	/* Third Serial Port Config */
+	portconfig.SlotsSelect3 = SlotCfg8Groups;
+	portconfig.FirstBlockNum3 = 0;
+	portconfig.FirstSlotMask3 = 0x5554;
+	portconfig.SecBlockNum3 = 1;
+	portconfig.SecSlotMask3 = 0x5555;
+	portconfig.SerialWordSize3 = SerWordSize8;
+	portconfig.CompandingMode3 = cmpNone;
+	portconfig.TxFrameSyncPolarity3 = FrameSyncActHigh;
+	portconfig.RxFrameSyncPolarity3 = FrameSyncActHigh;
+	portconfig.TxClockPolarity3 = SerClockActHigh;
+	portconfig.RxClockPolarity3 = SerClockActLow;
+	portconfig.TxDataDelay3 = DataDelay0;
+	portconfig.RxDataDelay3 = DataDelay0;
+	portconfig.DxDelay3 = Disabled;
+	portconfig.ThirdSlotMask3 = 0x5555;
+	portconfig.FouthSlotMask3 = 0x5555;
+	portconfig.FifthSlotMask3 = 0x0001;
+	portconfig.SixthSlotMask3 = 0x0000;
+	portconfig.SevenSlotMask3 = 0x0000;
+	portconfig.EightSlotMask3 = 0x0000;
+
+	if ((configportstatus = gpakConfigurePorts(vpm150m->dspid, &portconfig, &pstatus))) {
+		module_printk("Configuration of ports failed (%d)!\n", configportstatus);
+		return -1;
+	} else {
+		debug_printk(1, "Configured McBSP ports successfully\n");
+	}
+
+	if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+		module_printk("Error pinging DSP (%d)\n", res);
+		return -1;
+	}
+
+	for (i = 0; i < 32; i++) {
+		/* Let's configure a channel */
+		chanconfig.PcmInPortA = 3;
+		chanconfig.PcmInSlotA = (i + 1) * 2;
+		chanconfig.PcmOutPortA = 2;
+		chanconfig.PcmOutSlotA = (i + 1) * 2;
+		chanconfig.PcmInPortB = 2;
+		chanconfig.PcmInSlotB = (i + 1) * 2;
+		chanconfig.PcmOutPortB = 3;
+		chanconfig.PcmOutSlotB = (i + 1) * 2;
+		if (vpmdtmfsupport) {
+			chanconfig.ToneTypesA = DTMF_tone;
+			chanconfig.MuteToneA = Enabled;
+			chanconfig.FaxCngDetA = Enabled;
+		} else {
+			chanconfig.ToneTypesA = Null_tone;
+			chanconfig.MuteToneA = Disabled;
+			chanconfig.FaxCngDetA = Disabled;
+		}
+		chanconfig.ToneTypesB = Null_tone;
+		chanconfig.EcanEnableA = Enabled;
+		chanconfig.EcanEnableB = Disabled;
+		chanconfig.MuteToneB = Disabled;
+		chanconfig.FaxCngDetB = Disabled;
+
+		chanconfig.SoftwareCompand = cmpNone;
+
+		chanconfig.FrameRate = rate10ms;
+	
+		chanconfig.EcanParametersA.EcanTapLength = 1024;
+		chanconfig.EcanParametersA.EcanNlpType = vpmnlptype;
+		chanconfig.EcanParametersA.EcanAdaptEnable = 1;
+		chanconfig.EcanParametersA.EcanG165DetEnable = 1;
+		chanconfig.EcanParametersA.EcanDblTalkThresh = 6;
+		chanconfig.EcanParametersA.EcanNlpThreshold = vpmnlpthresh;
+		chanconfig.EcanParametersA.EcanNlpConv = 0;
+		chanconfig.EcanParametersA.EcanNlpUnConv = 0;
+		chanconfig.EcanParametersA.EcanNlpMaxSuppress = vpmnlpmaxsupp;
+		chanconfig.EcanParametersA.EcanCngThreshold = 43;
+		chanconfig.EcanParametersA.EcanAdaptLimit = 50;
+		chanconfig.EcanParametersA.EcanCrossCorrLimit = 15;
+		chanconfig.EcanParametersA.EcanNumFirSegments = 3;
+		chanconfig.EcanParametersA.EcanFirSegmentLen = 64;
+	
+		chanconfig.EcanParametersB.EcanTapLength = 1024;
+		chanconfig.EcanParametersB.EcanNlpType = vpmnlptype;
+		chanconfig.EcanParametersB.EcanAdaptEnable = 1;
+		chanconfig.EcanParametersB.EcanG165DetEnable = 1;
+		chanconfig.EcanParametersB.EcanDblTalkThresh = 6;
+		chanconfig.EcanParametersB.EcanNlpThreshold = vpmnlpthresh;
+		chanconfig.EcanParametersB.EcanNlpConv = 0;
+		chanconfig.EcanParametersB.EcanNlpUnConv = 0;
+		chanconfig.EcanParametersB.EcanNlpMaxSuppress = vpmnlpmaxsupp;
+		chanconfig.EcanParametersB.EcanCngThreshold = 43;
+		chanconfig.EcanParametersB.EcanAdaptLimit = 50;
+		chanconfig.EcanParametersB.EcanCrossCorrLimit = 15;
+		chanconfig.EcanParametersB.EcanNumFirSegments = 3;
+		chanconfig.EcanParametersB.EcanFirSegmentLen = 64;
+	
+		if ((res = gpakConfigureChannel(vpm150m->dspid, i, tdmToTdm, &chanconfig, &cstatus))) {
+			module_printk("Unable to configure channel (%d)\n", res);
+			if (res == 1) {
+				module_printk("Reason %d\n", cstatus);
+			}
+	
+			return -1;
+		}
+
+		if ((res = gpakAlgControl(vpm150m->dspid, i, BypassEcanA, &algstatus))) {
+			module_printk("Unable to disable echo can on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+			return -1;
+		}
+
+		if (vpmdtmfsupport) {
+			if ((res = gpakAlgControl(vpm150m->dspid, i, DisableDTMFMuteA, &algstatus))) {
+				module_printk("Unable to disable dtmf muting  on channel %d (reason %d:%d)\n", i + 1, res, algstatus);
+				return -1;
+			}
+		}
+	}
+
+	if ((res = gpakPingDsp(vpm150m->dspid, &vpm150m->version))) {
+		module_printk("Error pinging DSP (%d)\n", res);
+		return -1;
+	}
+
+	/* Turn on DTMF detection */
+	if (vpmdtmfsupport)
+		set_bit(VPM150M_DTMFDETECT, &vpm150m->control);
+	set_bit(VPM150M_ACTIVE, &vpm150m->control);
+
+	return 0;
+}
+
+#endif
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/vpmadt032.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/vpmadt032.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/vpmadt032.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/vpmadt032.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,148 @@
+/*
+ * Digium, Inc.  Wildcard TE12xP T1/E1 card Driver
+ *
+ * Written by Michael Spiceland <mspiceland@digium.com>
+ *
+ * Adapted from the wctdm24xxp and wcte11xp drivers originally
+ * written by Mark Spencer <markster@digium.com>
+ *            Matthew Fredrickson <creslin@digium.com>
+ *            William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _VPM150M_H
+#define _VPM150M_H
+
+#include "wcte12xp.h"
+#include "adt_lec.h"
+
+struct t1_firmware {
+	const struct firmware *fw;
+	unsigned int offset;
+};
+
+/* Host and DSP system dependent related definitions. */
+#define MAX_DSP_CORES 128                 /* maximum number of DSP cores */
+//#define MAX_CONFS 1                     /* maximum number of conferences */
+//#define MAX_PKT_CHANNELS 8              /* maximum number of packet channels */
+#define MAX_CHANNELS 32                  /* maximum number of channels */
+#define MAX_WAIT_LOOPS 50               /* max number of wait delay loops */
+#define DSP_IFBLK_ADDRESS 0x0100        /* DSP address of I/F block pointer */
+#define DOWNLOAD_BLOCK_SIZE 512	        /* download block size (DSP words) */
+//#define MAX_CIDPAYLOAD_BYTES 512        /* max size of a CID payload (octets) */
+typedef unsigned short DSP_WORD;    /* 16 bit DSP word */
+typedef unsigned int DSP_ADDRESS;  /* 32 bit DSP address */
+typedef struct t1_firmware* GPAK_FILE_ID; /* G.PAK Download file identifier */
+
+#define __VPM150M_RWPAGE	(1 << 4)
+#define __VPM150M_RD		(1 << 3)
+#define __VPM150M_WR		(1 << 2)
+#define __VPM150M_FIN		(1 << 1)
+#define __VPM150M_TX		(1 << 0)
+
+#define VPM150M_HPI_CONTROL 0x00
+#define VPM150M_HPI_ADDRESS 0x02
+#define VPM150M_HPI_DATA 0x03
+
+#define VPM150M_MAX_COMMANDS 8
+
+/* Some Bit ops for different operations */
+#define VPM150M_SPIRESET		0
+#define VPM150M_HPIRESET		1
+#define VPM150M_SWRESET			2
+#define VPM150M_DTMFDETECT		3
+#define VPM150M_ACTIVE			4
+#define VPM150M_MAX_DATA		1
+
+struct vpm150m_cmd {
+	unsigned short address;
+	unsigned short data[VPM150M_MAX_DATA];
+	unsigned char ident;
+	unsigned char datalen;
+	unsigned int flags;
+	unsigned char cs_slot;
+};
+
+struct vpm150m {
+	unsigned short dspid;
+	unsigned long control;
+	unsigned char curpage;
+	unsigned short version;
+	struct vpm150m_cmd cmdq[VPM150M_MAX_COMMANDS];
+	spinlock_t lock; /* control access to list of bottom half tasks */
+	struct semaphore sem;
+	struct workqueue_struct *wq;
+	struct work_struct work_dtmf;
+	struct work_struct work_debug;
+	struct work_struct work_echocan;
+	struct list_head worklist;
+	unsigned char curtone[32];
+	unsigned long curdtmfmutestate;
+	unsigned long desireddtmfmutestate;
+	struct adt_lec_params chan_params[32];
+	struct t1 *wc;
+};
+
+/* linked list for vpm echocan workqueue*/
+struct vpm150m_workentry {
+	struct list_head list;
+	struct t1 *wc; /* what card are we dealing with? */
+	struct zt_chan *chan; /* what channels are we going to deal with? */
+	struct adt_lec_params params; /* how should we behave? */
+};
+
+extern int debug;
+extern int vpmsupport;
+extern int vpmdtmfsupport;
+extern struct pci_driver te12xp_driver;
+
+void t1_vpm150m_init(struct t1 *wc);
+void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int whichframe);
+void vpm150m_cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk);
+int vpm150m_config_hw(struct t1 *wc);
+
+/* gpak API functions */
+void gpakReadDspMemory(
+    unsigned short int DspId,   /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    DSP_ADDRESS DspAddress,     /* DSP's memory address of first word */
+    unsigned int NumWords,      /* number of contiguous words to read */
+    DSP_WORD *pWordValues       /* pointer to array of word values variable */
+    );
+void gpakWriteDspMemory(
+    unsigned short int DspId,   /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    DSP_ADDRESS DspAddress,     /* DSP's memory address of first word */
+    unsigned int NumWords,      /* number of contiguous words to write */
+    DSP_WORD *pWordValues       /* pointer to array of word values to write */
+    );
+void gpakHostDelay(void);
+void gpakLockAccess(
+    unsigned short int DspId      /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    );
+void gpakUnlockAccess(
+    unsigned short int DspId       /* DSP Identifier (0 to MAX_DSP_CORES-1) */
+    );
+int gpakReadFile(
+    GPAK_FILE_ID FileId,        /* G.PAK Download File Identifier */
+    unsigned char *pBuffer,	    /* pointer to buffer for storing bytes */
+    unsigned int NumBytes       /* number of bytes to read */
+    );
+
+#endif
diff -uNr zaptel-1.4.8/wcte12xp/.svn/text-base/wcte12xp.h.svn-base zaptel-1.4/wcte12xp/.svn/text-base/wcte12xp.h.svn-base
--- zaptel-1.4.8/wcte12xp/.svn/text-base/wcte12xp.h.svn-base	1970-01-01 01:00:00.000000000 +0100
+++ zaptel-1.4/wcte12xp/.svn/text-base/wcte12xp.h.svn-base	2008-02-03 17:46:02.000000000 +0100
@@ -0,0 +1,179 @@
+/*
+ * Digium, Inc.  Wildcard TE12xP T1/E1 card Driver
+ *
+ * Written by Michael Spiceland <mspiceland@digium.com>
+ *
+ * Adapted from the wctdm24xxp and wcte11xp drivers originally
+ * written by Mark Spencer <markster@digium.com>
+ *            Matthew Fredrickson <creslin@digium.com>
+ *            William Meadows <wmeadows@digium.com>
+ *
+ * Copyright (C) 2007, Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * 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 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the 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 _WCTE12XP_H
+#define _WCTE12XP_H
+
+#ifdef LINUX26
+/* Comment to disable VPM support */
+#define VPM_SUPPORT 1
+#endif
+
+#define WC_MAX_IFACES 8
+
+#ifdef VPM_SUPPORT
+#define MAX_TDM_CHAN 31
+#endif
+
+#define SDI_CLK		(0x00010000)
+#define SDI_DOUT	(0x00020000)
+#define SDI_DREAD	(0x00040000)
+#define SDI_DIN		(0x00080000)
+
+#define EFRAME_SIZE	108
+#define ERING_SIZE	16		/* Maximum ring size */
+#define EFRAME_GAP	20
+#define SFRAME_SIZE	((EFRAME_SIZE * ZT_CHUNKSIZE) + (EFRAME_GAP * (ZT_CHUNKSIZE - 1)))
+
+#define PCI_WINDOW_SIZE ((2 * 2 * 2 * SFRAME_SIZE) + (2 * ERING_SIZE * 4))
+
+#define MAX_COMMANDS 7*7*2 /* 42 bytes /3 (cntl,addr,data) /2 (cs) */
+
+#define ISR_COMMANDS  2
+#define NUM_EC 4
+
+#define __CMD_VPM  (1 << 16)		/* flag for VPM action */
+#define __CMD_ISR  (1 << 17)		/* flag for ISR reads */
+#define __CMD_PINS (1 << 18)		/* CPLD pin read */
+#define __CMD_LEDS (1 << 19)		/* LED Operation */
+#define __CMD_RD   (1 << 20)		/* Read Operation */
+#define __CMD_WR   (1 << 21)		/* Write Operation */
+#define __CMD_FIN  (1 << 22)		/* Has finished receive */
+#define __CMD_TX   (1 << 23)		/* Has been transmitted */
+
+#define __LED_ORANGE	(1<<3)
+#define __LED_GREEN	(1<<2)
+#define __LED_RED	(1<<1)
+
+#define SET_LED_ORANGE(a) a | __LED_ORANGE 
+#define SET_LED_RED(a) (a | __LED_RED) & ~__LED_GREEN
+#define SET_LED_GREEN(a) (a | __LED_GREEN) & ~__LED_RED
+
+#define UNSET_LED_ORANGE(a) a & ~__LED_ORANGE 
+#define UNSET_LED_REDGREEN(a) a | __LED_RED | __LED_GREEN
+
+#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR)
+#define CMD_RD(a) (((a) << 8) | __CMD_RD)
+#define CMD_LEDS(a) (((a) << 8) | __CMD_LEDS)
+//#define CMD_BYTE(slot, a) (slot*6)+(a*2) /* only even slots */
+#define CMD_BYTE(slot, a, is_vpm) (slot*6)+(a*2)+is_vpm /* only even slots */
+//TODO: make a separate macro
+
+#define TYPE_T1	1
+#define TYPE_E1	2
+
+#define NOT_VPM -1
+
+#define module_printk(fmt, args...) printk("%s: " fmt, te12xp_driver.name, ## args)
+#define debug_printk(level, fmt, args...) if (debug >= level) printk("%s (%s): " fmt, te12xp_driver.name, __FUNCTION__, ## args)
+extern spinlock_t ifacelock;
+
+struct command {
+	unsigned short address;
+	unsigned char data;
+	unsigned char ident;
+	unsigned int flags;
+	unsigned char cs_slot;
+	unsigned char vpm_num; /* ignored for all but vpm commmands */
+};
+
+struct cmdq {
+	struct command cmds[MAX_COMMANDS];
+	unsigned char isrshadow[ISR_COMMANDS];
+};
+
+struct vpm150m;
+
+struct t1 {
+	struct pci_dev *dev;
+	spinlock_t reglock;
+	unsigned char txident;
+	unsigned char rxident;
+	unsigned char statreg; /* bit 0 = vpmadt032 int */
+	int spantype;
+	struct {
+		unsigned int nmf:1;
+		unsigned int sendingyellow:1;
+	} flags;
+	unsigned char txsigs[16];  /* Copy of tx sig registers */
+	int num;
+	int alarmcount;			/* How much red alarm we've seen */
+	int alarmdebounce;
+	char *variety;
+	unsigned int intcount;
+	int sync;
+	int dead;
+	int blinktimer;
+	int alarmtimer;
+	int yellowtimer;
+	int ledlastvalue;
+	int alarms_read;
+	int checktiming;	/* Set >0 to cause the timing source to be checked */
+	int loopupcnt;
+	int loopdowncnt;
+	int initialized;
+	int *chanmap;
+	unsigned char ledtestreg;
+	unsigned long iobase;
+	unsigned char ec_chunk1[32][ZT_CHUNKSIZE];
+	unsigned char ec_chunk2[32][ZT_CHUNKSIZE];
+	struct zt_span span;						/* Span */
+	struct zt_chan chans[32];					/* Channels */
+	int freeregion;
+	unsigned int intmask;
+	wait_queue_head_t regq;
+	struct cmdq	cmdq;
+	struct command dummy;	/* preallocate for dummy noop command */
+	unsigned char ctlreg;
+	int rdbl;
+	int tdbl;
+	unsigned int rxints;
+	unsigned int txints;
+	unsigned int sdi;
+	int usecount;
+	dma_addr_t 	readdma;
+	dma_addr_t	writedma;
+	dma_addr_t  descripdma;
+	volatile unsigned int *writechunk;
+	volatile unsigned int *readchunk;
+	volatile unsigned int *descripchunk;
+	unsigned int isrreaderrors;
+#ifdef VPM_SUPPORT
+	int vpm;
+	struct vpm150m *vpm150m;
+	unsigned long dtmfactive;
+	unsigned long dtmfmask;
+	unsigned long dtmfmutemask;
+#endif
+};
+
+int schluffen(wait_queue_head_t *q);
+
+#endif
diff -uNr zaptel-1.4.8/wcte12xp/vpmadt032.c zaptel-1.4/wcte12xp/vpmadt032.c
--- zaptel-1.4.8/wcte12xp/vpmadt032.c	2008-01-11 00:15:28.000000000 +0100
+++ zaptel-1.4/wcte12xp/vpmadt032.c	2008-02-03 17:46:02.000000000 +0100
@@ -42,6 +42,10 @@
 
 extern struct t1 *ifaces[WC_MAX_IFACES];
 
+extern int vpmnlptype;
+extern int vpmnlpthresh;
+extern int vpmnlpmaxsupp;
+
 #ifdef VPM_SUPPORT
 
 inline void vpm150m_cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int whichframe)
@@ -1314,14 +1318,14 @@
 		chanconfig.FrameRate = rate10ms;
 	
 		chanconfig.EcanParametersA.EcanTapLength = 1024;
-		chanconfig.EcanParametersA.EcanNlpType = 1;
+		chanconfig.EcanParametersA.EcanNlpType = vpmnlptype;
 		chanconfig.EcanParametersA.EcanAdaptEnable = 1;
 		chanconfig.EcanParametersA.EcanG165DetEnable = 1;
 		chanconfig.EcanParametersA.EcanDblTalkThresh = 6;
-		chanconfig.EcanParametersA.EcanNlpThreshold = 24;
+		chanconfig.EcanParametersA.EcanNlpThreshold = vpmnlpthresh;
 		chanconfig.EcanParametersA.EcanNlpConv = 0;
 		chanconfig.EcanParametersA.EcanNlpUnConv = 0;
-		chanconfig.EcanParametersA.EcanNlpMaxSuppress = 0;
+		chanconfig.EcanParametersA.EcanNlpMaxSuppress = vpmnlpmaxsupp;
 		chanconfig.EcanParametersA.EcanCngThreshold = 43;
 		chanconfig.EcanParametersA.EcanAdaptLimit = 50;
 		chanconfig.EcanParametersA.EcanCrossCorrLimit = 15;
@@ -1329,14 +1333,14 @@
 		chanconfig.EcanParametersA.EcanFirSegmentLen = 64;
 	
 		chanconfig.EcanParametersB.EcanTapLength = 1024;
-		chanconfig.EcanParametersB.EcanNlpType = 1;
+		chanconfig.EcanParametersB.EcanNlpType = vpmnlptype;
 		chanconfig.EcanParametersB.EcanAdaptEnable = 1;
 		chanconfig.EcanParametersB.EcanG165DetEnable = 1;
 		chanconfig.EcanParametersB.EcanDblTalkThresh = 6;
-		chanconfig.EcanParametersB.EcanNlpThreshold = 24;
+		chanconfig.EcanParametersB.EcanNlpThreshold = vpmnlpthresh;
 		chanconfig.EcanParametersB.EcanNlpConv = 0;
 		chanconfig.EcanParametersB.EcanNlpUnConv = 0;
-		chanconfig.EcanParametersB.EcanNlpMaxSuppress = 0;
+		chanconfig.EcanParametersB.EcanNlpMaxSuppress = vpmnlpmaxsupp;
 		chanconfig.EcanParametersB.EcanCngThreshold = 43;
 		chanconfig.EcanParametersB.EcanAdaptLimit = 50;
 		chanconfig.EcanParametersB.EcanCrossCorrLimit = 15;
diff -uNr zaptel-1.4.8/wcte12xp/wcte12xp.h zaptel-1.4/wcte12xp/wcte12xp.h
--- zaptel-1.4.8/wcte12xp/wcte12xp.h	2007-12-08 18:28:28.000000000 +0100
+++ zaptel-1.4/wcte12xp/wcte12xp.h	2008-02-03 17:46:02.000000000 +0100
@@ -31,8 +31,10 @@
 #ifndef _WCTE12XP_H
 #define _WCTE12XP_H
 
+#ifdef LINUX26
 /* Comment to disable VPM support */
 #define VPM_SUPPORT 1
+#endif
 
 #define WC_MAX_IFACES 8
 
