[Pkg-voip-commits] r8989 - in /dahdi-linux/trunk/debian: changelog patches/dahdi_linux_extra patches/define_spinlock patches/series rules

tzafrir at alioth.debian.org tzafrir at alioth.debian.org
Sun Jun 19 17:03:59 UTC 2011


Author: tzafrir
Date: Sun Jun 19 17:03:58 2011
New Revision: 8989

URL: http://svn.debian.org/wsvn/pkg-voip/?sc=1&rev=8989
Log:
* Updated dahdi-linux-extra:
  - "Upstream" is now a complete git mirror.
  - Actually include ap400 in the list of modules to build.
  - Updated OpenVox drivers: opvxa1200 is a subdirectory
  - Updated OpenVox drivers: opvxd115 added (digital cards).
* Patch define_spinlock: include a (slightly big) build fix from upstream.

Added:
    dahdi-linux/trunk/debian/patches/define_spinlock
Modified:
    dahdi-linux/trunk/debian/changelog
    dahdi-linux/trunk/debian/patches/dahdi_linux_extra
    dahdi-linux/trunk/debian/patches/series
    dahdi-linux/trunk/debian/rules

Modified: dahdi-linux/trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/changelog?rev=8989&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/changelog (original)
+++ dahdi-linux/trunk/debian/changelog Sun Jun 19 17:03:58 2011
@@ -1,8 +1,14 @@
 dahdi-linux (1:2.4.1.1+dfsg-1) UNRELEASED; urgency=low
 
-  * New Upstream release.
-
- -- Tzafrir Cohen <tzafrir at debian.org>  Sun, 13 Mar 2011 23:57:05 +0200
+  * New upstream minor release.
+  * Updated dahdi-linux-extra:
+    - "Upstream" is now a complete git mirror.
+    - Actually include ap400 in the list of modules to build.
+    - Updated OpenVox drivers: opvxa1200 is a subdirectory 
+    - Updated OpenVox drivers: opvxd115 added (digital cards).
+  * Patch define_spinlock: include a (slightly big) build fix from upstream.
+
+ -- Tzafrir Cohen <tzafrir at debian.org>  Sun, 19 Jun 2011 19:27:29 +0300
 
 dahdi-linux (1:2.4.1+dfsg-1) unstable; urgency=low
 

Modified: dahdi-linux/trunk/debian/patches/dahdi_linux_extra
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/patches/dahdi_linux_extra?rev=8989&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/patches/dahdi_linux_extra (original)
+++ dahdi-linux/trunk/debian/patches/dahdi_linux_extra Sun Jun 19 17:03:58 2011
@@ -1,19 +1,265 @@
-Subject: dahdi-extra: out-of-tree DAHDI drivers 
-Origin: http://gitorious.org/dahdi-extra 
-Forwarded: No 
-Last-Update: 2011-03-07 
+Subject: dahdi-extra: out-of-tree DAHDI drivers
+Origin: http://gitorious.org/dahdi-extra/dahdi-linux-extra
+Forwarded: No
+Last-Update: 2011-06-19
  
-This patch includes a number of out-of-tree DAHDI drivers from the 
-dahdi-extra repository. They are all out-of-tree and are highly likely 
- not to be included in DAHDI-linux in the forseeable future. 
+This patch includes a number of out-of-tree DAHDI drivers from the
+dahdi-extra repository. They are all out-of-tree and are highly likely
+not to be included in DAHDI-linux in the forseeable future.
  
-Git-Commit: 0343810f314e7d934aaa7dde1e2e6d3ea6777251 
-Dahdi: tags/2.4.1 
+Git-Commit: 9268744f9bc0c5aa29e16cb847fa058b2ff3f8ec
+Dahdi: tags/2.4.1.1
 ---
-
-diff -urN dahdi-svn-orig/drivers/dahdi/ap400/ap400_drv.c dahdi-svn-new/drivers/dahdi/ap400/ap400_drv.c
---- dahdi-svn-orig/drivers/dahdi/ap400/ap400_drv.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/ap400/ap400_drv.c	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/Kbuild b/drivers/dahdi/Kbuild
+index 3fe2e28..bdc8144 100644
+--- a/drivers/dahdi/Kbuild
++++ b/drivers/dahdi/Kbuild
+@@ -29,6 +29,14 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_STEVE2)	+= dahdi_echocan_sec2.o
+ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_KB1)	+= dahdi_echocan_kb1.o
+ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_MG2)	+= dahdi_echocan_mg2.o
+ 
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_AP400)		+= ap400/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115)          += opvxd115/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200)         += opvxa1200/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCOPENPCI)		+= wcopenpci.o
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC)		+= zaphfc/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_ECHO)			+= ../staging/echo/
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_OSLEC)	+= dahdi_echocan_oslec.o
++
+ obj-m += $(DAHDI_MODULES_EXTRA)
+ 
+ # Only enable this if you think you know what you're doing. This is not
+diff --git a/drivers/dahdi/Kconfig b/drivers/dahdi/Kconfig
+index 6952c6a..3ad3e6c 100644
+--- a/drivers/dahdi/Kconfig
++++ b/drivers/dahdi/Kconfig
+@@ -292,3 +292,76 @@ config DAHDI_WCTE11XP
+ 	  If unsure, say Y.
+ 
+ source "drivers/dahdi/xpp/Kconfig"
++
++
++config DAHDI_OPVXD115
++        tristate "OpenVox Single-T1/E1/J1 Support"
++        depends on DAHDI && PCI
++        default DAHDI
++        ---help---
++          This driver provides support for the following OpenVox
++          Wildcard products:
++
++          * D115P/DE115P/D130P/DE130P (PCI)
++          * D115E/DE115E/D130E/DE130E (PCI-E)
++
++          To compile this driver as a module, choose M here: the
++          module will be called opvxd115.
++
++          If unsure, say Y.
++
++config DAHDI_OPVXA1200
++        tristate "OpenVox 8/12 ports analog card Support"
++        depends on DAHDI && PCI
++        default DAHDI
++        ---help---
++          This driver provides support for the following OpenVox
++          Wildcard products:
++
++          * A1200P (PCI)
++          * A1200E (PCI-E)
++          * A800P (PCI)
++          * A800E (PCI-E)
++
++          To compile this driver as a module, choose M here: the
++          module will be called opvxa1200.
++
++          If unsure, say Y.
++
++config DAHDI_WCOPENPCI
++	tristate "Voicetronix OpenPCI Interface DAHDI driver"
++	depends on DAHDI && PCI
++	default DAHDI
++	---help---
++	  This driver provides support for the Voicetronix OpenPCI Interface.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called wcopenpci.
++
++	  If unsure, say Y.
++
++config DAHDI_ZAPHFC
++	tristate "HFC-S DAHDI Driver"
++	depends on DAHDI && PCI
++	default DAHDI
++	---help---
++	  This driver provides DAHDI support for various HFC-S single-port 
++          ISDN (BRI) cards.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called zaphfc.
++
++	  If unsure, say Y.
++
++config ECHO
++	tristate "Line Echo Canceller support"
++	default DAHDI
++	--help--
++	  This driver provides line echo cancelling support for mISDN and
++	  DAHDI drivers.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called echo.
++
++	  If unsure, say Y.
++
+diff --git a/drivers/dahdi/ap400/Kbuild b/drivers/dahdi/ap400/Kbuild
+new file mode 100644
+index 0000000..d124261
+--- /dev/null
++++ b/drivers/dahdi/ap400/Kbuild
+@@ -0,0 +1,26 @@
++obj-m += ap400.o
++
++EXTRA_CFLAGS := -I$(src)/.. 
++
++ap400-objs := ap400_drv.o
++
++# APEC_SUPPORT
++ECHO_FIRMWARE := $(wildcard $(src)/OCT61*.ima)
++ifneq ($(strip $(ECHO_FIRMWARE)),)
++	EXTRA_CFLAGS+=-DAPEC_SUPPORT $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
++	ap400-objs += apec.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x) firmware_oct6104e-64d.o firmware_oct6104e-128d.o
++endif
++
++$(obj)/apec.o: $(src)/apec.h $(src)/../oct612x/include/oct6100api/oct6100_api.h
++
++$(obj)/firmware_oct6104e-64d.o: $(src)/OCT6104E-64D.ima $(obj)/ap400_drv.o $(src)/../firmware/make_firmware_object
++	@echo Making firmware object file for $(notdir $<)
++	@cd $(src) && ../firmware/make_firmware_object $(notdir $<) $@ $(obj)/ap400_drv.o
++
++$(obj)/firmware_oct6104e-128d.o: $(src)/OCT6104E-128D.ima $(obj)/ap400_drv.o $(src)/../firmware/make_firmware_object
++	@echo Making firmware object file for $(notdir $<)
++	@cd $(src) && ../firmware/make_firmware_object $(notdir $<) $@ $(obj)/ap400_drv.o
++
++$(src)/../firmware/make_firmware_object:
++	make -C $(src)/../firmware make_firmware_object
++
+diff --git a/drivers/dahdi/ap400/ap400.h b/drivers/dahdi/ap400/ap400.h
+new file mode 100644
+index 0000000..ba233d1
+--- /dev/null
++++ b/drivers/dahdi/ap400/ap400.h
+@@ -0,0 +1,107 @@
++/*
++ * AP4XX  T1/E1 PCI Driver
++ *
++ * Written by Ronaldo Valiati <aligera at aligera.com.br>
++ *
++ * Based on previous works, designs, and archetectures conceived and
++ * written by Jim Dixon <jim at lambdatel.com> and Mark Spencer <markster at digium.com>.
++ *
++ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
++ * Copyright (C) 2001-2005, 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/ioctl.h>
++
++
++#define AP4_GET_ALARMS  _IOW (DAHDI_CODE, 60, int)
++#define AP4_GET_SLIPS	_IOW (DAHDI_CODE, 61, int)
++
++#define AP4XX_CARD_ID		0x41434532		// "ACE2"
++#define APE4XX_CARD_ID		0x41504534		// "APE4"
++
++#define AP_CAS_BASE		0x0080
++#define AP_DATA_BASE		0x0100
++
++#define AP_CARD_TYPE_REG	0x0001
++#define AP_T1E1_CONFIG_REG	0x0003
++#define AP_E1_CONFIG_REG	0x0004
++#define AP_E1_STATUS_REG	0x0005
++#define AP_LEDS_REG		0x0006
++#define AP_CLKSRC_REG		0x0007
++#define AP_HWCONFIG_REG		0x0008
++#define AP_INT_CONTROL_REG	0x0009
++#define AP_CNT_IRQ_REG		0x000B
++#define AP_CNT_CV_REG		0x000C
++#define AP_CNT_CRC_REG		0x000D
++#define AP_CLEAR_IRQ_REG	0x000E
++#define AP_CNT_SLIP_REG		0x000F
++
++#define AP_HWID_MASK		0x00F0
++
++#define AP_CLKSRC_MASK		0x07
++
++#define AP_LIU1_LINECODE	0x0080
++#define AP_LIU2_LINECODE	0x0100
++#define AP_LIU_RESET_BIT	0x0200
++
++#define AP_E1_AIS_STATUS	0x01
++#define AP_E1_BFAE_STATUS	0x02
++#define AP_E1_MFAE_STATUS	0x04
++#define AP_E1_SYNC_STATUS	0x08
++#define AP_E1_CAS_STATUS	0x10
++#define AP_E1_LOS_STATUS	0x20
++#define AP_E1_RAI_STATUS	0x40
++
++#define AP_E1_RAI_CONFIG	0x01
++#define AP_E1_LOOP_CONFIG	0x10
++#define AP_E1_CASEN_CONFIG	0x20
++#define AP_E1_PCM30_CONFIG	0x40
++#define AP_E1_CRCEN_CONFIG	0x80
++
++#define AP_INT_CTL_ENABLE	0x01
++#define AP_INT_CTL_ACTIVE	0x02
++
++#define AP_HWID_1E1_RJ		0x01
++#define AP_HWID_2E1_RJ		0x00
++#define AP_HWID_4E1_RJ		0x02
++#define AP_HWID_T1		0x04
++
++#define AP4_T1_NE1_SEL		0x04
++#define AP4_T1_ESF_NSF		0x02
++#define AP4_T1_CAS_ENABLE	0x01
++
++#define AP4_T1_FRAME_SYNC	0x01
++
++
++typedef enum {
++	AP_PULS_E1_75 = 0,
++	AP_PULS_E1_120,
++	AP_PULS_DSX1_0FT,
++	AP_PULS_DSX1_133FT,
++	AP_PULS_DSX1_266FT,
++	AP_PULS_DSX1_399FT,
++	AP_PULS_DSX1_533FT,
++	AP_PULS_J1_110,
++	AP_PULS_DS1_0DB,
++	AP_PULS_DS1_M075DB,
++	AP_PULS_DS1_M150DB,
++	AP_PULS_DS1_M225DB
++} liu_mode;
++
+diff --git a/drivers/dahdi/ap400/ap400_drv.c b/drivers/dahdi/ap400/ap400_drv.c
+new file mode 100644
+index 0000000..5153af0
+--- /dev/null
++++ b/drivers/dahdi/ap400/ap400_drv.c
 @@ -0,0 +1,2363 @@
 +/*
 + * AP4XX PCI Card Driver
@@ -2378,120 +2624,11 @@
 +
 +module_init(ap4_init);
 +module_exit(ap4_cleanup);
-diff -urN dahdi-svn-orig/drivers/dahdi/ap400/ap400.h dahdi-svn-new/drivers/dahdi/ap400/ap400.h
---- dahdi-svn-orig/drivers/dahdi/ap400/ap400.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/ap400/ap400.h	2011-03-07 11:52:51.411050187 +0200
-@@ -0,0 +1,107 @@
-+/*
-+ * AP4XX  T1/E1 PCI Driver
-+ *
-+ * Written by Ronaldo Valiati <aligera at aligera.com.br>
-+ *
-+ * Based on previous works, designs, and archetectures conceived and
-+ * written by Jim Dixon <jim at lambdatel.com> and Mark Spencer <markster at digium.com>.
-+ *
-+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
-+ * Copyright (C) 2001-2005, 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/ioctl.h>
-+
-+
-+#define AP4_GET_ALARMS  _IOW (DAHDI_CODE, 60, int)
-+#define AP4_GET_SLIPS	_IOW (DAHDI_CODE, 61, int)
-+
-+#define AP4XX_CARD_ID		0x41434532		// "ACE2"
-+#define APE4XX_CARD_ID		0x41504534		// "APE4"
-+
-+#define AP_CAS_BASE		0x0080
-+#define AP_DATA_BASE		0x0100
-+
-+#define AP_CARD_TYPE_REG	0x0001
-+#define AP_T1E1_CONFIG_REG	0x0003
-+#define AP_E1_CONFIG_REG	0x0004
-+#define AP_E1_STATUS_REG	0x0005
-+#define AP_LEDS_REG		0x0006
-+#define AP_CLKSRC_REG		0x0007
-+#define AP_HWCONFIG_REG		0x0008
-+#define AP_INT_CONTROL_REG	0x0009
-+#define AP_CNT_IRQ_REG		0x000B
-+#define AP_CNT_CV_REG		0x000C
-+#define AP_CNT_CRC_REG		0x000D
-+#define AP_CLEAR_IRQ_REG	0x000E
-+#define AP_CNT_SLIP_REG		0x000F
-+
-+#define AP_HWID_MASK		0x00F0
-+
-+#define AP_CLKSRC_MASK		0x07
-+
-+#define AP_LIU1_LINECODE	0x0080
-+#define AP_LIU2_LINECODE	0x0100
-+#define AP_LIU_RESET_BIT	0x0200
-+
-+#define AP_E1_AIS_STATUS	0x01
-+#define AP_E1_BFAE_STATUS	0x02
-+#define AP_E1_MFAE_STATUS	0x04
-+#define AP_E1_SYNC_STATUS	0x08
-+#define AP_E1_CAS_STATUS	0x10
-+#define AP_E1_LOS_STATUS	0x20
-+#define AP_E1_RAI_STATUS	0x40
-+
-+#define AP_E1_RAI_CONFIG	0x01
-+#define AP_E1_LOOP_CONFIG	0x10
-+#define AP_E1_CASEN_CONFIG	0x20
-+#define AP_E1_PCM30_CONFIG	0x40
-+#define AP_E1_CRCEN_CONFIG	0x80
-+
-+#define AP_INT_CTL_ENABLE	0x01
-+#define AP_INT_CTL_ACTIVE	0x02
-+
-+#define AP_HWID_1E1_RJ		0x01
-+#define AP_HWID_2E1_RJ		0x00
-+#define AP_HWID_4E1_RJ		0x02
-+#define AP_HWID_T1		0x04
-+
-+#define AP4_T1_NE1_SEL		0x04
-+#define AP4_T1_ESF_NSF		0x02
-+#define AP4_T1_CAS_ENABLE	0x01
-+
-+#define AP4_T1_FRAME_SYNC	0x01
-+
-+
-+typedef enum {
-+	AP_PULS_E1_75 = 0,
-+	AP_PULS_E1_120,
-+	AP_PULS_DSX1_0FT,
-+	AP_PULS_DSX1_133FT,
-+	AP_PULS_DSX1_266FT,
-+	AP_PULS_DSX1_399FT,
-+	AP_PULS_DSX1_533FT,
-+	AP_PULS_J1_110,
-+	AP_PULS_DS1_0DB,
-+	AP_PULS_DS1_M075DB,
-+	AP_PULS_DS1_M150DB,
-+	AP_PULS_DS1_M225DB
-+} liu_mode;
-+
-diff -urN dahdi-svn-orig/drivers/dahdi/ap400/apec.c dahdi-svn-new/drivers/dahdi/ap400/apec.c
---- dahdi-svn-orig/drivers/dahdi/ap400/apec.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/ap400/apec.c	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/ap400/apec.c b/drivers/dahdi/ap400/apec.c
+new file mode 100644
+index 0000000..b43655e
+--- /dev/null
++++ b/drivers/dahdi/ap400/apec.c
 @@ -0,0 +1,390 @@
 +/*
 + * AP400 Echo Cancelation Hardware support
@@ -2883,9 +3020,11 @@
 +	kfree(apec);
 +	printk(KERN_INFO "APEC: Releasing...\n");
 +}
-diff -urN dahdi-svn-orig/drivers/dahdi/ap400/apec.h dahdi-svn-new/drivers/dahdi/ap400/apec.h
---- dahdi-svn-orig/drivers/dahdi/ap400/apec.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/ap400/apec.h	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/ap400/apec.h b/drivers/dahdi/ap400/apec.h
+new file mode 100644
+index 0000000..483b182
+--- /dev/null
++++ b/drivers/dahdi/ap400/apec.h
 @@ -0,0 +1,48 @@
 +/*
 + * AP400 Echo Cancelation Hardware support
@@ -2935,124 +3074,57 @@
 +void apec_release(struct apec_s *instance);
 +
 +#endif /*_APEC_H_*/
-diff -urN dahdi-svn-orig/drivers/dahdi/ap400/Kbuild dahdi-svn-new/drivers/dahdi/ap400/Kbuild
---- dahdi-svn-orig/drivers/dahdi/ap400/Kbuild	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/ap400/Kbuild	2011-03-07 11:52:51.411050187 +0200
-@@ -0,0 +1,26 @@
-+obj-m += ap400.o
-+
-+EXTRA_CFLAGS := -I$(src)/.. 
-+
-+ap400-objs := ap400_drv.o
-+
-+# APEC_SUPPORT
-+ECHO_FIRMWARE := $(wildcard $(src)/OCT61*.ima)
-+ifneq ($(strip $(ECHO_FIRMWARE)),)
-+	EXTRA_CFLAGS+=-DAPEC_SUPPORT $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
-+	ap400-objs += apec.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x) firmware_oct6104e-64d.o firmware_oct6104e-128d.o
+diff --git a/drivers/dahdi/opvxa1200/Kbuild b/drivers/dahdi/opvxa1200/Kbuild
+new file mode 100644
+index 0000000..8f90819
+--- /dev/null
++++ b/drivers/dahdi/opvxa1200/Kbuild
+@@ -0,0 +1,19 @@
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200) += opvxa1200.o
++
++EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
++
++opvxa1200-objs := base.o
++
++DAHDI_KERNEL_H_NAME:=kernel.h
++DAHDI_KERNEL_H_PATH:=$(DAHDI_INCLUDE)/dahdi/$(DAHDI_KERNEL_H_NAME)
++ifneq ($(DAHDI_KERNEL_H_PATH),)
++        DAHDI_SPAN_MODULE:=$(shell if grep -C 5 "struct dahdi_span {" $(DAHDI_KERNEL_H_PATH) | grep -q "struct module \*owner"; then echo "yes"; else echo "no"; fi)
++        DAHDI_SPAN_OPS:=$(shell if grep -q "struct dahdi_span_ops {" $(DAHDI_KERNEL_H_PATH); then echo "yes"; else echo "no"; fi)
++        ifeq ($(DAHDI_SPAN_MODULE),yes)
++                EXTRA_CFLAGS+=-DDAHDI_SPAN_MODULE
++        else
++                ifeq ($(DAHDI_SPAN_OPS),yes)
++                        EXTRA_CFLAGS+=-DDAHDI_SPAN_OPS
++                endif
++        endif
 +endif
-+
-+$(obj)/apec.o: $(src)/apec.h $(src)/../oct612x/include/oct6100api/oct6100_api.h
-+
-+$(obj)/firmware_oct6104e-64d.o: $(src)/OCT6104E-64D.ima $(obj)/ap400_drv.o $(src)/../firmware/make_firmware_object
-+	@echo Making firmware object file for $(notdir $<)
-+	@cd $(src) && ../firmware/make_firmware_object $(notdir $<) $@ $(obj)/ap400_drv.o
-+
-+$(obj)/firmware_oct6104e-128d.o: $(src)/OCT6104E-128D.ima $(obj)/ap400_drv.o $(src)/../firmware/make_firmware_object
-+	@echo Making firmware object file for $(notdir $<)
-+	@cd $(src) && ../firmware/make_firmware_object $(notdir $<) $@ $(obj)/ap400_drv.o
-+
-+$(src)/../firmware/make_firmware_object:
-+	make -C $(src)/../firmware make_firmware_object
-+
-diff -urN dahdi-svn-orig/drivers/dahdi/Kbuild dahdi-svn-new/drivers/dahdi/Kbuild
---- dahdi-svn-orig/drivers/dahdi/Kbuild	2010-05-17 17:45:12.512409000 +0300
-+++ dahdi-svn-new/drivers/dahdi/Kbuild	2011-03-07 11:52:51.447051323 +0200
-@@ -1,11 +1,18 @@
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI)			+= dahdi.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_AP400)		+= ap400/
- #obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DUMMY)		+= dahdi_dummy.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200)		+= opvxa1200.o
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC)		+= dahdi_dynamic.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCOPENPCI)		+= wcopenpci.o
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_LOC)	+= dahdi_dynamic_loc.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC)		+= zaphfc/
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_ETH)	+= dahdi_dynamic_eth.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_ECHO)			+= ../staging/echo/
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_ETHMF)	+= dahdi_dynamic_ethmf.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_OSLEC)	+= dahdi_echocan_oslec.o
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TRANSCODE)		+= dahdi_transcode.o
- 
-+
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP)		+= wct4xxp/
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP)		+= wctc4xxp/
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP)	+= wctdm24xxp/
-diff -urN dahdi-svn-orig/drivers/dahdi/Kconfig dahdi-svn-new/drivers/dahdi/Kconfig
---- dahdi-svn-orig/drivers/dahdi/Kconfig	2010-02-25 21:10:02.273471000 +0200
-+++ dahdi-svn-new/drivers/dahdi/Kconfig	2011-03-07 11:52:51.443051289 +0200
-@@ -292,3 +292,54 @@
- 	  If unsure, say Y.
- 
- source "drivers/dahdi/xpp/Kconfig"
-+
-+
-+config DAHDI_OPVXA1200
-+	tristate "OpenVox A1200P FXS/FXO Interface"
-+	depends on DAHDI && PCI
-+	default DAHDI
-+	---help---
-+	  This driver provides support for the OpenVox A1200P FXS/FXO Interface.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called opvxa1200.
-+
-+	  If unsure, say Y.
-+
-+config DAHDI_WCOPENPCI
-+	tristate "Voicetronix OpenPCI Interface DAHDI driver"
-+	depends on DAHDI && PCI
-+	default DAHDI
-+	---help---
-+	  This driver provides support for the Voicetronix OpenPCI Interface.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called wcopenpci.
-+
-+	  If unsure, say Y.
-+
-+config DAHDI_ZAPHFC
-+	tristate "HFC-S DAHDI Driver"
-+	depends on DAHDI && PCI
-+	default DAHDI
-+	---help---
-+	  This driver provides DAHDI support for various HFC-S single-port 
-+          ISDN (BRI) cards.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called zaphfc.
-+
-+	  If unsure, say Y.
-+
-+config ECHO
-+	tristate "Line Echo Canceller support"
-+	default DAHDI
-+	--help--
-+	  This driver provides line echo cancelling support for mISDN and
-+	  DAHDI drivers.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called echo.
-+
-+	  If unsure, say Y.
-+
-diff -urN dahdi-svn-orig/drivers/dahdi/opvxa1200.c dahdi-svn-new/drivers/dahdi/opvxa1200.c
---- dahdi-svn-orig/drivers/dahdi/opvxa1200.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/opvxa1200.c	2011-03-07 11:52:51.407062026 +0200
-@@ -0,0 +1,3026 @@
+diff --git a/drivers/dahdi/opvxa1200/Makefile b/drivers/dahdi/opvxa1200/Makefile
+new file mode 100644
+index 0000000..baaab35
+--- /dev/null
++++ b/drivers/dahdi/opvxa1200/Makefile
+@@ -0,0 +1,8 @@
++ifdef 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
++endif
+diff --git a/drivers/dahdi/opvxa1200/base.c b/drivers/dahdi/opvxa1200/base.c
+new file mode 100644
+index 0000000..2ea3cff
+--- /dev/null
++++ b/drivers/dahdi/opvxa1200/base.c
+@@ -0,0 +1,3049 @@
 +/*
 + * OpenVox A1200P FXS/FXO Interface Driver for DAHDI Telephony interface
 + *
-+ * Modify from wctdm.c by MiaoLin<miaolin at openvox.com.cn>
++ * Written by MiaoLin<miaolin at openvox.cn>
++ *
++ * Copyright (C) 2005-2010 OpenVox Communication Co. Ltd,
 + *
 + * All rights reserved.
 + *
@@ -3149,8 +3221,8 @@
 +#include <linux/pci.h>
 +#include <linux/interrupt.h>
 +#include <linux/moduleparam.h>
++#include <asm/io.h>
 +#include <linux/sched.h>
-+#include <asm/io.h>
 +#include "proslic.h"
 +   
 +/* MiaoLin debug start */
@@ -3445,6 +3517,8 @@
 +static unsigned int battalarm;
 +static unsigned int battthresh;
 +static int ringdebounce = DEFAULT_RING_DEBOUNCE;
++/* times 4, because must be a multiple of 4ms: */
++static int dialdebounce = 8 * 8;
 +static int fwringdetect = 0;
 +static int debug = 0;
 +static int robust = 0;
@@ -4346,7 +4420,8 @@
 +	hook = (res & 1);
 +	if (hook != wc->mod[card].fxs.lastrxhook) {
 +		/* Reset the debounce (must be multiple of 4ms) */
-+		wc->mod[card].fxs.debounce = 8 * (4 * 8);
++		wc->mod[card].fxs.debounce = dialdebounce * 4;
++
 +#if 0
 +		printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod[card].fxs.debounce);
 +#endif
@@ -4586,7 +4661,7 @@
 +
 +	while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) {
 +		if ((jiffies - origjiffies) >= (HZ/2))
-+			break;;
++			break;
 +	}
 +
 +	if (vbat < 0x06) {
@@ -5318,7 +5393,8 @@
 +	return 0;
 +}
 +
-+static inline struct wctdm* wctdm_from_span(struct dahdi_span *span) {
++static inline struct wctdm *wctdm_from_span(struct dahdi_span *span)
++{
 +	return container_of(span, struct wctdm, span);
 +}
 +
@@ -5418,14 +5494,16 @@
 +	return 0;
 +}
 +
++#ifdef DAHDI_SPAN_OPS
 +static const struct dahdi_span_ops wctdm_span_ops = {
 +	.owner = THIS_MODULE,
 +	.hooksig = wctdm_hooksig,
 +	.open = wctdm_open,
 +	.close = wctdm_close,
 +	.ioctl = wctdm_ioctl,
-+	.watchdog = wctdm_watchdog
++	.watchdog = wctdm_watchdog,
 +};
++#endif
 +
 +static int wctdm_initialize(struct wctdm *wc)
 +{
@@ -5464,11 +5542,25 @@
 +		wc->chans[x]->chanpos = x+1;
 +		wc->chans[x]->pvt = wc;
 +	}
++
++#ifdef DAHDI_SPAN_MODULE	
++		wc->span.owner = THIS_MODULE;
++#endif
++
++#ifdef DAHDI_SPAN_OPS
++	wc->span.ops = &wctdm_span_ops;
++#else
++		wc->span.hooksig = wctdm_hooksig,
++		wc->span.watchdog = wctdm_watchdog,
++		wc->span.open = wctdm_open;
++		wc->span.close  = wctdm_close;
++		wc->span.ioctl = wctdm_ioctl;
++		wc->span.pvt = wc;
++#endif
 +	wc->span.chans = wc->chans;
 +	wc->span.channels = wc->max_cards;	/*MAX_NUM_CARDS;*/
 +	wc->span.irq = wc->dev->irq;
 +	wc->span.flags = DAHDI_FLAG_RBS;
-+	wc->span.ops = &wctdm_span_ops;
 +	init_waitqueue_head(&wc->span.maintq);
 +
 +	if (dahdi_register(&wc->span, 0)) {
@@ -5939,7 +6031,7 @@
 +	}
 + 
 +	kfree(wc);
-+	printk(KERN_INFO "Freed a OpenVox A1200 card\n");
++	printk(KERN_INFO "Free an OpenVox A1200 card\n");
 +}
 +
 +static void __devexit wctdm_remove_one(struct pci_dev *pdev)
@@ -6054,6 +6146,7 @@
 +module_param(battthresh, uint, 0600);
 +module_param(battalarm, uint, 0600);
 +module_param(ringdebounce, int, 0600);
++module_param(dialdebounce, int, 0600);
 +module_param(fwringdetect, int, 0600);
 +module_param(alawoverride, int, 0600);
 +module_param(fastpickup, int, 0600);
@@ -6075,9 +6168,6180 @@
 +
 +module_init(wctdm_init);
 +module_exit(wctdm_cleanup);
-diff -urN dahdi-svn-orig/drivers/dahdi/wcopenpci.c dahdi-svn-new/drivers/dahdi/wcopenpci.c
---- dahdi-svn-orig/drivers/dahdi/wcopenpci.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/wcopenpci.c	2011-03-07 11:52:51.407062026 +0200
+diff --git a/drivers/dahdi/opvxd115/Kbuild b/drivers/dahdi/opvxd115/Kbuild
+new file mode 100644
+index 0000000..474997d
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/Kbuild
+@@ -0,0 +1,32 @@
++obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115) += opvxd115.o
++
++FIRM_DIR	:= ../firmware
++
++EXTRA_CFLAGS += -I$(src)/.. $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
++
++ifeq ($(HOTPLUG_FIRMWARE),yes)
++  EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
++endif
++
++opvxd115-objs := base.o vpm450m.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x)
++
++DAHDI_KERNEL_H_NAME:=kernel.h
++DAHDI_KERNEL_H_PATH:=$(DAHDI_INCLUDE)/dahdi/$(DAHDI_KERNEL_H_NAME)
++ifneq ($(DAHDI_KERNEL_H_PATH),)
++        DAHDI_SPAN_MODULE:=$(shell if grep -C 5 "struct dahdi_span {" $(DAHDI_KERNEL_H_PATH) | grep -q "struct module \*owner"; then echo "yes"; else echo "no"; fi)
++        DAHDI_SPAN_OPS:=$(shell if grep -q "struct dahdi_span_ops {" $(DAHDI_KERNEL_H_PATH); then echo "yes"; else echo "no"; fi)
++        ifeq ($(DAHDI_SPAN_MODULE),yes)
++                EXTRA_CFLAGS+=-DDAHDI_SPAN_MODULE
++        else
++                ifeq ($(DAHDI_SPAN_OPS),yes)
++                        EXTRA_CFLAGS+=-DDAHDI_SPAN_OPS
++                endif
++        endif
++endif
++
++ifneq ($(HOTPLUG_FIRMWARE),yes)
++opvxd115-objs += $(FIRM_DIR)/dahdi-fw-oct6114-032.o
++endif
++
++$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-032.o: $(obj)/base.o
++	$(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-032.o
+diff --git a/drivers/dahdi/opvxd115/Makefile b/drivers/dahdi/opvxd115/Makefile
+new file mode 100644
+index 0000000..baaab35
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/Makefile
+@@ -0,0 +1,8 @@
++ifdef 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
++endif
+diff --git a/drivers/dahdi/opvxd115/base.c b/drivers/dahdi/opvxd115/base.c
+new file mode 100644
+index 0000000..a434c59
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/base.c
+@@ -0,0 +1,4906 @@
++/*
++ * OpenVox D115P/D115E PCI/PCI-E Driver version 0.1 01/07/2011
++ *
++ * Written by Mark Spencer <markster at digium.com>
++ * Modify from wct4xxp module by mark.liu at openvox.cn
++
++ * Based on previous works, designs, and archetectures conceived and
++ * written by Jim Dixon <jim at lambdatel.com>.
++ *
++ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
++ * Copyright (C) 2001-2010, Digium, Inc.
++ *
++ * All rights reserved.
++ *
++ */
++
++/*
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <asm/io.h>
++#include <linux/version.h>
++#include <linux/delay.h>
++#include <linux/moduleparam.h>
++
++#include <dahdi/kernel.h>
++
++#include "opvxd115.h"
++#include "vpm450m.h"
++
++/* Work queues are a way to better distribute load on SMP systems */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
++/*
++ * Work queues can significantly improve performance and scalability
++ * on multi-processor machines, but requires bypassing some kernel
++ * API's, so it's not guaranteed to be compatible with all kernels.
++ */
++/* #define ENABLE_WORKQUEUES */
++#endif
++
++/* Enable prefetching may help performance */
++#define ENABLE_PREFETCH
++
++/* Support first generation cards? */
++#define SUPPORT_GEN1 
++
++/* Define to get more attention-grabbing but slightly more I/O using
++   alarm status */
++#define FANCY_ALARM
++
++/* Define to support Digium Voice Processing Module expansion card */
++#define VPM_SUPPORT
++
++#define DEBUG_MAIN 		(1 << 0)
++#define DEBUG_DTMF 		(1 << 1)
++#define DEBUG_REGS 		(1 << 2)
++#define DEBUG_TSI  		(1 << 3)
++#define DEBUG_ECHOCAN 	(1 << 4)
++#define DEBUG_RBS 		(1 << 5)
++#define DEBUG_FRAMER		(1 << 6)
++
++/* Maximum latency to be used with Gen 5 */
++#define GEN5_MAX_LATENCY	127
++
++#define T4_BASE_SIZE (DAHDI_MAX_CHUNKSIZE * 32 * 4) 
++
++#ifdef ENABLE_WORKQUEUES
++#include <linux/cpu.h>
++
++/* XXX UGLY!!!! XXX  We have to access the direct structures of the workqueue which
++  are only defined within workqueue.c because they don't give us a routine to allow us
++  to nail a work to a particular thread of the CPU.  Nailing to threads gives us substantially
++  higher scalability in multi-CPU environments though! */
++
++/*
++ * The per-CPU workqueue (if single thread, we always use cpu 0's).
++ *
++ * The sequence counters are for flush_scheduled_work().  It wants to wait
++ * until until all currently-scheduled works are completed, but it doesn't
++ * want to be livelocked by new, incoming ones.  So it waits until
++ * remove_sequence is >= the insert_sequence which pertained when
++ * flush_scheduled_work() was called.
++ */
++ 
++struct cpu_workqueue_struct {
++
++	spinlock_t lock;
++
++	long remove_sequence;	/* Least-recently added (next to run) */
++	long insert_sequence;	/* Next to add */
++
++	struct list_head worklist;
++	wait_queue_head_t more_work;
++	wait_queue_head_t work_done;
++
++	struct workqueue_struct *wq;
++	task_t *thread;
++
++	int run_depth;		/* Detect run_workqueue() recursion depth */
++} ____cacheline_aligned;
++
++/*
++ * The externally visible workqueue abstraction is an array of
++ * per-CPU workqueues:
++ */
++struct workqueue_struct {
++	/* TODO: Find out exactly where the API changed */
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
++	struct cpu_workqueue_struct *cpu_wq;
++#else
++	struct cpu_workqueue_struct cpu_wq[NR_CPUS];
++#endif
++	const char *name;
++	struct list_head list; 	/* Empty if single thread */
++};
++
++/* Preempt must be disabled. */
++static void __t4_queue_work(struct cpu_workqueue_struct *cwq,
++			 struct work_struct *work)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&cwq->lock, flags);
++	work->wq_data = cwq;
++	list_add_tail(&work->entry, &cwq->worklist);
++	cwq->insert_sequence++;
++	wake_up(&cwq->more_work);
++	spin_unlock_irqrestore(&cwq->lock, flags);
++}
++
++/*
++ * Queue work on a workqueue. Return non-zero if it was successfully
++ * added.
++ *
++ * We queue the work to the CPU it was submitted, but there is no
++ * guarantee that it will be processed by that CPU.
++ */
++static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct *work, int cpu)
++{
++	int ret = 0;
++	get_cpu();
++	if (!test_and_set_bit(0, &work->pending)) {
++		BUG_ON(!list_empty(&work->entry));
++		__t4_queue_work(wq->cpu_wq + cpu, work);
++		ret = 1;
++	}
++	put_cpu();
++	return ret;
++}
++
++#endif
++
++/*
++ * Define CONFIG_EXTENDED_RESET to allow the qfalc framer extra time
++ * to reset itself upon hardware initialization. This exits for rare
++ * cases for customers who are seeing the qfalc returning unexpected
++ * information at initialization
++ */
++#undef CONFIG_EXTENDED_RESET
++
++static int pedanticpci = 1;
++static int debug=0;
++static int timingcable = 0;
++static int t1e1override = -1;  /* 0xff for E1, 0x00 for T1 */
++static int j1mode = 0;
++static int sigmode = FRMR_MODE_NO_ADDR_CMP;
++static int alarmdebounce = 2500; /* LOF/LFA def to 2.5s AT&T TR54016*/
++static int losalarmdebounce = 2500;/* LOS def to 2.5s AT&T TR54016*/
++static int aisalarmdebounce = 2500;/* AIS(blue) def to 2.5s AT&T TR54016*/
++static int yelalarmdebounce = 500;/* RAI(yellow) def to 0.5s AT&T devguide */
++static int max_latency = GEN5_MAX_LATENCY;  /* Used to set a maximum latency (if you don't wish it to hard cap it at a certain value) in milliseconds */
++#ifdef VPM_SUPPORT
++static int vpmsupport = 1;
++/* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */
++static int vpmdtmfsupport = -1; /* -1=auto, 0=disabled, 1=enabled*/
++static int vpmspans = 1;
++#define VPM_DEFAULT_DTMFTHRESHOLD 1000
++static int dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
++static int lastdtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
++#endif
++/* Enabling bursting can more efficiently utilize PCI bus bandwidth, but
++   can also cause PCI bus starvation, especially in combination with other
++   aggressive cards.  Please note that burst mode has no effect on CPU
++   utilization / max number of calls / etc. */
++static int noburst;
++/* For 56kbps links, set this module parameter to 0x7f */
++static int hardhdlcmode = 0xff;
++
++static int latency = 1;
++
++static int ms_per_irq = 1;
++
++#ifdef FANCY_ALARM
++static int altab[] = {
++0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, 
++};
++#endif
++
++#define MAX_SPANS 16
++
++#define FLAG_STARTED (1 << 0)
++#define FLAG_NMF (1 << 1)
++#define FLAG_SENDINGYELLOW (1 << 2)
++
++
++#define	TYPE_T1	1		/* is a T1 card */
++#define	TYPE_E1	2		/* is an E1 card */
++#define TYPE_J1 3		/* is a running J1 */
++
++#define FLAG_2NDGEN  (1 << 3)
++#define FLAG_2PORT   (1 << 4)
++#define FLAG_VPM2GEN (1 << 5)
++#define FLAG_OCTOPT  (1 << 6)
++#define FLAG_3RDGEN  (1 << 7)
++#define FLAG_BURST   (1 << 8)
++#define FLAG_EXPRESS (1 << 9)
++#define FLAG_5THGEN  (1 << 10)
++
++#define CANARY 0xc0de
++
++
++#define PORTS_PER_FRAMER 4
++
++struct devtype {
++	char *desc;
++	unsigned int flags;
++};
++
++static struct devtype opvxd115 = { "OpenVox D115P/D115E ", FLAG_2NDGEN};
++static struct devtype opvxd130 = { "OpenVox D130P/D130E", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN};
++	
++
++struct t4;
++
++struct t4_span {
++	struct t4 *owner;
++	unsigned int *writechunk;					/* Double-word aligned write memory */
++	unsigned int *readchunk;					/* Double-word aligned read memory */
++	int spantype;		/* card type, T1 or E1 or J1 */
++	int sync;
++	int psync;
++	int alarmtimer;
++	int redalarms;
++	int notclear;
++	int alarmcount;
++	int losalarmcount;
++	int aisalarmcount;
++	int yelalarmcount;
++	int spanflags;
++	int syncpos;
++#ifdef SUPPORT_GEN1
++	int e1check;			/* E1 check */
++#endif
++	struct dahdi_span span;
++	unsigned char txsigs[16];	/* Transmit sigs */
++	int loopupcnt;
++	int loopdowncnt;
++#ifdef SUPPORT_GEN1
++	unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; /* first EC chunk buffer */
++	unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; /* second EC chunk buffer */
++#endif
++	int irqmisses;
++	
++	/* HDLC controller fields */
++	struct dahdi_chan *sigchan;
++	unsigned char sigmode;
++	int sigactive;
++	int frames_out;
++	int frames_in;
++
++#ifdef VPM_SUPPORT
++	unsigned long dtmfactive;
++	unsigned long dtmfmask;
++	unsigned long dtmfmutemask;
++	short dtmfenergy[31];
++	short dtmfdigit[31];
++#endif
++#ifdef ENABLE_WORKQUEUES
++	struct work_struct swork;
++#endif	
++	struct dahdi_chan *chans[32];		/* Individual channels */
++	struct dahdi_echocan_state *ec[32];	/* Echocan state for each channel */
++};
++
++struct t4 {
++	/* This structure exists one per card */
++	struct pci_dev *dev;		/* Pointer to PCI device */
++	unsigned int intcount;
++	int num;			/* Which card we are */
++	int t1e1;			/* T1/E1 select pins */
++	int globalconfig;	/* Whether global setup has been done */
++	int syncsrc;			/* active sync source */
++	struct t4_span *tspans[4];	/* Individual spans */
++	int numspans;			/* Number of spans on the card */
++	int blinktimer;
++#ifdef FANCY_ALARM
++	int alarmpos;
++#endif
++	int irq;			/* IRQ used by device */
++	int order;			/* Order */
++	int flags;                      /* Device flags */
++	unsigned int falc31 : 1;	/* are we falc v3.1 (atomic not necessary) */
++	int master;				/* Are we master */
++	int ledreg;				/* LED Register */
++	unsigned int gpio;
++	unsigned int gpioctl;
++	int e1recover;			/* E1 recovery timer */
++	spinlock_t reglock;		/* lock register access */
++	int spansstarted;		/* number of spans started */
++	volatile unsigned int *writechunk;					/* Double-word aligned write memory */
++	volatile unsigned int *readchunk;					/* Double-word aligned read memory */
++	unsigned short canary;
++#ifdef ENABLE_WORKQUEUES
++	atomic_t worklist;
++	struct workqueue_struct *workq;
++#endif
++	unsigned int passno;	/* number of interrupt passes */
++	char *variety;
++	int last0;		/* for detecting double-missed IRQ */
++
++	/* DMA related fields */
++	unsigned int dmactrl;
++	dma_addr_t 	readdma;
++	dma_addr_t	writedma;
++	unsigned long memaddr;		/* Base address of card */
++	unsigned long memlen;
++	__iomem volatile unsigned int *membase;	/* Base address of card */
++
++	/* Add this for our softlockup protector */
++	unsigned int oct_rw_count;
++
++	/* Flags for our bottom half */
++	unsigned long checkflag;
++	struct tasklet_struct t4_tlet;
++	unsigned int vpm400checkstatus;
++	/* Latency related additions */
++	unsigned char rxident;
++	unsigned char lastindex;
++	int numbufs;
++	int needed_latency;
++	
++#ifdef VPM_SUPPORT
++	struct vpm450m *vpm450m;
++	int vpm;
++#endif	
++
++};
++
++#define T4_VPM_PRESENT (1 << 28)
++
++#ifdef VPM_SUPPORT
++static void t4_vpm400_init(struct t4 *wc);
++static void t4_vpm450_init(struct t4 *wc);
++static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold);
++
++static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
++
++static const struct dahdi_echocan_features vpm400m_ec_features = {
++	.NLP_automatic = 1,
++	.CED_tx_detect = 1,
++	.CED_rx_detect = 1,
++};
++
++static const struct dahdi_echocan_features vpm450m_ec_features = {
++	.NLP_automatic = 1,
++	.CED_tx_detect = 1,
++	.CED_rx_detect = 1,
++};
++
++static const struct dahdi_echocan_ops vpm400m_ec_ops = {
++	.name = "VPM400M",
++	.echocan_free = echocan_free,
++};
++
++static const struct dahdi_echocan_ops vpm450m_ec_ops = {
++	.name = "VPM450M",
++	.echocan_free = echocan_free,
++};
++#endif
++
++static void __set_clear(struct t4 *wc, int span);
++static int t4_startup(struct dahdi_span *span);
++static int t4_shutdown(struct dahdi_span *span);
++static int t4_rbsbits(struct dahdi_chan *chan, int bits);
++static int t4_maint(struct dahdi_span *span, int cmd);
++static int t4_clear_maint(struct dahdi_span *span);
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++static int t4_reset_counters(struct dahdi_span *span);
++#endif
++#ifdef SUPPORT_GEN1
++static int t4_reset_dma(struct t4 *wc);
++#endif
++static void t4_hdlc_hard_xmit(struct dahdi_chan *chan);
++static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data);
++static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan);
++static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan);
++static void __t4_set_rclk_src(struct t4 *wc, int span);
++static void __t4_set_sclk_src(struct t4 *wc, int mode, int master, int slave);
++static void t4_check_alarms(struct t4 *wc, int span);
++static void t4_check_sigbits(struct t4 *wc, int span);
++
++#define WC_RDADDR	0
++#define WC_WRADDR	1
++#define WC_COUNT	2
++#define WC_DMACTRL	3	
++#define WC_INTR		4
++/* #define WC_GPIO		5 */
++#define WC_VERSION	6
++#define WC_LEDS		7
++#define WC_GPIOCTL	8
++#define WC_GPIO		9
++#define WC_LADDR	10
++#define WC_LDATA		11
++#define WC_LCS		(1 << 11)
++#define WC_LCS2		(1 << 12)
++#define WC_LALE			(1 << 13)
++#define WC_LFRMR_CS	(1 << 10)	/* Framer's ChipSelect signal */
++#define WC_ACTIVATE	(1 << 12)
++#define WC_LREAD			(1 << 15)
++#define WC_LWRITE		(1 << 16)
++
++#define WC_OFF    (0)
++#define WC_RED    (1)
++#define WC_GREEN  (2)
++#define WC_YELLOW (3)
++
++#define WC_RECOVER 	0
++#define WC_SELF 	1
++
++#define LIM0_T 0x36 		/* Line interface mode 0 register */
++#define LIM0_LL (1 << 1)	/* Local Loop */
++#define LIM1_T 0x37		/* Line interface mode 1 register */
++#define LIM1_RL (1 << 1)	/* Remote Loop */
++
++#define FMR0 0x1C		/* Framer Mode Register 0 */
++#define FMR0_SIM (1 << 0)	/* Alarm Simulation */
++#define FMR1_T 0x1D		/* Framer Mode Register 1 */
++#define FMR1_ECM (1 << 2)	/* Error Counter 1sec Interrupt Enable */
++#define DEC_T 0x60		/* Diable Error Counter */
++#define IERR_T 0x1B		/* Single Bit Defect Insertion Register */
++#define IBV	0	 /* Bipolar violation */
++#define IPE	(1 << 1) /* PRBS defect */
++#define ICASE	(1 << 2) /* CAS defect */
++#define ICRCE	(1 << 3) /* CRC defect */
++#define IMFE	(1 << 4) /* Multiframe defect */
++#define IFASE	(1 << 5) /* FAS defect */
++#define ISR3_SEC (1 << 6)	/* Internal one-second interrupt bit mask */
++#define ISR3_ES (1 << 7)	/* Errored Second interrupt bit mask */
++#define ESM 0x47		/* Errored Second mask register */
++
++#define FMR2_T 0x1E		/* Framer Mode Register 2 */
++#define FMR2_PLB (1 << 2)	/* Framer Mode Register 2 */
++
++#define FECL_T 0x50		/* Framing Error Counter Lower Byte */
++#define FECH_T 0x51		/* Framing Error Counter Higher Byte */
++#define CVCL_T 0x52		/* Code Violation Counter Lower Byte */
++#define CVCH_T 0x53		/* Code Violation Counter Higher Byte */
++#define CEC1L_T 0x54		/* CRC Error Counter 1 Lower Byte */
++#define CEC1H_T 0x55		/* CRC Error Counter 1 Higher Byte */
++#define EBCL_T 0x56		/* E-Bit Error Counter Lower Byte */
++#define EBCH_T 0x57		/* E-Bit Error Counter Higher Byte */
++#define BECL_T 0x58		/* Bit Error Counter Lower Byte */
++#define BECH_T 0x59		/* Bit Error Counter Higher Byte */
++#define COEC_T 0x5A		/* COFA Event Counter */
++#define PRBSSTA_T 0xDA		/* PRBS Status Register */
++
++#define LCR1_T 0x3B		/* Loop Code Register 1 */
++#define EPRM (1 << 7)		/* Enable PRBS rx */
++#define XPRBS (1 << 6)		/* Enable PRBS tx */
++#define FLLB (1 << 1)		/* Framed line loop/Invert */
++#define LLBP (1 << 0)		/* Line Loopback Pattern */
++#define TPC0_T 0xA8		/* Test Pattern Control Register */
++#define FRA (1 << 6)		/* Framed/Unframed Selection */
++#define PRBS23 (3 << 4)		/* Pattern selection (23 poly) */
++#define PRM (1 << 2)		/* Non framed mode */
++#define FRS1_T 0x4D		/* Framer Receive Status Reg 1 */
++#define LLBDD (1 << 4)
++#define LLBAD (1 << 3)
++
++#define MAX_T4_CARDS 64
++
++static void t4_isr_bh(unsigned long data);
++
++static struct t4 *cards[MAX_T4_CARDS];
++
++
++#define MAX_TDM_CHAN 32
++#define MAX_DTMF_DET 16
++
++#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF)
++#if 0
++#define HDLC_IMR1_MASK (FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR)
++#else
++#define HDLC_IMR1_MASK	(FRMR_IMR1_XDU | FRMR_IMR1_XPR)
++#endif
++
++static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr)
++{
++	unsigned int res = readl(&wc->membase[addr]);
++	return res;
++}
++
++static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
++{
++	unsigned int tmp;
++	writel(value, &wc->membase[addr]);
++	if (pedanticpci) {
++		tmp = __t4_pci_in(wc, WC_VERSION);
++		if ((tmp & 0xffff0000) != 0xc01a0000)
++			dev_notice(&wc->dev->dev,
++					"Version Synchronization Error!\n");
++	}
++#if 0
++	tmp = __t4_pci_in(wc, addr);
++	if ((value != tmp) && (addr != WC_LEDS) && (addr != WC_LDATA) &&
++		(addr != WC_GPIO) && (addr != WC_INTR))
++		dev_info(&wc->dev->dev, "Tried to load %08x into %08x, "
++				"but got %08x instead\n", value, addr, tmp);
++#endif		
++}
++
++static inline void __t4_gpio_set(struct t4 *wc, unsigned bits, unsigned int val)
++{
++	unsigned int newgpio;
++	newgpio = wc->gpio & (~bits);
++	newgpio |= val;
++	if (newgpio != wc->gpio) {
++		wc->gpio = newgpio;
++		__t4_pci_out(wc, WC_GPIO, wc->gpio);
++	}	
++}
++
++static inline void __t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
++{
++	unsigned int newgpioctl;
++	newgpioctl = wc->gpioctl & (~bits);
++	newgpioctl |= val;
++	if (newgpioctl != wc->gpioctl) {
++		wc->gpioctl = newgpioctl;
++		__t4_pci_out(wc, WC_GPIOCTL, wc->gpioctl);
++	}
++}
++
++static inline void t4_gpio_setdir(struct t4 *wc, unsigned int bits, unsigned int val)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_gpio_setdir(wc, bits, val);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static inline void t4_gpio_set(struct t4 *wc, unsigned int bits, unsigned int val)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_gpio_set(wc, bits, val);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_pci_out(wc, addr, value);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static inline void __t4_set_led(struct t4 *wc, int span, int color)
++{
++	int oldreg = wc->ledreg;
++	wc->ledreg &= ~(0x3 << (span << 1));
++	wc->ledreg |= (color << (span << 1));
++	if (oldreg != wc->ledreg)
++		__t4_pci_out(wc, WC_LEDS, wc->ledreg);
++}
++
++static inline void t4_activate(struct t4 *wc)
++{
++	wc->ledreg |= WC_ACTIVATE;
++	t4_pci_out(wc, WC_LEDS, wc->ledreg);
++}
++
++static inline unsigned int t4_pci_in(struct t4 *wc, const unsigned int addr)
++{
++	unsigned int ret;
++	unsigned long flags;
++	
++	spin_lock_irqsave(&wc->reglock, flags);
++	ret = __t4_pci_in(wc, addr);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	return ret;
++}
++
++static inline unsigned int __t4_framer_in(struct t4 *wc, int unit, const unsigned int addr)
++{
++	unsigned int ret;
++	unit &= 0x3;
++	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LREAD);
++	if (!pedanticpci) {
++		__t4_pci_in(wc, WC_VERSION);
++	} else {
++		__t4_pci_out(wc, WC_VERSION, 0);
++	}
++	ret = __t4_pci_in(wc, WC_LDATA);
++ 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
++
++	if (unlikely(debug & DEBUG_REGS))
++		dev_info(&wc->dev->dev, "Reading unit %d address %02x is "
++				"%02x\n", unit, addr, ret & 0xff);
++
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++
++	return ret & 0xff;
++}
++
++static inline unsigned int t4_framer_in(struct t4 *wc, int unit, const unsigned int addr)
++{
++	unsigned long flags;
++	unsigned int ret;
++	spin_lock_irqsave(&wc->reglock, flags);
++	ret = __t4_framer_in(wc, unit, addr);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	return ret;
++
++}
++
++static inline void __t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
++{
++	unit &= 0x3;
++	if (unlikely(debug & DEBUG_REGS))
++		dev_info(&wc->dev->dev, "Writing %02x to address %02x of "
++				"unit %d\n", value, addr, unit);
++	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
++	__t4_pci_out(wc, WC_LDATA, value);
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LWRITE);
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	if (unlikely(debug & DEBUG_REGS))
++		dev_info(&wc->dev->dev, "Write complete\n");
++#if 0
++	if ((addr != FRMR_TXFIFO) && (addr != FRMR_CMDR) && (addr != 0xbc))
++	{ unsigned int tmp;
++	tmp = __t4_framer_in(wc, unit, addr);
++	if (tmp != value) {
++		dev_notice(&wc->dev->dev, "Expected %d from unit %d "
++				"register %d but got %d instead\n",
++				value, unit, addr, tmp);
++	} }
++#endif	
++}
++
++static inline void t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_framer_out(wc, unit, addr, value);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++#ifdef VPM_SUPPORT
++
++static inline void wait_a_little(void)
++{
++	unsigned long newjiffies=jiffies+2;
++	while(jiffies < newjiffies);
++}
++
++static inline unsigned int __t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr)
++{
++	unsigned int ret;
++	unit &= 0x7;
++	__t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12));
++	__t4_pci_out(wc, WC_LADDR, (addr & 0x1ff) | ( unit << 12) | (1 << 11) | WC_LREAD);
++	ret = __t4_pci_in(wc, WC_LDATA);
++	__t4_pci_out(wc, WC_LADDR, 0);
++	return ret & 0xff;
++}
++
++static inline void __t4_raw_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
++{
++	int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
++	if (!octopt) 
++		__t4_gpio_set(wc, 0xff, (addr >> 8));
++	__t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
++	if (!octopt)
++		__t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
++	__t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	if (!octopt)
++		__t4_gpio_set(wc, 0xff, (value >> 8));
++	__t4_pci_out(wc, WC_LDATA, (value & 0xffff));
++	__t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE | WC_LCS));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	__t4_pci_out(wc, WC_LADDR, (0));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++}
++
++static inline unsigned int __t4_raw_oct_in(struct t4 *wc, const unsigned int addr)
++{
++	unsigned int ret;
++	int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
++	if (!octopt)
++		__t4_gpio_set(wc, 0xff, (addr >> 8));
++	__t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
++	if (!octopt)
++		__t4_pci_out(wc, WC_LADDR, (WC_LWRITE));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	__t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++#ifdef PEDANTIC_OCTASIC_CHECKING 
++	__t4_pci_out(wc, WC_LADDR, (WC_LALE));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++#endif
++	if (!octopt) {
++		__t4_gpio_setdir(wc, 0xff, 0x00);
++		__t4_gpio_set(wc, 0xff, 0x00);
++	}
++	__t4_pci_out(wc, WC_LADDR, (WC_LREAD | WC_LALE | WC_LCS));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	if (octopt) {
++		ret = __t4_pci_in(wc, WC_LDATA) & 0xffff;
++	} else {
++		ret = __t4_pci_in(wc, WC_LDATA) & 0xff;
++		ret |= (__t4_pci_in(wc, WC_GPIO) & 0xff) << 8;
++	}
++	__t4_pci_out(wc, WC_LADDR, (0));
++	if (!pedanticpci)
++		__t4_pci_in(wc, WC_VERSION);
++	if (!octopt)
++		__t4_gpio_setdir(wc, 0xff, 0xff);
++	return ret & 0xffff;
++}
++
++static inline unsigned int __t4_oct_in(struct t4 *wc, unsigned int addr)
++{
++#ifdef PEDANTIC_OCTASIC_CHECKING
++	int count = 1000;
++#endif
++	__t4_raw_oct_out(wc, 0x0008, (addr >> 20));
++	__t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
++	__t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1));
++#ifdef PEDANTIC_OCTASIC_CHECKING
++	while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
++	if (count != 1000)
++		dev_notice(&wc->dev->dev, "Yah, read can be slow...\n");
++	if (!count)
++		dev_notice(&wc->dev->dev, "Read timed out!\n");
++#endif
++	return __t4_raw_oct_in(wc, 0x0004);
++}
++
++static inline unsigned int t4_oct_in(struct t4 *wc, const unsigned int addr)
++{
++	unsigned long flags;
++	unsigned int ret;
++
++	spin_lock_irqsave(&wc->reglock, flags);
++	ret = __t4_oct_in(wc, addr);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	return ret;
++}
++
++static inline unsigned int t4_vpm_in(struct t4 *wc, int unit, const unsigned int addr)
++{
++	unsigned long flags;
++	unsigned int ret;
++	spin_lock_irqsave(&wc->reglock, flags);
++	ret = __t4_vpm_in(wc, unit, addr);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	return ret;
++}
++
++static inline void __t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
++{
++	unit &= 0x7;
++	if (debug & DEBUG_REGS)
++		dev_notice(&wc->dev->dev, "Writing %02x to address %02x of "
++				"ec unit %d\n", value, addr, unit);
++	__t4_pci_out(wc, WC_LADDR, (addr & 0xff));
++	__t4_pci_out(wc, WC_LDATA, value);
++	__t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11));
++	__t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11) | WC_LWRITE);
++	__t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff) | (1 << 11));
++	__t4_pci_out(wc, WC_LADDR, (unit << 12) | (addr & 0x1ff));	
++	__t4_pci_out(wc, WC_LADDR, 0);
++	if (debug & DEBUG_REGS)
++		dev_notice(&wc->dev->dev, "Write complete\n");
++
++      
++#if 0
++	{ unsigned int tmp;
++	tmp = t4_vpm_in(wc, unit, addr);
++	if (tmp != value) {
++		dev_notice(&wc->dev->dev, "Expected %d from unit %d echo "
++				"register %d but got %d instead\n",
++				value, unit, addr, tmp);
++	} }
++#endif
++}
++
++static inline void __t4_oct_out(struct t4 *wc, unsigned int addr, unsigned int value)
++{
++#ifdef PEDANTIC_OCTASIC_CHECKING
++	int count = 1000;
++#endif
++	__t4_raw_oct_out(wc, 0x0008, (addr >> 20));
++	__t4_raw_oct_out(wc, 0x000a, (addr >> 4) & ((1 << 16) - 1));
++	__t4_raw_oct_out(wc, 0x0004, value);
++	__t4_raw_oct_out(wc, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1);
++#ifdef PEDANTIC_OCTASIC_CHECKING
++	while((__t4_raw_oct_in(wc, 0x0000) & (1 << 8)) && --count);
++	if (count != 1000)
++		dev_notice(&wc->dev->dev, "Yah, write can be slow\n");
++	if (!count)
++		dev_notice(&wc->dev->dev, "Write timed out!\n");
++#endif
++}
++
++static inline void t4_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_oct_out(wc, addr, value);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static inline void t4_vpm_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_vpm_out(wc, unit, addr, value);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static const char vpm_digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', '*', '#'};
++
++static void t4_check_vpm450(struct t4 *wc)
++{
++	int channel, tone, start, span;
++
++	if (vpm450m_checkirq(wc->vpm450m)) {
++		while(vpm450m_getdtmf(wc->vpm450m, &channel, &tone, &start)) {
++			span = channel & 0x3;
++			channel >>= 2;
++			if (!wc->t1e1)
++				channel -= 5;
++			else
++				channel -= 1;
++			if (unlikely(debug))
++				dev_info(&wc->dev->dev, "Got tone %s of '%c' "
++					"on channel %d of span %d\n",
++					(start ? "START" : "STOP"),
++					tone, channel, span + 1);
++			if (test_bit(channel, &wc->tspans[span]->dtmfmask) && (tone != 'u')) {
++				if (start) {
++					/* The octasic is supposed to mute us, but...  Yah, you
++					   guessed it.  */
++					if (test_bit(channel, &wc->tspans[span]->dtmfmutemask)) {
++						unsigned long flags;
++						struct dahdi_chan *chan = wc->tspans[span]->span.chans[channel];
++						int y;
++						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], DAHDI_XLAW(0, chan), chan->readidx[y]);
++						}
++						spin_unlock_irqrestore(&chan->lock, flags);
++					}
++					set_bit(channel, &wc->tspans[span]->dtmfactive);
++					dahdi_qevent_lock(wc->tspans[span]->span.chans[channel], (DAHDI_EVENT_DTMFDOWN | tone));
++				} else {
++					clear_bit(channel, &wc->tspans[span]->dtmfactive);
++					dahdi_qevent_lock(wc->tspans[span]->span.chans[channel], (DAHDI_EVENT_DTMFUP | tone));
++				}
++			}
++		}
++	}
++}
++
++static void t4_check_vpm400(struct t4 *wc, unsigned int newio)
++{
++	unsigned int digit, regval = 0;
++	unsigned int regbyte;
++	int x, i;
++	short energy=0;
++	static unsigned int lastio = 0;
++	struct t4_span *ts;
++
++	if (debug && (newio != lastio)) 
++		dev_notice(&wc->dev->dev, "Last was %08x, new is %08x\n",
++				lastio, newio);
++
++	lastio = newio;
++ 
++	for(x = 0; x < 8; x++) {
++		if (newio & (1 << (7 - x)))
++			continue;
++		ts = wc->tspans[x%4];
++		/* Start of DTMF detection process */	
++		regbyte = t4_vpm_in(wc, x, 0xb8);
++		t4_vpm_out(wc, x, 0xb8, regbyte); /* Write 1 to clear */
++		regval = regbyte << 8;
++		regbyte = t4_vpm_in(wc, x, 0xb9);
++		t4_vpm_out(wc, x, 0xb9, regbyte);
++		regval |= regbyte;
++
++		for(i = 0; (i < MAX_DTMF_DET) && regval; i++) {
++			if(regval & 0x0001) {
++				int channel = (i << 1) + (x >> 2);
++				int base = channel - 1;
++
++				if (!wc->t1e1)
++					base -= 4;
++				regbyte = t4_vpm_in(wc, x, 0xa8 + i);
++				digit = vpm_digits[regbyte];
++				if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN)) {
++					energy = t4_vpm_in(wc, x, 0x58 + channel);
++					energy = DAHDI_XLAW(energy, ts->chans[0]);
++					ts->dtmfenergy[base] = energy;
++				}
++				set_bit(base, &ts->dtmfactive);
++				if (ts->dtmfdigit[base]) {
++					if (ts->dtmfmask & (1 << base))
++						dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFUP | ts->dtmfdigit[base]));
++				}
++				ts->dtmfdigit[base] = digit;
++				if (test_bit(base, &ts->dtmfmask))
++					dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFDOWN | digit));
++				if (test_bit(base, &ts->dtmfmutemask)) {
++					/* Mute active receive buffer*/
++					unsigned long flags;
++					struct dahdi_chan *chan = ts->span.chans[base];
++					int y;
++					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], DAHDI_XLAW(0, chan), chan->readidx[y]);
++					}
++					spin_unlock_irqrestore(&chan->lock, flags);
++				}
++				if (debug)
++					dev_notice(&wc->dev->dev, "Digit "
++						"Seen: %d, Span: %d, channel:"
++						" %d, energy: %02x, 'channel "
++						"%d' chip %d\n", digit, x % 4,
++						base + 1, energy, channel, x);
++				
++			}
++			regval = regval >> 1;
++		}
++		if (!(wc->tspans[0]->spanflags & FLAG_VPM2GEN))
++			continue;
++
++		/* Start of DTMF off detection process */	
++		regbyte = t4_vpm_in(wc, x, 0xbc);
++		t4_vpm_out(wc, x, 0xbc, regbyte); /* Write 1 to clear */
++		regval = regbyte << 8;
++		regbyte = t4_vpm_in(wc, x, 0xbd);
++		t4_vpm_out(wc, x, 0xbd, regbyte);
++		regval |= regbyte;
++
++		for(i = 0; (i < MAX_DTMF_DET) && regval; i++) {
++			if(regval & 0x0001) {
++				int channel = (i << 1) + (x >> 2);
++				int base = channel - 1;
++
++				if (!wc->t1e1)
++					base -= 4;
++				clear_bit(base, &ts->dtmfactive);
++				if (ts->dtmfdigit[base]) {
++					if (test_bit(base, &ts->dtmfmask))
++						dahdi_qevent_lock(ts->span.chans[base], (DAHDI_EVENT_DTMFUP | ts->dtmfdigit[base]));
++				}
++				digit = ts->dtmfdigit[base];
++				ts->dtmfdigit[base] = 0;
++				if (debug)
++					dev_notice(&wc->dev->dev, "Digit "
++						"Gone: %d, Span: %d, channel:"
++						" %d, energy: %02x, 'channel "
++						"%d' chip %d\n", digit, x % 4,
++						base + 1, energy, channel, x);
++				
++			}
++			regval = regval >> 1;
++		}
++
++	}
++}
++#endif
++
++static void hdlc_stop(struct t4 *wc, unsigned int span)
++{
++	struct t4_span *t = wc->tspans[span];
++	unsigned char imr0, imr1, mode;
++	int i = 0;
++
++	if (debug & DEBUG_FRAMER)
++		dev_notice(&wc->dev->dev, "Stopping HDLC controller on span "
++				"%d\n", span+1);
++	
++	/* Clear receive and transmit timeslots */
++	for (i = 0; i < 4; i++) {
++		t4_framer_out(wc, span, FRMR_RTR_BASE + i, 0x00);
++		t4_framer_out(wc, span, FRMR_TTR_BASE + i, 0x00);
++	}
++
++	imr0 = t4_framer_in(wc, span, FRMR_IMR0);
++	imr1 = t4_framer_in(wc, span, FRMR_IMR1);
++
++	/* Disable HDLC interrupts */
++	imr0 |= HDLC_IMR0_MASK;
++	t4_framer_out(wc, span, FRMR_IMR0, imr0);
++
++	imr1 |= HDLC_IMR1_MASK;
++	t4_framer_out(wc, span, FRMR_IMR1, imr1);
++
++	mode = t4_framer_in(wc, span, FRMR_MODE);
++	mode &= ~FRMR_MODE_HRAC;
++	t4_framer_out(wc, span, FRMR_MODE, mode);
++
++	t->sigactive = 0;
++}
++
++static inline void __t4_framer_cmd(struct t4 *wc, unsigned int span, int cmd)
++{
++	__t4_framer_out(wc, span, FRMR_CMDR, cmd);
++}
++
++static inline void t4_framer_cmd_wait(struct t4 *wc, unsigned int span, int cmd)
++{
++	int sis;
++	int loops = 0;
++
++	/* XXX could be time consuming XXX */
++	for (;;) {
++		sis = t4_framer_in(wc, span, FRMR_SIS);
++		if (!(sis & 0x04))
++			break;
++		if (!loops++ && (debug & DEBUG_FRAMER)) {
++			dev_notice(&wc->dev->dev, "!!!SIS Waiting before cmd "
++					"%02x\n", cmd);
++		}
++	}
++	if (loops && (debug & DEBUG_FRAMER))
++		dev_notice(&wc->dev->dev, "!!!SIS waited %d loops\n", loops);
++
++	t4_framer_out(wc, span, FRMR_CMDR, cmd);
++}
++
++static int hdlc_start(struct t4 *wc, unsigned int span, struct dahdi_chan *chan, unsigned char mode)
++{
++	struct t4_span *t = wc->tspans[span];
++	unsigned char imr0, imr1;
++	int offset = chan->chanpos;
++	unsigned long flags;
++
++	if (debug & DEBUG_FRAMER)
++		dev_info(&wc->dev->dev, "Starting HDLC controller for channel "
++				"%d span %d\n", offset, span+1);
++
++	if (mode != FRMR_MODE_NO_ADDR_CMP)
++		return -1;
++
++	mode |= FRMR_MODE_HRAC;
++
++	/* Make sure we're in the right mode */
++	t4_framer_out(wc, span, FRMR_MODE, mode);
++	t4_framer_out(wc, span, FRMR_TSEO, 0x00);
++	t4_framer_out(wc, span, FRMR_TSBS1, hardhdlcmode);
++
++	/* Set the interframe gaps, etc */
++	t4_framer_out(wc, span, FRMR_CCR1, FRMR_CCR1_ITF|FRMR_CCR1_EITS);
++
++	t4_framer_out(wc, span, FRMR_CCR2, FRMR_CCR2_RCRC);
++	
++	/* Set up the time slot that we want to tx/rx on */
++	t4_framer_out(wc, span, FRMR_TTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
++	t4_framer_out(wc, span, FRMR_RTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
++
++	imr0 = t4_framer_in(wc, span, FRMR_IMR0);
++	imr1 = t4_framer_in(wc, span, FRMR_IMR1);
++
++	/* Enable our interrupts again */
++	imr0 &= ~HDLC_IMR0_MASK;
++	t4_framer_out(wc, span, FRMR_IMR0, imr0);
++
++	imr1 &= ~HDLC_IMR1_MASK;
++	t4_framer_out(wc, span, FRMR_IMR1, imr1);
++
++	/* Reset the signaling controller */
++	t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
++
++	spin_lock_irqsave(&wc->reglock, flags);
++	t->sigchan = chan;
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	t->sigactive = 0;
++
++	return 0;
++}
++
++static void __set_clear(struct t4 *wc, int span)
++{
++	int i,j;
++	int oldnotclear;
++	unsigned short val=0;
++	struct t4_span *ts = wc->tspans[span];
++
++	oldnotclear = ts->notclear;
++	if ((ts->spantype == TYPE_T1) || (ts->spantype == TYPE_J1)) {
++		for (i=0;i<24;i++) {
++			j = (i/8);
++			if (ts->span.chans[i]->flags & DAHDI_FLAG_CLEAR) {
++				val |= 1 << (7 - (i % 8));
++				ts->notclear &= ~(1 << i);
++			} else
++				ts->notclear |= (1 << i);
++			if ((i % 8)==7) {
++				if (debug)
++					dev_notice(&wc->dev->dev, "Putting %d "
++						"in register %02x on span %d"
++						"\n", val, 0x2f + j, span + 1);
++				__t4_framer_out(wc, span, 0x2f + j, val);
++				val = 0;
++			}
++		}
++	} else {
++		for (i=0;i<31;i++) {
++			if (ts->span.chans[i]->flags & DAHDI_FLAG_CLEAR)
++				ts->notclear &= ~(1 << i);
++			else 
++				ts->notclear |= (1 << i);
++		}
++	}
++	if (ts->notclear != oldnotclear) {
++		unsigned char reg;
++		reg = __t4_framer_in(wc, span, FRMR_IMR0);
++		if (ts->notclear)
++			reg &= ~0x08;
++		else
++			reg |= 0x08;
++		__t4_framer_out(wc, span, FRMR_IMR0, reg);
++	}
++}
++
++#if 0
++static void set_clear(struct t4 *wc, int span)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&wc->reglock, flags);
++	__set_clear(wc, span);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++#endif
++
++static int t4_dacs(struct dahdi_chan *dst, struct dahdi_chan *src)
++{
++	struct t4 *wc;
++	struct t4_span *ts;
++	wc = dst->pvt;
++	ts = wc->tspans[dst->span->offset];
++	if (src && (src->pvt != dst->pvt)) {
++		if (ts->spanflags & FLAG_2NDGEN)
++			t4_tsi_unassign(wc, dst->span->offset, dst->chanpos);
++		wc = src->pvt;
++		if (ts->spanflags & FLAG_2NDGEN)
++			t4_tsi_unassign(wc, src->span->offset, src->chanpos);
++		if (debug)
++			dev_notice(&wc->dev->dev, "Unassigning %d/%d by "
++				"default and...\n", src->span->offset,
++				src->chanpos);
++		if (debug)
++			dev_notice(&wc->dev->dev, "Unassigning %d/%d by "
++				"default\n", dst->span->offset, dst->chanpos);
++		return -1;
++	}
++	if (src) {
++		t4_tsi_assign(wc, src->span->offset, src->chanpos, dst->span->offset, dst->chanpos);
++		if (debug)
++			dev_notice(&wc->dev->dev, "Assigning channel %d/%d -> "
++				"%d/%d!\n", src->span->offset, src->chanpos,
++				dst->span->offset, dst->chanpos);
++	} else {
++		t4_tsi_unassign(wc, dst->span->offset, dst->chanpos);
++		if (debug)
++			dev_notice(&wc->dev->dev, "Unassigning channel %d/%d!"
++				"\n", dst->span->offset, dst->chanpos);
++	}
++	return 0;
++}
++
++#ifdef VPM_SUPPORT
++
++void oct_set_reg(void *data, unsigned int reg, unsigned int val)
++{
++	struct t4 *wc = data;
++	t4_oct_out(wc, reg, val);
++}
++
++unsigned int oct_get_reg(void *data, unsigned int reg)
++{
++	struct t4 *wc = data;
++	unsigned int ret;
++	ret = t4_oct_in(wc, reg);
++	return ret;
++}
++
++static int t4_vpm_unit(int span, int channel)
++{
++	int unit = 0;
++	switch(vpmspans) {
++	case 4:
++		unit = span;
++		unit += (channel & 1) << 2;
++		break;
++	case 2:
++		unit = span;
++		unit += (channel & 0x3) << 1;
++		break;
++	case 1:
++		unit = span;
++		unit += (channel & 0x7);
++	}
++	return unit;
++}
++
++static inline struct t4_span *t4_from_span(struct dahdi_span *span)
++{
++	return container_of(span, struct t4_span, span);
++}
++
++static int t4_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
++			  struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec)
++{
++	struct t4 *wc = chan->pvt;
++	struct t4_span *tspan = container_of(chan->span, struct t4_span, span);
++	int channel;
++	const struct dahdi_echocan_ops *ops;
++	const struct dahdi_echocan_features *features;
++
++	if (!vpmsupport || !wc->vpm)
++		return -ENODEV;
++
++	if (chan->span->offset >= vpmspans)
++		return -ENODEV;
++
++	if (wc->vpm450m) {
++		ops = &vpm450m_ec_ops;
++		features = &vpm450m_ec_features;
++	} else {
++		ops = &vpm400m_ec_ops;
++		features = &vpm400m_ec_features;
++	}
++
++	if (ecp->param_count > 0) {
++		dev_warn(&wc->dev->dev, "%s echo canceller does not support "
++				"parameters; failing request\n", ops->name);
++		return -EINVAL;
++	}
++
++	*ec = tspan->ec[chan->chanpos - 1];
++	(*ec)->ops = ops;
++	(*ec)->features = *features;
++
++	channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4;
++
++	if (wc->vpm450m) {
++		channel = channel << 2;
++		channel |= chan->span->offset;
++		if (debug & DEBUG_ECHOCAN)
++			dev_notice(&wc->dev->dev, "echocan: Card is %d, "
++				"Channel is %d, Span is %d, offset is %d "
++				"length %d\n", wc->num, chan->chanpos,
++				chan->span->offset, channel, ecp->tap_length);
++		vpm450m_setec(wc->vpm450m, channel, ecp->tap_length);
++	} else {
++		int unit = t4_vpm_unit(chan->span->offset, channel);
++
++		if (debug & DEBUG_ECHOCAN)
++			dev_notice(&wc->dev->dev, "echocan: Card is %d, "
++				"Channel is %d, Span is %d, unit is %d, "
++				"unit offset is %d length %d\n", wc->num,
++				chan->chanpos, chan->span->offset, unit,
++				channel, ecp->tap_length);
++		t4_vpm_out(wc, unit, channel, 0x3e);
++	}
++
++	return 0;
++}
++
++static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec)
++{
++	struct t4 *wc = chan->pvt;
++	int channel;
++
++	memset(ec, 0, sizeof(*ec));
++
++	channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4;
++
++	if (wc->vpm450m) {
++		channel = channel << 2;
++		channel |= chan->span->offset;
++		if (debug & DEBUG_ECHOCAN)
++			dev_notice(&wc->dev->dev, "echocan: Card is %d, "
++				"Channel is %d, Span is %d, offset is %d "
++				"length 0\n", wc->num, chan->chanpos,
++				chan->span->offset, channel);
++		vpm450m_setec(wc->vpm450m, channel, 0);
++	} else {
++		int unit = t4_vpm_unit(chan->span->offset, channel);
++
++		if (debug & DEBUG_ECHOCAN)
++			dev_notice(&wc->dev->dev, "echocan: Card is %d, "
++				"Channel is %d, Span is %d, unit is %d, "
++				"unit offset is %d length 0\n", wc->num,
++				chan->chanpos, chan->span->offset, unit,
++				channel);
++		t4_vpm_out(wc, unit, channel, 0x01);
++	}
++}
++#endif
++
++static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data)
++{
++	struct t4_regs regs;
++	int x;
++	struct t4 *wc = chan->pvt;
++#ifdef VPM_SUPPORT
++	int j;
++	int channel;
++	struct t4_span *ts = wc->tspans[chan->span->offset];
++#endif
++
++#ifdef VPM_SUPPORT
++	if (dtmfthreshold == 0)
++		dtmfthreshold = VPM_DEFAULT_DTMFTHRESHOLD;
++	if (lastdtmfthreshold != dtmfthreshold) {
++		lastdtmfthreshold = dtmfthreshold;
++		t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
++	}
++#endif
++
++	switch(cmd) {
++	case WCT4_GET_REGS:
++		for (x=0;x<NUM_PCI;x++)
++			regs.pci[x] = t4_pci_in(wc, x);
++		for (x=0;x<NUM_REGS;x++)
++			regs.regs[x] = t4_framer_in(wc, chan->span->offset, x);
++		if (copy_to_user((__user void *) data, &regs, sizeof(regs)))
++			return -EFAULT;
++		break;
++#ifdef VPM_SUPPORT
++	case DAHDI_TONEDETECT:
++		if (get_user(j, (__user int *) data))
++			return -EFAULT;
++		if (!wc->vpm)
++			return -ENOSYS;
++		if (j && (vpmdtmfsupport == 0))
++			return -ENOSYS;
++		if (j & DAHDI_TONEDETECT_ON)
++			set_bit(chan->chanpos - 1, &ts->dtmfmask);
++		else
++			clear_bit(chan->chanpos - 1, &ts->dtmfmask);
++		if (j & DAHDI_TONEDETECT_MUTE)
++			set_bit(chan->chanpos - 1, &ts->dtmfmutemask);
++		else
++			clear_bit(chan->chanpos - 1, &ts->dtmfmutemask);
++		if (wc->vpm450m) {
++			channel = (chan->chanpos) << 2;
++			if (!wc->t1e1)
++				channel += (4 << 2);
++			channel |= chan->span->offset;
++			vpm450m_setdtmf(wc->vpm450m, channel, j & DAHDI_TONEDETECT_ON, j & DAHDI_TONEDETECT_MUTE);
++		}
++		return 0;
++#endif
++	default:
++		return -ENOTTY;
++	}
++	return 0;
++}
++
++static void inline t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts)
++{
++	int res, i;
++	unsigned int size = 32;
++	unsigned char buf[32];
++
++	res = dahdi_hdlc_getbuf(ts->sigchan, buf, &size);
++	if (debug & DEBUG_FRAMER)
++		dev_notice(&wc->dev->dev, "Got buffer sized %d and res %d "
++				"for %d\n", size, res, span);
++	if (size > 0) {
++		ts->sigactive = 1;
++
++		if (debug & DEBUG_FRAMER) {
++			dev_notice(&wc->dev->dev, "TX(");
++			for (i = 0; i < size; i++)
++				dev_notice(&wc->dev->dev, "%s%02x",
++						(i ? " " : ""), buf[i]);
++			dev_notice(&wc->dev->dev, ")\n");
++		}
++
++		for (i = 0; i < size; i++)
++			t4_framer_out(wc, span, FRMR_TXFIFO, buf[i]);
++
++		if (res) /* End of message */ {
++			if (debug & DEBUG_FRAMER)
++				dev_notice(&wc->dev->dev,
++					"transmiting XHF|XME\n");
++			t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF | FRMR_CMDR_XME);
++#if 0
++			ts->sigactive = (__t4_framer_in(wc, span, FRMR_SIS) & FRMR_SIS_XFW) ? 0 : 1;
++#endif
++			++ts->frames_out;
++			if ((debug & DEBUG_FRAMER) && !(ts->frames_out & 0x0f))
++				dev_notice(&wc->dev->dev, "Transmitted %d "
++					"frames on span %d\n", ts->frames_out,
++					span);
++		} else { /* Still more to transmit */
++			if (debug & DEBUG_FRAMER)
++				dev_notice(&wc->dev->dev, "transmiting XHF\n");
++			t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF);
++		}
++	}
++	else if (res < 0)
++		ts->sigactive = 0;
++}
++
++static void t4_hdlc_hard_xmit(struct dahdi_chan *chan)
++{
++	struct t4 *wc = chan->pvt;
++	int span = chan->span->offset;
++	struct t4_span *ts = wc->tspans[span];
++	unsigned long flags; 
++
++	spin_lock_irqsave(&wc->reglock, flags);
++	if (!ts->sigchan) {
++		dev_notice(&wc->dev->dev, "t4_hdlc_hard_xmit: Invalid (NULL) "
++				"signalling channel\n");
++		spin_unlock_irqrestore(&wc->reglock, flags);
++		return;
++	}
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	if (debug & DEBUG_FRAMER)
++		dev_notice(&wc->dev->dev, "t4_hdlc_hard_xmit on channel %s "
++				"(sigchan %s), sigactive=%d\n", chan->name,
++				ts->sigchan->name, ts->sigactive);
++
++	if ((ts->sigchan == chan) && !ts->sigactive)
++		t4_hdlc_xmit_fifo(wc, span, ts);
++}
++
++static int t4_maint(struct dahdi_span *span, int cmd)
++{
++	struct t4_span *ts = t4_from_span(span);
++	struct t4 *wc = ts->owner;
++	unsigned int reg;
++#ifdef DAHDI_SPAN_OPS
++	unsigned long flags;
++#endif
++
++	if (ts->spantype == TYPE_E1) {
++		switch(cmd) {
++		case DAHDI_MAINT_NONE:
++			dev_info(&wc->dev->dev, "Clearing all maint modes\n");
++			t4_clear_maint(span);
++			break;
++		case DAHDI_MAINT_LOCALLOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on local loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, LIM0_T);
++			t4_framer_out(wc, span->offset, LIM0_T, (reg|LIM0_LL));
++			break;
++#ifdef DAHDI_SPAN_OPS
++		case DAHDI_MAINT_NETWORKLINELOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on network line loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, LIM1_T);
++			t4_framer_out(wc, span->offset, LIM1_T, (reg|LIM1_RL));
++			break;
++		case DAHDI_MAINT_NETWORKPAYLOADLOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on network payload loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, FMR2_T);
++			t4_framer_out(wc, span->offset, FMR2_T, (reg|FMR2_PLB));
++			break;
++#endif
++		case DAHDI_MAINT_LOOPUP:
++		case DAHDI_MAINT_LOOPDOWN:
++		case DAHDI_MAINT_LOOPSTOP:
++			dev_info(&wc->dev->dev,
++				"Loopup & loopdown supported in E1 mode\n");
++			return -ENOSYS;
++#ifdef DAHDI_SPAN_OPS
++		case DAHDI_MAINT_FAS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IFASE);
++			break;
++		case DAHDI_MAINT_MULTI_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IMFE);
++			break;
++		case DAHDI_MAINT_CRC_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, ICRCE);
++			break;
++		case DAHDI_MAINT_CAS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, ICASE);
++			break;
++		case DAHDI_MAINT_PRBS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IPE);
++			break;
++		case DAHDI_MAINT_BIPOLAR_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IBV);
++			break;
++		case DAHDI_RESET_COUNTERS:
++			t4_reset_counters(span);
++			break;
++		case DAHDI_MAINT_ALARM_SIM:
++			dev_info(&wc->dev->dev, "Invoking alarm state");
++			reg = t4_framer_in(wc, span->offset, FMR0);
++			t4_framer_out(wc, span->offset, FMR0, (reg|FMR0_SIM));
++			break;
++#endif
++		default:
++			dev_info(&wc->dev->dev,
++					"Unknown E1 maint command: %d\n", cmd);
++			return -ENOSYS;
++		}
++	} else {
++		switch(cmd) {
++		case DAHDI_MAINT_NONE:
++			dev_info(&wc->dev->dev, "Clearing all maint modes\n");
++			t4_clear_maint(span);
++			break;
++		case DAHDI_MAINT_LOCALLOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on local loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, LIM0_T);
++			t4_framer_out(wc, span->offset, LIM0_T, (reg|LIM0_LL));
++			break;
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++		case DAHDI_MAINT_NETWORKLINELOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on network line loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, LIM1_T);
++			t4_framer_out(wc, span->offset, LIM1_T, (reg|LIM1_RL));
++			break;
++		case DAHDI_MAINT_NETWORKPAYLOADLOOP:
++			dev_info(&wc->dev->dev,
++				 "Turning on network payload loopback\n");
++			t4_clear_maint(span);
++			reg = t4_framer_in(wc, span->offset, FMR2_T);
++			t4_framer_out(wc, span->offset, FMR2_T, (reg|FMR2_PLB));
++			break;
++#endif
++		case DAHDI_MAINT_LOOPUP:
++			dev_info(&wc->dev->dev, "Transmitting loopup code\n");
++			t4_clear_maint(span);
++			t4_framer_out(wc, span->offset, 0x21, 0x50);
++			break;
++		case DAHDI_MAINT_LOOPDOWN:
++			dev_info(&wc->dev->dev, "Transmitting loopdown code\n");
++			t4_clear_maint(span);
++			t4_framer_out(wc, span->offset, 0x21, 0x60);
++			break;
++		case DAHDI_MAINT_LOOPSTOP:
++			dev_info(&wc->dev->dev, "Transmitting loopstop code\n");
++			t4_clear_maint(span);
++			t4_framer_out(wc, span->offset, 0x21, 0x40);
++			break;
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++		case DAHDI_MAINT_FAS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IFASE);
++			break;
++		case DAHDI_MAINT_MULTI_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IMFE);
++			break;
++		case DAHDI_MAINT_CRC_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, ICRCE);
++			break;
++		case DAHDI_MAINT_CAS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, ICASE);
++			break;
++		case DAHDI_MAINT_PRBS_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IPE);
++			break;
++		case DAHDI_MAINT_BIPOLAR_DEFECT:
++			t4_framer_out(wc, span->offset, IERR_T, IBV);
++			break;
++		case DAHDI_MAINT_PRBS:
++			dev_info(&wc->dev->dev, "PRBS not supported\n");
++#if 0
++			dev_notice(&wc->dev->dev, "Enabling PRBS!\n");
++			span->mainttimer = 1;
++			/* Enable PRBS monitor */
++			reg = t4_framer_in(wc, span->offset, LCR1_T);
++			reg |= EPRM;
++
++			/* Setup PRBS xmit */
++			t4_framer_out(wc, span->offset, TPC0_T, 0);
++
++			/* Enable PRBS transmit */
++			reg |= XPRBS;
++			reg &= ~LLBP;
++			reg &= ~FLLB;
++			t4_framer_out(wc, span->offset, LCR1_T, reg);
++#endif
++			return -ENOSYS;
++		case DAHDI_RESET_COUNTERS:
++			t4_reset_counters(span);
++			break;
++#endif
++#ifdef DAHDI_SPAN_OPS
++		case DAHDI_MAINT_ALARM_SIM:
++			reg = t4_framer_in(wc, span->offset, FMR0);
++
++			/*
++			 * The alarm simulation state machine requires us to
++			 * bring this bit up and down for at least 1 clock cycle
++			 */
++			spin_lock_irqsave(&wc->reglock, flags);
++			__t4_framer_out(wc, span->offset,
++					FMR0, (reg | FMR0_SIM));
++			udelay(1);
++			__t4_framer_out(wc, span->offset,
++					FMR0, (reg & ~FMR0_SIM));
++			udelay(1);
++			spin_unlock_irqrestore(&wc->reglock, flags);
++
++			reg = t4_framer_in(wc, span->offset, 0x4e);
++			if (debug & DEBUG_MAIN) {
++				dev_info(&wc->dev->dev,
++					"FRS2(alarm state): %d\n",
++					((reg & 0xe0) >> 5));
++			}
++			break;
++#endif
++		default:
++			dev_info(&wc->dev->dev, "Unknown T1 maint command:%d\n",
++									cmd);
++			break;
++	   }
++    }
++	return 0;
++}
++
++static int t4_clear_maint(struct dahdi_span *span)
++{
++	struct t4_span *ts = t4_from_span(span);
++	struct t4 *wc = ts->owner;
++	unsigned int reg;
++
++	/* Clear local loop */
++	reg = t4_framer_in(wc, span->offset, LIM0_T);
++	t4_framer_out(wc, span->offset, LIM0_T, (reg & ~LIM0_LL));
++
++	/* Clear Remote Loop */
++	reg = t4_framer_in(wc, span->offset, LIM1_T);
++	t4_framer_out(wc, span->offset, LIM1_T, (reg & ~LIM1_RL));
++
++	/* Clear Remote Payload Loop */
++	reg = t4_framer_in(wc, span->offset, FMR2_T);
++	t4_framer_out(wc, span->offset, FMR2_T, (reg & ~FMR2_PLB));
++
++	/* Clear PRBS */
++	reg = t4_framer_in(wc, span->offset, LCR1_T);
++	t4_framer_out(wc, span->offset, LCR1_T, (reg & ~(XPRBS | EPRM)));
++
++	span->mainttimer = 0;
++
++	return 0;
++}
++
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++static int t4_reset_counters(struct dahdi_span *span)
++{
++	struct t4_span *ts = t4_from_span(span);
++	memset(&ts->span.count, 0, sizeof(ts->span.count));
++	return 0;
++}
++#endif
++
++static int t4_rbsbits(struct dahdi_chan *chan, int bits)
++{
++	u_char m,c;
++	int k,n,b;
++	struct t4 *wc = chan->pvt;
++	struct t4_span *ts = wc->tspans[chan->span->offset];
++	unsigned long flags;
++	
++	if (debug & DEBUG_RBS)
++		dev_notice(&wc->dev->dev, "Setting bits to %d on channel %s\n",
++				bits, chan->name);
++	spin_lock_irqsave(&wc->reglock, flags);	
++	k = chan->span->offset;
++	if (ts->spantype == TYPE_E1) { /* do it E1 way */
++		if (chan->chanpos == 16) {
++			spin_unlock_irqrestore(&wc->reglock, flags);
++			return 0;
++		}
++		n = chan->chanpos - 1;
++		if (chan->chanpos > 15) n--;
++		b = (n % 15);
++		c = ts->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 */
++		ts->txsigs[b] = c;
++		  /* output them to the chip */
++		__t4_framer_out(wc,k,0x71 + b,c); 
++	} else if (ts->span.lineconfig & DAHDI_CONFIG_D4) {
++		n = chan->chanpos - 1;
++		b = (n/4);
++		c = ts->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 */
++		ts->txsigs[b] = c;
++		  /* output them to the chip */
++		__t4_framer_out(wc,k,0x70 + b,c); 
++		__t4_framer_out(wc,k,0x70 + b + 6,c); 
++	} else if (ts->span.lineconfig & DAHDI_CONFIG_ESF) {
++		n = chan->chanpos - 1;
++		b = (n/2);
++		c = ts->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 */
++		ts->txsigs[b] = c;
++		  /* output them to the chip */
++		__t4_framer_out(wc,k,0x70 + b,c); 
++	} 
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	if (debug & DEBUG_RBS)
++		dev_notice(&wc->dev->dev, "Finished setting RBS bits\n");
++	return 0;
++}
++
++static int t4_shutdown(struct dahdi_span *span)
++{
++	int tspan;
++	int wasrunning;
++	unsigned long flags;
++	struct t4_span *ts = t4_from_span(span);
++	struct t4 *wc = ts->owner;
++
++	tspan = span->offset + 1;
++	if (tspan < 0) {
++		dev_notice(&wc->dev->dev, "opvxd115: Span '%d' isn't us?\n",
++				span->spanno);
++		return -1;
++	}
++
++	if (debug & DEBUG_MAIN)
++		dev_notice(&wc->dev->dev, "Shutting down span %d (%s)\n",
++				span->spanno, span->name);
++
++	/* Stop HDLC controller if runned */
++	if (ts->sigchan)
++		hdlc_stop(wc, span->offset);
++	
++	spin_lock_irqsave(&wc->reglock, flags);
++	wasrunning = span->flags & DAHDI_FLAG_RUNNING;
++
++	span->flags &= ~DAHDI_FLAG_RUNNING;
++	__t4_set_led(wc, span->offset, WC_OFF);
++	if ((wc->numspans == 1) && 
++	    (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING))) {
++		/* No longer in use, disable interrupts */
++		dev_info(&wc->dev->dev, "opvxd115: Disabling interrupts since "
++				"there are no active spans\n");
++		set_bit(T4_STOP_DMA, &wc->checkflag);
++	} else
++		set_bit(T4_CHECK_TIMING, &wc->checkflag);
++
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	/* Wait for interrupt routine to shut itself down */
++	msleep(10);
++	if (wasrunning)
++		wc->spansstarted--;
++
++	if (debug & DEBUG_MAIN)
++		dev_notice(&wc->dev->dev, "Span %d (%s) shutdown\n",
++				span->spanno, span->name);
++	return 0;
++}
++
++static void t4_chan_set_sigcap(struct dahdi_span *span, int x)
++{
++	struct t4_span *wc = container_of(span, struct t4_span, span);
++	struct dahdi_chan *chan = wc->chans[x];
++	chan->sigcap = DAHDI_SIG_CLEAR;
++	/* E&M variant supported depends on span type */
++	if (wc->spantype == TYPE_E1) {
++		/* E1 sigcap setup */
++		if (span->lineconfig & DAHDI_CONFIG_CCS) {
++			/* CCS setup */
++			chan->sigcap |= DAHDI_SIG_MTP2 | DAHDI_SIG_SF |
++				DAHDI_SIG_HARDHDLC;
++			return;
++		}
++		/* clear out sig and sigcap for channel 16 on E1 CAS
++		 * lines, otherwise, set it correctly */
++		if (x == 15) {
++			/* CAS signaling channel setup */
++			wc->chans[15]->sigcap = 0;
++			wc->chans[15]->sig = 0;
++			return;
++		}
++		/* normal CAS setup */
++		chan->sigcap |= DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS |
++			DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_SF |
++			DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS |
++			DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS;
++	} else {
++		/* T1 sigcap setup */
++		chan->sigcap |= DAHDI_SIG_EM | DAHDI_SIG_FXSLS |
++			DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS | DAHDI_SIG_MTP2 |
++			DAHDI_SIG_SF | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS |
++			DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_DACS_RBS |
++			DAHDI_SIG_HARDHDLC;
++	}
++}
++
++static int t4_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc)
++{
++	int i;
++	struct t4_span *ts = t4_from_span(span);
++	struct t4 *wc = ts->owner;
++
++	if (debug)
++		dev_info(&wc->dev->dev, "About to enter spanconfig!\n");
++	if (debug & DEBUG_MAIN)
++		dev_notice(&wc->dev->dev, "opvxd115: Configuring span %d\n",
++				span->spanno);
++
++	if (lc->sync < 0)
++		lc->sync = 0;
++	if (lc->sync > wc->numspans)
++		lc->sync = 0;
++	
++	/* remove this span number from the current sync sources, if there */
++	for(i = 0; i < wc->numspans; i++) {
++		if (wc->tspans[i]->sync == span->spanno) {
++			wc->tspans[i]->sync = 0;
++			wc->tspans[i]->psync = 0;
++		}
++	}
++	wc->tspans[span->offset]->syncpos = lc->sync;
++	/* if a sync src, put it in proper place */
++	if (lc->sync) {
++		wc->tspans[lc->sync - 1]->sync = span->spanno;
++		wc->tspans[lc->sync - 1]->psync = span->offset + 1;
++	}
++	set_bit(T4_CHECK_TIMING, &wc->checkflag);
++
++	/* Make sure this is clear in case of multiple startup and shutdown
++	 * iterations */
++	clear_bit(T4_STOP_DMA, &wc->checkflag);
++	
++	/* make sure that sigcaps gets updated if necessary */
++	for (i = 0; i < span->channels; i++)
++		t4_chan_set_sigcap(span, i);
++
++	/* If we're already running, then go ahead and apply the changes */
++	if (span->flags & DAHDI_FLAG_RUNNING)
++		return t4_startup(span);
++
++	if (debug)
++		dev_info(&wc->dev->dev, "Done with spanconfig!\n");
++	return 0;
++}
++
++static int t4_chanconfig(struct dahdi_chan *chan, int sigtype)
++{
++	int alreadyrunning;
++	unsigned long flags;
++	struct t4 *wc = chan->pvt;
++	struct t4_span *ts = wc->tspans[chan->span->offset];
++
++	alreadyrunning = ts->span.flags & DAHDI_FLAG_RUNNING;
++	if (debug & DEBUG_MAIN) {
++		if (alreadyrunning)
++			dev_notice(&wc->dev->dev, "opvxd115: Reconfigured "
++				"channel %d (%s) sigtype %d\n",
++				chan->channo, chan->name, sigtype);
++		else
++			dev_notice(&wc->dev->dev, "opvxd115: Configured channel"
++				" %d (%s) sigtype %d\n",
++				chan->channo, chan->name, sigtype);
++	}
++
++	spin_lock_irqsave(&wc->reglock, flags);	
++
++	if (alreadyrunning)
++		__set_clear(wc, chan->span->offset);
++
++	spin_unlock_irqrestore(&wc->reglock, flags);	
++
++	/* (re)configure signalling channel */
++	if ((sigtype == DAHDI_SIG_HARDHDLC) || (ts->sigchan == chan)) {
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "%sonfiguring hardware HDLC "
++				"on %s\n",
++				((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : "Unc"),
++				chan->name);
++		if (alreadyrunning) {
++			if (ts->sigchan)
++				hdlc_stop(wc, ts->sigchan->span->offset);
++			if (sigtype == DAHDI_SIG_HARDHDLC) {
++				if (hdlc_start(wc, chan->span->offset, chan, ts->sigmode)) {
++					dev_notice(&wc->dev->dev, "Error "
++						"initializing signalling "
++						"controller\n");
++					return -1;
++				}
++			} else {
++				spin_lock_irqsave(&wc->reglock, flags);
++				ts->sigchan = NULL;
++				spin_unlock_irqrestore(&wc->reglock, flags);
++			}
++		
++		}
++		else {
++			spin_lock_irqsave(&wc->reglock, flags);
++			ts->sigchan = (sigtype == DAHDI_SIG_HARDHDLC) ? chan : NULL;
++			spin_unlock_irqrestore(&wc->reglock, flags);
++			ts->sigactive = 0;
++		}
++	}
++	return 0;
++}
++
++static int t4_open(struct dahdi_chan *chan)
++{
++	return 0;
++}
++
++static int t4_close(struct dahdi_chan *chan)
++{
++	return 0;
++}
++
++static void set_span_devicetype(struct t4 *wc)
++{
++	int x;
++	struct t4_span *ts;
++
++	for (x = 0; x < wc->numspans; x++) {
++		ts = wc->tspans[x];
++		dahdi_copy_string(ts->span.devicetype, wc->variety, sizeof(ts->span.devicetype));
++		if (wc->vpm == T4_VPM_PRESENT) {
++			if (!wc->vpm450m)
++				strncat(ts->span.devicetype, " (VPM400M)", sizeof(ts->span.devicetype) - 1);
++			else
++				strncat(ts->span.devicetype, " (VPMOCT032)",
++					sizeof(ts->span.devicetype) - 1);
++		}
++	}
++}
++
++/* The number of cards we have seen with each
++   possible 'order' switch setting.
++*/
++static unsigned int order_index[16];
++
++static void setup_chunks(struct t4 *wc, int which)
++{
++	struct t4_span *ts;
++	int offset = 1;
++	int x, y;
++	int gen2;
++
++	if (!wc->t1e1)
++		offset += 4;
++
++	gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN);
++
++	for (x = 0; x < wc->numspans; x++) {
++		ts = wc->tspans[x];
++		ts->writechunk = (void *)(wc->writechunk + (x * 32 * 2) + (which * (1024 >> 2)));
++		ts->readchunk = (void *)(wc->readchunk + (x * 32 * 2) + (which * (1024 >> 2)));
++		for (y=0;y<wc->tspans[x]->span.channels;y++) {
++			struct dahdi_chan *mychans = ts->chans[y];
++			if (gen2) {
++				mychans->writechunk = (void *)(wc->writechunk + ((x * 32 + y + offset) * 2) + (which * (1024 >> 2)));
++				mychans->readchunk = (void *)(wc->readchunk + ((x * 32 + y + offset) * 2) + (which * (1024 >> 2)));
++			}
++		}
++	}
++}
++
++#ifdef DAHDI_SPAN_OPS
++static const struct dahdi_span_ops t4_gen1_span_ops = {
++	.owner = THIS_MODULE,
++	.spanconfig = t4_spanconfig,
++	.chanconfig = t4_chanconfig,
++	.startup = t4_startup,
++	.shutdown = t4_shutdown,
++	.rbsbits = t4_rbsbits,
++	.maint = t4_maint,
++	.open = t4_open,
++	.close  = t4_close,
++	.ioctl = t4_ioctl,
++	.hdlc_hard_xmit = t4_hdlc_hard_xmit,
++};
++
++static const struct dahdi_span_ops t4_gen2_span_ops = {
++	.owner = THIS_MODULE,
++	.spanconfig = t4_spanconfig,
++	.chanconfig = t4_chanconfig,
++	.startup = t4_startup,
++	.shutdown = t4_shutdown,
++	.rbsbits = t4_rbsbits,
++	.maint = t4_maint,
++	.open = t4_open,
++	.close  = t4_close,
++	.ioctl = t4_ioctl,
++	.hdlc_hard_xmit = t4_hdlc_hard_xmit,
++	.dacs = t4_dacs,
++#ifdef VPM_SUPPORT
++	.echocan_create = t4_echocan_create,
++#endif
++};
++#endif
++
++static void init_spans(struct t4 *wc)
++{
++	int x,y;
++	int gen2;
++	struct t4_span *ts;
++	unsigned int reg;
++	
++	gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN);
++	for (x = 0; x < wc->numspans; x++) {
++		ts = wc->tspans[x];
++		sprintf(ts->span.name, "D115/D130/%d/%d", wc->num, x + 1);
++		snprintf(ts->span.desc, sizeof(ts->span.desc) - 1,
++			 "D115/D130 (E1|T1) Card %d Span %d", wc->num, x+1);
++		ts->span.manufacturer = "OpenVox";
++		if (order_index[wc->order] == 1)
++			snprintf(ts->span.location, sizeof(ts->span.location) - 1, "Board ID Switch %d", wc->order);
++		else
++			snprintf(ts->span.location, sizeof(ts->span.location) - 1,
++				 "PCI%s Bus %02d Slot %02d", (ts->spanflags & FLAG_EXPRESS) ? " Express" : " ",
++				 wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
++		switch (ts->spantype) {
++		case TYPE_T1:
++			ts->span.spantype = "T1";
++			break;
++		case TYPE_E1:
++			ts->span.spantype = "E1";
++			break;
++		case TYPE_J1:
++			ts->span.spantype = "J1";
++			break;
++		}
++#ifdef DAHDI_SPAN_MODULE	
++		ts->span.owner = THIS_MODULE;
++#endif
++#ifdef DAHDI_SPAN_OPS
++		if (gen2) {
++			ts->span.ops = &t4_gen2_span_ops;
++		} else {
++			ts->span.ops = &t4_gen1_span_ops;
++		}
++#else
++		ts->span.spanconfig = t4_spanconfig;
++		ts->span.chanconfig = t4_chanconfig;
++		ts->span.startup = t4_startup;
++		ts->span.shutdown = t4_shutdown;
++		ts->span.rbsbits = t4_rbsbits;
++		ts->span.maint = t4_maint;
++		ts->span.open = t4_open;
++		ts->span.close  = t4_close;
++		ts->span.ioctl = t4_ioctl;
++		ts->span.hdlc_hard_xmit = t4_hdlc_hard_xmit;
++		if (gen2) {
++#ifdef VPM_SUPPORT
++		if (vpmsupport)
++			ts->span.echocan_create = t4_echocan_create;
++#endif			
++			ts->span.dacs = t4_dacs;
++		}
++		ts->span.pvt = ts;
++#endif
++		ts->span.irq = wc->dev->irq;
++
++		/* HDLC Specific init */
++		ts->sigchan = NULL;
++		ts->sigmode = sigmode;
++		ts->sigactive = 0;
++		
++		if (ts->spantype == TYPE_T1 || ts->spantype == TYPE_J1) {
++			ts->span.channels = 24;
++			ts->span.deflaw = DAHDI_LAW_MULAW;
++			ts->span.linecompat = DAHDI_CONFIG_AMI |
++				DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 |
++				DAHDI_CONFIG_ESF;
++		} else {
++			ts->span.channels = 31;
++			ts->span.deflaw = DAHDI_LAW_ALAW;
++			ts->span.linecompat = DAHDI_CONFIG_AMI |
++				DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS |
++				DAHDI_CONFIG_CRC4;
++		}
++		ts->span.chans = ts->chans;
++		ts->span.flags = DAHDI_FLAG_RBS;
++
++		ts->owner = wc;
++		ts->span.offset = x;
++		ts->writechunk = (void *)(wc->writechunk + x * 32 * 2);
++		ts->readchunk = (void *)(wc->readchunk + x * 32 * 2);
++		init_waitqueue_head(&ts->span.maintq);
++
++		for (y=0;y<wc->tspans[x]->span.channels;y++) {
++			struct dahdi_chan *mychans = ts->chans[y];
++			sprintf(mychans->name, "D115/D130/%d/%d/%d", wc->num, x + 1, y + 1);
++			t4_chan_set_sigcap(&ts->span, x);
++			mychans->pvt = wc;
++			mychans->chanpos = y + 1;
++		}
++
++		/* Enable 1sec timer interrupt */
++		reg = t4_framer_in(wc, x, FMR1_T);
++		t4_framer_out(wc, x, FMR1_T, (reg | FMR1_ECM));
++
++		/* Enable Errored Second interrupt */
++		t4_framer_out(wc, x, ESM, 0);
++
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++		t4_reset_counters(&ts->span);
++#endif
++	}
++
++	set_span_devicetype(wc);
++	setup_chunks(wc, 0);
++	wc->lastindex = 0;
++}
++
++static void t4_serial_setup(struct t4 *wc, int unit)
++{
++	if (!wc->globalconfig) {
++		wc->globalconfig = 1;
++		if (debug)
++			dev_info(&wc->dev->dev, "opvxd115: Setting up global "
++					"serial parameters\n");
++		t4_framer_out(wc, 0, 0x85, 0xe0);	/* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
++		t4_framer_out(wc, 0, 0x08, 0x01);	/* IPC: Interrupt push/pull active low */
++	
++		/* Global clocks (8.192 Mhz CLK) */
++		t4_framer_out(wc, 0, 0x92, 0x00);	
++		t4_framer_out(wc, 0, 0x93, 0x18);
++		t4_framer_out(wc, 0, 0x94, 0xfb);
++		t4_framer_out(wc, 0, 0x95, 0x0b);
++		t4_framer_out(wc, 0, 0x96, 0x00);
++		t4_framer_out(wc, 0, 0x97, 0x0b);
++		t4_framer_out(wc, 0, 0x98, 0xdb);
++		t4_framer_out(wc, 0, 0x99, 0xdf);
++	}
++
++	/* Configure interrupts */	
++	t4_framer_out(wc, unit, FRMR_GCR, 0x00);	/* GCR: Interrupt on Activation/Deactivation of each */
++
++	/* Configure system interface */
++	t4_framer_out(wc, unit, FRMR_SIC1, 0xc2);	/* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
++	t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); /* SIC2: No FFS, no center receive eliastic buffer, phase */
++	t4_framer_out(wc, unit, FRMR_SIC3, 0x04);	/* SIC3: Edges for capture */
++	t4_framer_out(wc, unit, FRMR_CMR2, 0x00);	/* CMR2: We provide sync and clock for tx and rx. */
++	if (!wc->t1e1) { /* T1 mode */
++		t4_framer_out(wc, unit, FRMR_XC0, 0x03);	/* XC0: Normal operation of Sa-bits */
++		t4_framer_out(wc, unit, FRMR_XC1, 0x84);	/* XC1: 0 offset */
++		if (wc->tspans[unit]->spantype == TYPE_J1)
++			t4_framer_out(wc, unit, FRMR_RC0, 0x83);	/* RC0: Just shy of 1023 */
++		else
++			t4_framer_out(wc, unit, FRMR_RC0, 0x03);	/* RC0: Just shy of 1023 */
++		t4_framer_out(wc, unit, FRMR_RC1, 0x84);	/* RC1: The rest of RC0 */
++	} else { /* E1 mode */
++		t4_framer_out(wc, unit, FRMR_XC0, 0x00);	/* XC0: Normal operation of Sa-bits */
++		t4_framer_out(wc, unit, FRMR_XC1, 0x04);	/* XC1: 0 offset */
++		t4_framer_out(wc, unit, FRMR_RC0, 0x04);	/* RC0: Just shy of 1023 */
++		t4_framer_out(wc, unit, FRMR_RC1, 0x04);	/* RC1: The rest of RC0 */
++	}
++	
++	/* Configure ports */
++	t4_framer_out(wc, unit, 0x80, 0x00);	/* PC1: SPYR/SPYX input on RPA/XPA */
++	if (wc->falc31) {
++			  t4_framer_out(wc, unit, 0x81, 0xBB);	/* PC2: RMFB/XSIG output/input on RPB/XPB */
++			  t4_framer_out(wc, unit, 0x82, 0xBB);	/* PC3: Some unused stuff */
++			  t4_framer_out(wc, unit, 0x83, 0xBB);	/* PC4: Some more unused stuff */
++	} else {
++			  t4_framer_out(wc, unit, 0x81, 0x22);	/* PC2: RMFB/XSIG output/input on RPB/XPB */
++			  t4_framer_out(wc, unit, 0x82, 0x65);	/* PC3: Some unused stuff */
++			  t4_framer_out(wc, unit, 0x83, 0x35);	/* PC4: Some more unused stuff */
++	}
++	t4_framer_out(wc, unit, 0x84, 0x01);	/* PC5: XMFS active low, SCLKR is input, RCLK is output */
++	if (debug & DEBUG_MAIN)
++		dev_notice(&wc->dev->dev, "Successfully initialized serial "
++				"bus for unit %d\n", unit);
++}
++
++static int syncsrc = 0;
++static int syncnum = 0 /* -1 */;
++static int syncspan = 0;
++#ifdef DEFINE_SPINLOCK
++static DEFINE_SPINLOCK(synclock);
++#else
++static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
++#endif
++
++static void __t4_set_rclk_src(struct t4 *wc, int span)
++{
++	int cmr1 = 0x38;	/* Clock Mode: RCLK sourced by DCO-R1
++				   by default, Disable Clock-Switching */
++
++	cmr1 |= (span << 6);
++	__t4_framer_out(wc, 0, 0x44, cmr1);
++
++	dev_info(&wc->dev->dev, "RCLK source set to span %d\n", span+1);
++}
++
++static void __t4_set_sclk_src(struct t4 *wc, int mode, int master, int slave)
++{
++	if (slave) {
++		wc->dmactrl |= (1 << 25);
++		dev_info(&wc->dev->dev, "SCLK is slaved to timing cable\n");
++	} else {
++		wc->dmactrl &= ~(1 << 25);
++	}
++
++	if (master) {
++		wc->dmactrl |= (1 << 24);
++		dev_info(&wc->dev->dev, "SCLK is master to timing cable\n");
++	} else {
++		wc->dmactrl &= ~(1 << 24);
++	}
++
++	if (mode == WC_RECOVER)
++		wc->dmactrl |= (1 << 29); /* Recover timing from RCLK */
++
++	if (mode == WC_SELF)
++		wc->dmactrl &= ~(1 << 29);/* Provide timing from MCLK */
++
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18))
++static ssize_t t4_timing_master_show(struct device *dev,
++				     struct device_attribute *attr,
++				     char *buf)
++{
++	struct t4 *wc = dev_get_drvdata(dev);
++	if (wc->dmactrl & (1 << 29))
++		return sprintf(buf, "%d\n", wc->syncsrc);
++	else
++		return sprintf(buf, "%d\n", -1);
++}
++
++static DEVICE_ATTR(timing_master, 0400, t4_timing_master_show, NULL);
++
++static void create_sysfs_files(struct t4 *wc)
++{
++	int ret;
++	ret = device_create_file(&wc->dev->dev,
++				 &dev_attr_timing_master);
++	if (ret) {
++		dev_info(&wc->dev->dev,
++			"Failed to create device attributes.\n");
++	}
++}
++
++static void remove_sysfs_files(struct t4 *wc)
++{
++	device_remove_file(&wc->dev->dev,
++			   &dev_attr_timing_master);
++}
++
++#else
++
++static inline void create_sysfs_files(struct t4 *wc) { return; }
++static inline void remove_sysfs_files(struct t4 *wc) { return; }
++
++#endif /* LINUX_KERNEL > 2.6.18 */
++
++static inline void __t4_update_timing(struct t4 *wc)
++{
++	int i;
++	/* update sync src info */
++	if (wc->syncsrc != syncsrc) {
++		dev_info(&wc->dev->dev, "Swapping card %d from %d to %d\n",
++				wc->num, wc->syncsrc, syncsrc);
++		wc->syncsrc = syncsrc;
++		/* Update sync sources */
++		for (i = 0; i < wc->numspans; i++) {
++			wc->tspans[i]->span.syncsrc = wc->syncsrc;
++		}
++		if (syncnum == wc->num) {
++			__t4_set_rclk_src(wc, syncspan-1);
++			__t4_set_sclk_src(wc, WC_RECOVER, 1, 0);
++			if (debug)
++				dev_notice(&wc->dev->dev, "Card %d, using sync "
++					"span %d, master\n", wc->num, syncspan);
++		} else {
++			__t4_set_sclk_src(wc, WC_RECOVER, 0, 1);
++			if (debug)
++				dev_notice(&wc->dev->dev, "Card %d, using "
++					"Timing Bus, NOT master\n", wc->num);
++		}
++	}
++}
++
++static int __t4_findsync(struct t4 *wc)
++{
++	int i;
++	int x;
++	unsigned long flags;
++	int p;
++	int nonzero;
++	int newsyncsrc = 0;			/* DAHDI span number */
++	int newsyncnum = 0;			/* opvxd115 card number */
++	int newsyncspan = 0;		/* span on given opvxd115 card */
++	spin_lock_irqsave(&synclock, flags);
++#if 1
++	if (!wc->num) {
++		/* If we're the first card, go through all the motions, up to 8 levels
++		   of sync source */
++		p = 1;
++		while (p < 8) {
++			nonzero = 0;
++			for (x=0;cards[x];x++) {
++				for (i = 0; i < wc->numspans; i++) {
++					if (cards[x]->tspans[i]->syncpos) {
++						nonzero = 1;
++						if ((cards[x]->tspans[i]->syncpos == p) &&
++						    !(cards[x]->tspans[i]->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_LOOPBACK)) &&
++							(cards[x]->tspans[i]->span.flags & DAHDI_FLAG_RUNNING)) {
++								/* This makes a good sync source */
++								newsyncsrc = cards[x]->tspans[i]->span.spanno;
++								newsyncnum = x;
++								newsyncspan = i + 1;
++								/* Jump out */
++								goto found;
++						}
++					}
++				}		
++			}
++			if (nonzero)
++				p++;
++			else 
++				break;
++		}
++found:		
++		if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) {
++			if (debug)
++				dev_notice(&wc->dev->dev, "New syncnum: %d "
++					"(was %d), syncsrc: %d (was %d), "
++					"syncspan: %d (was %d)\n", newsyncnum,
++					syncnum, newsyncsrc, syncsrc,
++					newsyncspan, syncspan);
++			syncnum = newsyncnum;
++			syncsrc = newsyncsrc;
++			syncspan = newsyncspan;
++			for (x=0;cards[x];x++) {
++				__t4_update_timing(cards[x]);
++			}
++		}
++	}
++	__t4_update_timing(wc);
++#endif	
++	spin_unlock_irqrestore(&synclock, flags);
++	return 0;
++}
++
++static void __t4_set_timing_source_auto(struct t4 *wc)
++{
++	int x;
++	int firstprio, secondprio;
++	firstprio = secondprio = 4;
++
++	if (debug)
++		dev_info(&wc->dev->dev, "timing source auto\n");
++	clear_bit(T4_CHECK_TIMING, &wc->checkflag);
++	if (timingcable) {
++		__t4_findsync(wc);
++	} else {
++		if (debug)
++			dev_info(&wc->dev->dev, "Evaluating spans for timing "
++					"source\n");
++		for (x=0;x<wc->numspans;x++) {
++			if ((wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) &&
++			   !(wc->tspans[x]->span.alarms & (DAHDI_ALARM_RED |
++							   DAHDI_ALARM_BLUE))) {
++				if (debug)
++					dev_info(&wc->dev->dev, "span %d is "
++						"green : syncpos %d\n", x+1,
++						wc->tspans[x]->syncpos);
++				if (wc->tspans[x]->syncpos) {
++					/* Valid rsync source in recovered
++					   timing mode */
++					if (firstprio == 4)
++						firstprio = x;
++					else if (wc->tspans[x]->syncpos <
++						wc->tspans[firstprio]->syncpos)
++						firstprio = x;
++				} else {
++					/* Valid rsync source in system timing
++					   mode */
++					if (secondprio == 4)
++						secondprio = x;
++				}
++			}
++		}
++		if (firstprio != 4) {
++			wc->syncsrc = firstprio;
++			__t4_set_rclk_src(wc, firstprio);
++			__t4_set_sclk_src(wc, WC_RECOVER, 0, 0);
++			dev_info(&wc->dev->dev, "Recovered timing mode, "\
++						"RCLK set to span %d\n",
++						firstprio+1);
++		} else if (secondprio != 4) {
++			wc->syncsrc = -1;
++			__t4_set_rclk_src(wc, secondprio);
++			__t4_set_sclk_src(wc, WC_SELF, 0, 0);
++			dev_info(&wc->dev->dev, "System timing mode, "\
++						"RCLK set to span %d\n",
++						secondprio+1);
++		} else {
++			wc->syncsrc = -1;
++			dev_info(&wc->dev->dev, "All spans in alarm : No valid"\
++						"span to source RCLK from\n");
++			/* Default rclk to lock with span 1 */
++			__t4_set_rclk_src(wc, 0);
++			__t4_set_sclk_src(wc, WC_SELF, 0, 0);
++		}
++	}
++}
++
++static void __t4_configure_t1(struct t4 *wc, int unit, 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 = 0x9c; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */
++	fmr2 = 0x20; /* FMR2: no payload loopback, don't auto yellow */
++	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 */
++	__t4_framer_out(wc, unit, 0x1d, fmr1);
++	__t4_framer_out(wc, unit, 0x1e, fmr2);
++
++	/* Configure line interface */
++	if (lineconfig & DAHDI_CONFIG_AMI) {
++		line = "AMI";
++		/* workaround for errata #2 in ES v3 09-10-16 */
++		fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
++	} else {
++		line = "B8ZS";
++		fmr0 = 0xf0;
++	}
++	if (lineconfig & DAHDI_CONFIG_D4) {
++		framing = "D4";
++	} else {
++		framing = "ESF";
++		fmr4 |= 0x2;
++		fmr2 |= 0xc0;
++	}
++	__t4_framer_out(wc, unit, 0x1c, fmr0);
++	__t4_framer_out(wc, unit, 0x20, fmr4);
++	__t4_framer_out(wc, unit, 0x21, 0x40);	/* FMR5: Enable RBS mode */
++
++	__t4_framer_out(wc, unit, 0x37, 0xf0 );	/* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
++	__t4_framer_out(wc, unit, 0x36, 0x08);	/* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
++
++	__t4_framer_out(wc, unit, 0x02, 0x50);	/* CMDR: Reset the receiver and transmitter line interface */
++	__t4_framer_out(wc, unit, 0x02, 0x00);	/* CMDR: Reset the receiver and transmitter line interface */
++
++	if (wc->falc31) {
++		if (debug)
++			dev_info(&wc->dev->dev, "card %d span %d: setting Rtx "
++					"to 0ohm for T1\n", wc->num, unit);
++		__t4_framer_out(wc, unit, 0x86, 0x00);	/* PC6: set Rtx to 0ohm for T1 */
++
++		// Hitting the bugfix register to fix errata #3
++		__t4_framer_out(wc, unit, 0xbd, 0x05);
++	}
++
++	__t4_framer_out(wc, unit, 0x3a, lim2);	/* LIM2: 50% peak amplitude is a "1" */
++	__t4_framer_out(wc, unit, 0x38, 0x0a);	/* PCD: LOS after 176 consecutive "zeros" */
++	__t4_framer_out(wc, unit, 0x39, 0x15);	/* PCR: 22 "ones" clear LOS */
++	
++	/* Generate pulse mask for T1 */
++	switch(mytxlevel) {
++	case 3:
++		__t4_framer_out(wc, unit, 0x26, 0x07);	/* XPM0 */
++		__t4_framer_out(wc, unit, 0x27, 0x01);	/* XPM1 */
++		__t4_framer_out(wc, unit, 0x28, 0x00);	/* XPM2 */
++		break;
++	case 2:
++		__t4_framer_out(wc, unit, 0x26, 0x8c);	/* XPM0 */
++		__t4_framer_out(wc, unit, 0x27, 0x11);	/* XPM1 */
++		__t4_framer_out(wc, unit, 0x28, 0x01);	/* XPM2 */
++		break;
++	case 1:
++		__t4_framer_out(wc, unit, 0x26, 0x8c);	/* XPM0 */
++		__t4_framer_out(wc, unit, 0x27, 0x01);	/* XPM1 */
++		__t4_framer_out(wc, unit, 0x28, 0x00);	/* XPM2 */
++		break;
++	case 0:
++	default:
++		__t4_framer_out(wc, unit, 0x26, 0xd7);	/* XPM0 */
++		__t4_framer_out(wc, unit, 0x27, 0x22);	/* XPM1 */
++		__t4_framer_out(wc, unit, 0x28, 0x01);	/* XPM2 */
++		break;
++	}
++
++	/* Don't mask framer interrupts if hardware HDLC is in use */
++	__t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0));	/* IMR0: We care about CAS changes, etc */
++	__t4_framer_out(wc, unit, FRMR_IMR1, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0));	/* IMR1: We care about nothing */
++	__t4_framer_out(wc, unit, 0x16, 0x00);	/* IMR2: All the alarm stuff! */
++	__t4_framer_out(wc, unit, 0x17, 0x34);	/* IMR3: AIS and friends */
++	__t4_framer_out(wc, unit, 0x18, 0x3f);  /* IMR4: Slips on transmit */
++
++	dev_info(&wc->dev->dev, "Span %d configured for %s/%s\n", unit + 1,
++			framing, line);
++}
++
++static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
++{
++	unsigned int fmr2, fmr1, fmr0;
++	unsigned int cas = 0;
++	unsigned int imr3extra=0;
++	char *crc4 = "";
++	char *framing, *line;
++	fmr1 = 0x44; /* 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 (lineconfig & DAHDI_CONFIG_CRC4) {
++		fmr1 |= 0x08;	/* CRC4 transmit */
++		fmr2 |= 0xc0;	/* CRC4 receive */
++		crc4 = "/CRC4";
++	}
++	__t4_framer_out(wc, unit, 0x1d, fmr1);
++	__t4_framer_out(wc, unit, 0x1e, fmr2);
++
++	/* Configure line interface */
++	if (lineconfig & DAHDI_CONFIG_AMI) {
++		line = "AMI";
++		/* workaround for errata #2 in ES v3 09-10-16 */
++		fmr0 = (wc->falc31) ? 0xb0 : 0xa0;
++	} else {
++		line = "HDB3";
++		fmr0 = 0xf0;
++	}
++	if (lineconfig & DAHDI_CONFIG_CCS) {
++		framing = "CCS";
++		imr3extra = 0x28;
++	} else {
++		framing = "CAS";
++		cas = 0x40;
++	}
++	__t4_framer_out(wc, unit, 0x1c, fmr0);
++
++	__t4_framer_out(wc, unit, 0x37, 0xf0 /*| 0x6 */ );	/* LIM1: Clear data in case of LOS, Set receiver threshold (0.5V), No remote loop, no DRS */
++	__t4_framer_out(wc, unit, 0x36, 0x08);	/* LIM0: Enable auto long haul mode, no local loop (must be after LIM1) */
++
++	__t4_framer_out(wc, unit, 0x02, 0x50);	/* CMDR: Reset the receiver and transmitter line interface */
++	__t4_framer_out(wc, unit, 0x02, 0x00);	/* CMDR: Reset the receiver and transmitter line interface */
++
++	if (wc->falc31) {
++		if (debug)
++			dev_info(&wc->dev->dev,
++					"setting Rtx to 7.5ohm for E1\n");
++		__t4_framer_out(wc, unit, 0x86, 0x40);	/* PC6: turn on 7.5ohm Rtx for E1 */
++	}
++
++	/* Condition receive line interface for E1 after reset */
++	__t4_framer_out(wc, unit, 0xbb, 0x17);
++	__t4_framer_out(wc, unit, 0xbc, 0x55);
++	__t4_framer_out(wc, unit, 0xbb, 0x97);
++	__t4_framer_out(wc, unit, 0xbb, 0x11);
++	__t4_framer_out(wc, unit, 0xbc, 0xaa);
++	__t4_framer_out(wc, unit, 0xbb, 0x91);
++	__t4_framer_out(wc, unit, 0xbb, 0x12);
++	__t4_framer_out(wc, unit, 0xbc, 0x55);
++	__t4_framer_out(wc, unit, 0xbb, 0x92);
++	__t4_framer_out(wc, unit, 0xbb, 0x0c);
++	__t4_framer_out(wc, unit, 0xbb, 0x00);
++	__t4_framer_out(wc, unit, 0xbb, 0x8c);
++	
++	__t4_framer_out(wc, unit, 0x3a, 0x20);	/* LIM2: 50% peak amplitude is a "1" */
++	__t4_framer_out(wc, unit, 0x38, 0x0a);	/* PCD: LOS after 176 consecutive "zeros" */
++	__t4_framer_out(wc, unit, 0x39, 0x15);	/* PCR: 22 "ones" clear LOS */
++	
++	__t4_framer_out(wc, unit, 0x20, 0x9f);	/* XSW: Spare bits all to 1 */
++	__t4_framer_out(wc, unit, 0x21, 0x1c|cas);	/* XSP: E-bit set when async. AXS auto, XSIF to 1 */
++	
++	
++	/* Generate pulse mask for E1 */
++	__t4_framer_out(wc, unit, 0x26, 0x54);	/* XPM0 */
++	__t4_framer_out(wc, unit, 0x27, 0x02);	/* XPM1 */
++	__t4_framer_out(wc, unit, 0x28, 0x00);	/* XPM2 */
++
++	/* Don't mask framer interrupts if hardware HDLC is in use */
++	__t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0));	/* IMR0: We care about CRC errors, CAS changes, etc */
++	__t4_framer_out(wc, unit, FRMR_IMR1, 0x3f & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0));	/* IMR1: We care about loopup / loopdown */
++	__t4_framer_out(wc, unit, 0x16, 0x00);	/* IMR2: We care about all the alarm stuff! */
++	__t4_framer_out(wc, unit, 0x17, 0x04 | imr3extra); /* IMR3: AIS */
++	__t4_framer_out(wc, unit, 0x18, 0x3f);  /* IMR4: We care about slips on transmit */
++
++	dev_info(&wc->dev->dev, "opvxd115: Span %d configured for %s/%s%s\n",
++			unit + 1, framing, line, crc4);
++}
++
++static int t4_startup(struct dahdi_span *span)
++{
++#ifdef SUPPORT_GEN1
++	int i;
++#endif
++	int tspan;
++	unsigned long flags;
++	int alreadyrunning;
++	struct t4_span *ts = t4_from_span(span);
++	struct t4 *wc = ts->owner;
++
++	set_bit(T4_IGNORE_LATENCY, &wc->checkflag);
++	if (debug)
++		dev_info(&wc->dev->dev, "About to enter startup!\n");
++	tspan = span->offset + 1;
++	if (tspan < 0) {
++		dev_info(&wc->dev->dev, "opvxd115: Span '%d' isn't us?\n",
++				span->spanno);
++		return -1;
++	}
++
++	spin_lock_irqsave(&wc->reglock, flags);
++
++	alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
++
++#ifdef SUPPORT_GEN1
++	/* initialize the start value for the entire chunk of last ec buffer */
++	for(i = 0; i < span->channels; i++)
++	{
++		memset(ts->ec_chunk1[i],
++			DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE);
++		memset(ts->ec_chunk2[i],
++			DAHDI_LIN2X(0,span->chans[i]),DAHDI_CHUNKSIZE);
++	}
++#endif
++	/* Force re-evaluation of timing source */
++	wc->syncsrc = -1;
++	set_bit(T4_CHECK_TIMING, &wc->checkflag);
++
++	if (ts->spantype == TYPE_E1) { /* if this is an E1 card */
++		__t4_configure_e1(wc, span->offset, span->lineconfig);
++	} else { /* is a T1 card */
++		__t4_configure_t1(wc, span->offset, span->lineconfig, span->txlevel);
++	}
++
++	/* Note clear channel status */
++	wc->tspans[span->offset]->notclear = 0;
++	__set_clear(wc, span->offset);
++	
++	if (!alreadyrunning) {
++		span->flags |= DAHDI_FLAG_RUNNING;
++		wc->spansstarted++;
++
++		if (wc->flags & FLAG_5THGEN)
++			__t4_pci_out(wc, 5, (ms_per_irq << 16) | wc->numbufs);
++		/* enable interrupts */
++		/* Start DMA, enabling DMA interrupts on read only */
++#if 0
++		/* Enable framer only interrupts */
++		wc->dmactrl |= 1 << 27;
++#endif
++		wc->dmactrl |= (ts->spanflags & FLAG_2NDGEN) ? 0xc0000000 : 0xc0000003;
++#ifdef VPM_SUPPORT
++		wc->dmactrl |= wc->vpm;
++#endif
++		/* Seed interrupt register */
++		__t4_pci_out(wc, WC_INTR, 0x0c);
++		if (noburst || !(ts->spanflags & FLAG_BURST))
++			wc->dmactrl |= (1 << 26);
++		__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++
++		/* Startup HDLC controller too */
++	}
++
++	if (ts->sigchan) {
++		struct dahdi_chan *sigchan = ts->sigchan;
++
++		spin_unlock_irqrestore(&wc->reglock, flags);
++		if (hdlc_start(wc, span->offset, sigchan, ts->sigmode)) {
++			dev_notice(&wc->dev->dev, "Error initializing "
++					"signalling controller\n");
++			return -1;
++		}
++		spin_lock_irqsave(&wc->reglock, flags);
++	}
++
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	t4_check_alarms(wc, span->offset);
++	t4_check_sigbits(wc, span->offset);
++
++	if (wc->tspans[0]->sync == span->spanno)
++		dev_info(&wc->dev->dev, "SPAN %d: Primary Sync Source\n",
++				span->spanno);
++#ifdef VPM_SUPPORT
++	if (!alreadyrunning && !wc->vpm) {
++		wait_a_little();
++		t4_vpm400_init(wc);
++		if (!wc->vpm)
++			t4_vpm450_init(wc);
++		wc->dmactrl |= wc->vpm;
++		t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++		if (wc->vpm)
++			set_span_devicetype(wc);
++	}
++#endif
++	if (debug)
++		dev_info(&wc->dev->dev, "Completed startup!\n");
++	clear_bit(T4_IGNORE_LATENCY, &wc->checkflag);
++	return 0;
++}
++
++#ifdef SUPPORT_GEN1
++static inline void e1_check(struct t4 *wc, int span, int val)
++{
++	struct t4_span *ts = wc->tspans[span];
++	if ((ts->span.channels > 24) &&
++	    (ts->span.flags & DAHDI_FLAG_RUNNING) &&
++	    !(ts->span.alarms) &&
++	    (!wc->e1recover))   {
++		if (val != 0x1b) {
++			ts->e1check++;
++		} else
++			ts->e1check = 0;
++		if (ts->e1check > 100) {
++			/* Wait 1000 ms */
++			wc->e1recover = 1000 * 8;
++			wc->tspans[0]->e1check = 0;
++			if (debug & DEBUG_MAIN)
++				dev_notice(&wc->dev->dev, "Detected loss of "
++					"E1 alignment on span %d!\n", span);
++			t4_reset_dma(wc);
++		}
++	}
++}
++
++static void t4_receiveprep(struct t4 *wc, int irq)
++{
++	volatile unsigned int *readchunk;
++	int dbl = 0;
++	int x,y,z;
++	unsigned int tmp;
++	int offset=0;
++	if (!wc->t1e1)
++		offset = 4;
++	if (irq & 1) {
++		/* First part */
++		readchunk = wc->readchunk;
++		if (!wc->last0) 
++			dbl = 1;
++		wc->last0 = 0;
++	} else {
++		readchunk = wc->readchunk + DAHDI_CHUNKSIZE * 32;
++		if (wc->last0) 
++			dbl = 1;
++		wc->last0 = 1;
++	}
++	if (dbl) {
++		for (x=0;x<wc->numspans;x++)
++			wc->tspans[x]->irqmisses++;
++		if (debug & DEBUG_MAIN)
++			dev_notice(&wc->dev->dev, "opvxd115: Double/missed "
++				"interrupt detected\n");
++	}
++	for (x=0;x<DAHDI_CHUNKSIZE;x++) {
++		for (z=0;z<24;z++) {
++			/* All T1/E1 channels */
++			tmp = readchunk[z+1+offset];
++			wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24;
++		}
++		if (wc->t1e1) {
++			if (wc->e1recover > 0)
++				wc->e1recover--;
++			tmp = readchunk[0];
++			e1_check(wc, 0, (tmp & 0x7f000000) >> 24);
++			for (z=24;z<31;z++) {
++				/* Only E1 channels now */
++				tmp = readchunk[z+1];
++				if (wc->tspans[0]->span.channels > 24)
++					wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24;
++			}
++		}
++		/* Advance pointer by 4 TDM frame lengths */
++		readchunk += 32;
++	}
++	for (x=0;x<wc->numspans;x++) {
++		if (wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) {
++			for (y=0;y<wc->tspans[x]->span.channels;y++) {
++				/* Echo cancel double buffered data */
++				dahdi_ec_chunk(wc->tspans[x]->span.chans[y], 
++				    wc->tspans[x]->span.chans[y]->readchunk, 
++					wc->tspans[x]->ec_chunk2[y]);
++				memcpy(wc->tspans[x]->ec_chunk2[y],wc->tspans[x]->ec_chunk1[y],
++					DAHDI_CHUNKSIZE);
++				memcpy(wc->tspans[x]->ec_chunk1[y],
++					wc->tspans[x]->span.chans[y]->writechunk,
++						DAHDI_CHUNKSIZE);
++			}
++			dahdi_receive(&wc->tspans[x]->span);
++		}
++	}
++}
++#endif
++
++#if (DAHDI_CHUNKSIZE != 8)
++#error Sorry, nextgen does not support chunksize != 8
++#endif
++
++static inline void __receive_span(struct t4_span *ts)
++{
++#ifdef VPM_SUPPORT
++	int y;
++	unsigned long merged;
++	merged = ts->dtmfactive & ts->dtmfmutemask;
++	if (merged) {
++		for (y=0;y<ts->span.channels;y++) {
++			/* Mute any DTMFs which are supposed to be muted */
++			if (test_bit(y, &merged)) {
++				memset(ts->span.chans[y]->readchunk, DAHDI_XLAW(0, ts->span.chans[y]), DAHDI_CHUNKSIZE);
++			}
++		}
++	}
++#endif	
++
++#ifdef ENABLE_PREFETCH
++	prefetch((void *)(ts->readchunk));
++	prefetch((void *)(ts->writechunk));
++	prefetch((void *)(ts->readchunk + 8));
++	prefetch((void *)(ts->writechunk + 8));
++	prefetch((void *)(ts->readchunk + 16));
++	prefetch((void *)(ts->writechunk + 16));
++	prefetch((void *)(ts->readchunk + 24));
++	prefetch((void *)(ts->writechunk + 24));
++	prefetch((void *)(ts->readchunk + 32));
++	prefetch((void *)(ts->writechunk + 32));
++	prefetch((void *)(ts->readchunk + 40));
++	prefetch((void *)(ts->writechunk + 40));
++	prefetch((void *)(ts->readchunk + 48));
++	prefetch((void *)(ts->writechunk + 48));
++	prefetch((void *)(ts->readchunk + 56));
++	prefetch((void *)(ts->writechunk + 56));
++#endif
++
++	dahdi_ec_span(&ts->span);
++	dahdi_receive(&ts->span);
++}
++
++static inline void __transmit_span(struct t4_span *ts)
++{
++	dahdi_transmit(&ts->span);
++}
++
++#ifdef ENABLE_WORKQUEUES
++static void workq_handlespan(void *data)
++{
++	struct t4_span *ts = data;
++	struct t4 *wc = ts->owner;
++	
++	__receive_span(ts);
++	__transmit_span(ts);
++	atomic_dec(&wc->worklist);
++	if (!atomic_read(&wc->worklist))
++		t4_pci_out(wc, WC_INTR, 0);
++}
++#else
++static void t4_prep_gen2(struct t4 *wc)
++{
++	int x;
++	for (x=0;x<wc->numspans;x++) {
++		if (wc->tspans[x]->span.flags & DAHDI_FLAG_RUNNING) {
++			__receive_span(wc->tspans[x]);
++			__transmit_span(wc->tspans[x]);
++		}
++	}
++}
++
++#endif
++#ifdef SUPPORT_GEN1
++static void t4_transmitprep(struct t4 *wc, int irq)
++{
++	volatile unsigned int *writechunk;
++	int x,y,z;
++	unsigned int tmp;
++	int offset=0;
++	if (!wc->t1e1)
++		offset = 4;
++	if (irq & 1) {
++		/* First part */
++		writechunk = wc->writechunk + 1;
++	} else {
++		writechunk = wc->writechunk + DAHDI_CHUNKSIZE * 32  + 1;
++	}
++	for (y=0;y<wc->numspans;y++) {
++		if (wc->tspans[y]->span.flags & DAHDI_FLAG_RUNNING) 
++			dahdi_transmit(&wc->tspans[y]->span);
++	}
++
++	for (x=0;x<DAHDI_CHUNKSIZE;x++) {
++		/* Once per chunk */
++		for (z=0;z<24;z++) {
++			/* All T1/E1 channels */
++			tmp = (wc->tspans[0]->span.chans[z]->writechunk[x] << 24);
++			writechunk[z+offset] = tmp;
++		}
++		if (wc->t1e1) {
++			for (z=24;z<31;z++) {
++				/* Only E1 channels now */
++				tmp = 0;
++				if (wc->tspans[0]->span.channels > 24)
++					tmp |= (wc->tspans[0]->span.chans[z]->writechunk[x] << 24);
++				writechunk[z] = tmp;
++			}
++		}
++		/* Advance pointer by 4 TDM frame lengths */
++		writechunk += 32;
++	}
++
++}
++#endif
++
++static void t4_check_sigbits(struct t4 *wc, int span)
++{
++	int a,i,rxs;
++	struct t4_span *ts = wc->tspans[span];
++
++	if (debug & DEBUG_RBS)
++		dev_notice(&wc->dev->dev, "Checking sigbits on span %d\n",
++				span + 1);
++
++	if (!(ts->span.flags & DAHDI_FLAG_RUNNING))
++		return;
++	if (ts->spantype == TYPE_E1) {
++		for (i = 0; i < 15; i++) {
++			a = t4_framer_in(wc, span, 0x71 + i);
++			/* Get high channel in low bits */
++			rxs = (a & 0xf);
++			if (!(ts->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i+16]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i+16], rxs);
++			}
++			rxs = (a >> 4) & 0xf;
++			if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i], rxs);
++			}
++		}
++	} else if (ts->span.lineconfig & DAHDI_CONFIG_D4) {
++		for (i = 0; i < 24; i+=4) {
++			a = t4_framer_in(wc, span, 0x70 + (i>>2));
++			/* Get high channel in low bits */
++			rxs = (a & 0x3) << 2;
++			if (!(ts->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i+3]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i+3], rxs);
++			}
++			rxs = (a & 0xc);
++			if (!(ts->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i+2]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i+2], rxs);
++			}
++			rxs = (a >> 2) & 0xc;
++			if (!(ts->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i+1]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i+1], rxs);
++			}
++			rxs = (a >> 4) & 0xc;
++			if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
++				if (ts->span.chans[i]->rxsig != rxs)
++					dahdi_rbsbits(ts->span.chans[i], rxs);
++			}
++		}
++	} else {
++		for (i = 0; i < 24; i+=2) {
++			a = t4_framer_in(wc, span, 0x70 + (i>>1));
++			/* Get high channel in low bits */
++			rxs = (a & 0xf);
++			if (!(ts->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) {
++				/* XXX Not really reset on every trans! XXX */
++				if (ts->span.chans[i+1]->rxsig != rxs) {
++					dahdi_rbsbits(ts->span.chans[i+1], rxs);
++				}
++			}
++			rxs = (a >> 4) & 0xf;
++			if (!(ts->span.chans[i]->sig & DAHDI_SIG_CLEAR)) {
++				/* XXX Not really reset on every trans! XXX */
++				if (ts->span.chans[i]->rxsig != rxs) {
++					dahdi_rbsbits(ts->span.chans[i], rxs);
++				}
++			}
++		}
++	}
++}
++
++static void t4_check_alarms(struct t4 *wc, int span)
++{
++	unsigned char c, d, e;
++	int alarms;
++	int x,j;
++	struct t4_span *ts = wc->tspans[span];
++	unsigned long flags;
++
++	if (!(ts->span.flags & DAHDI_FLAG_RUNNING))
++		return;
++
++	spin_lock_irqsave(&wc->reglock, flags);
++
++	c = __t4_framer_in(wc, span, 0x4c);
++	d = __t4_framer_in(wc, span, 0x4d);
++
++	/* Assume no alarms */
++	alarms = 0;
++
++	/* And consider only carrier alarms */
++	ts->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN);
++
++	if (ts->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 (!(ts->spanflags & FLAG_NMF)) {
++				__t4_framer_out(wc, span, 0x20, 0x9f | 0x20);	/* LIM0: Force RAI High */
++				ts->spanflags |= FLAG_NMF;
++				dev_notice(&wc->dev->dev,
++					"NMF workaround on!\n");
++			}
++			__t4_framer_out(wc, span, 0x1e, 0xc3);	/* Reset to CRC4 mode */
++			__t4_framer_out(wc, span, 0x1c, 0xf2);	/* Force Resync */
++			__t4_framer_out(wc, span, 0x1c, 0xf0);	/* Force Resync */
++		} else if (!(c & 0x02)) {
++			if ((ts->spanflags & FLAG_NMF)) {
++				__t4_framer_out(wc, span, 0x20, 0x9f);	/* LIM0: Clear forced RAI */
++				ts->spanflags &= ~FLAG_NMF;
++				dev_notice(&wc->dev->dev,
++					"NMF workaround off!\n");
++			}
++		}
++	} else {
++		/* Detect loopup code if we're not sending one */
++		if ((!ts->span.mainttimer) && (d & 0x08)) {
++			/* Loop-up code detected */
++			if ((ts->loopupcnt++ > 80)  && (ts->span.maintstat != DAHDI_MAINT_REMOTELOOP)) {
++				__t4_framer_out(wc, span, 0x36, 0x08);	/* LIM0: Disable any local loop */
++				__t4_framer_out(wc, span, 0x37, 0xf6 );	/* LIM1: Enable remote loop */
++				ts->span.maintstat = DAHDI_MAINT_REMOTELOOP;
++			}
++		} else
++			ts->loopupcnt = 0;
++		/* Same for loopdown code */
++		if ((!ts->span.mainttimer) && (d & 0x10)) {
++			/* Loop-down code detected */
++			if ((ts->loopdowncnt++ > 80)  && (ts->span.maintstat == DAHDI_MAINT_REMOTELOOP)) {
++				__t4_framer_out(wc, span, 0x36, 0x08);	/* LIM0: Disable any local loop */
++				__t4_framer_out(wc, span, 0x37, 0xf0 );	/* LIM1: Disable remote loop */
++				ts->span.maintstat = DAHDI_MAINT_NONE;
++			}
++		} else
++			ts->loopdowncnt = 0;
++	}
++
++	if (ts->span.lineconfig & DAHDI_CONFIG_NOTOPEN) {
++		for (x=0,j=0;x < ts->span.channels;x++)
++			if ((ts->span.chans[x]->flags & DAHDI_FLAG_OPEN) ||
++			    (ts->span.chans[x]->flags & DAHDI_FLAG_NETDEV))
++				j++;
++		if (!j)
++			alarms |= DAHDI_ALARM_NOTOPEN;
++	}
++
++	/* Loss of Frame Alignment */
++	if (c & 0x20) {
++		if (ts->alarmcount >= alarmdebounce) {
++
++			/* Disable Slip Interrupts */
++			e = __t4_framer_in(wc, span, 0x17);
++			__t4_framer_out(wc, span, 0x17, (e|0x03));
++
++			alarms |= DAHDI_ALARM_RED;
++		} else {
++			if (unlikely(debug && !ts->alarmcount)) {
++				/* starting to debounce LOF/LFA */
++				dev_info(&wc->dev->dev, "opvxd115: LOF/LFA "
++					"detected on span %d but debouncing "
++					"for %d ms\n", span + 1,
++					alarmdebounce);
++			}
++			ts->alarmcount++;
++		}
++	} else
++		ts->alarmcount = 0;
++
++	/* Loss of Signal */
++	if (c & 0x80) {
++		if (ts->losalarmcount >= losalarmdebounce) {
++			/* Disable Slip Interrupts */
++			e = __t4_framer_in(wc, span, 0x17);
++			__t4_framer_out(wc, span, 0x17, (e|0x03));
++
++			alarms |= DAHDI_ALARM_RED;
++		} else {
++			if (unlikely(debug && !ts->losalarmcount)) {
++				/* starting to debounce LOS */
++				dev_info(&wc->dev->dev, "opvxd115: LOS "
++					"detected on span %d but debouncing "
++					"for %d ms\n",
++					span + 1, losalarmdebounce);
++			}
++			ts->losalarmcount++;
++		}
++	} else
++		ts->losalarmcount = 0;
++
++	/* Alarm Indication Signal */
++	if (c & 0x40) {
++		if (ts->aisalarmcount >= aisalarmdebounce)
++			alarms |= DAHDI_ALARM_BLUE;
++		else {
++			if (unlikely(debug && !ts->aisalarmcount)) {
++				/* starting to debounce AIS */
++				dev_info(&wc->dev->dev, "opvxd115: AIS "
++					"detected on span %d but debouncing "
++					"for %d ms\n",
++					span + 1, aisalarmdebounce);
++			}
++			ts->aisalarmcount++;
++		}
++	} else
++		ts->aisalarmcount = 0;
++
++#ifdef DAHDI_SPAN_OPS
++	/* Add detailed alarm status information to a red alarm state */
++	if (alarms & DAHDI_ALARM_RED) {
++		if (c & FRS0_LOS)
++			alarms |= DAHDI_ALARM_LOS;
++		if (c & FRS0_LFA)
++			alarms |= DAHDI_ALARM_LFA;
++		if (c & FRS0_LMFA)
++			alarms |= DAHDI_ALARM_LMFA;
++	}
++
++	if (unlikely(debug)) {
++		/* Check to ensure the xmit line isn't shorted */
++		if (unlikely(d & FRS1_XLS)) {
++			dev_info(&wc->dev->dev,
++				"Detected a possible hardware malfunction"\
++				" this card may need servicing\n");
++		}
++	}
++#endif
++
++	if (((!ts->span.alarms) && alarms) || 
++	    (ts->span.alarms && (!alarms))) 
++		set_bit(T4_CHECK_TIMING, &wc->checkflag);
++
++	/* Keep track of recovering */
++	if ((!alarms) && ts->span.alarms) 
++		ts->alarmtimer = DAHDI_ALARMSETTLE_TIME;
++	if (ts->alarmtimer)
++		alarms |= DAHDI_ALARM_RECOVER;
++
++	/* If receiving alarms, go into Yellow alarm state */
++	if (alarms && !(ts->spanflags & FLAG_SENDINGYELLOW)) {
++		/* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */
++		unsigned char fmr4;
++		fmr4 = __t4_framer_in(wc, span, 0x20);
++		__t4_framer_out(wc, span, 0x20, fmr4 | 0x20);
++		dev_info(&wc->dev->dev, "Setting yellow alarm span %d\n",
++								span+1);
++		ts->spanflags |= FLAG_SENDINGYELLOW;
++	} else if ((!alarms) && (ts->spanflags & FLAG_SENDINGYELLOW)) {
++		unsigned char fmr4;
++		/* We manually do yellow alarm to handle RECOVER  */
++		fmr4 = __t4_framer_in(wc, span, 0x20);
++		__t4_framer_out(wc, span, 0x20, fmr4 & ~0x20);
++		dev_info(&wc->dev->dev, "Clearing yellow alarm span %d\n",
++								span+1);
++
++		/* Re-enable timing slip interrupts */
++		e = __t4_framer_in(wc, span, 0x17);
++
++		__t4_framer_out(wc, span, 0x17, (e & ~(0x03)));
++
++		ts->spanflags &= ~FLAG_SENDINGYELLOW;
++	}
++
++	/* Re-check the timing source when we enter/leave alarm, not withstanding
++	   yellow alarm */
++	if (c & 0x10) { /* receiving yellow (RAI) */
++		if (ts->yelalarmcount >= yelalarmdebounce)
++			alarms |= DAHDI_ALARM_YELLOW;
++		else {
++			if (unlikely(debug && !ts->yelalarmcount)) {
++				/* starting to debounce AIS */
++				dev_info(&wc->dev->dev, "wct%dxxp: yellow "
++					"(RAI) detected on span %d but "
++					"debouncing for %d ms\n",
++					wc->numspans, span + 1,
++					yelalarmdebounce);
++			}
++			ts->yelalarmcount++;
++		}
++	} else
++		ts->yelalarmcount = 0;
++
++	if (ts->span.mainttimer || ts->span.maintstat) 
++		alarms |= DAHDI_ALARM_LOOPBACK;
++	ts->span.alarms = alarms;
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	dahdi_alarm_notify(&ts->span);
++}
++
++static void t4_do_counters(struct t4 *wc)
++{
++	int span;
++	for (span=0;span<wc->numspans;span++) {
++		struct t4_span *ts = wc->tspans[span];
++		int docheck=0;
++
++		spin_lock(&wc->reglock);
++		if (ts->loopupcnt || ts->loopdowncnt || ts->alarmcount
++			|| ts->losalarmcount || ts->aisalarmcount
++			|| ts->yelalarmcount)
++			docheck++;
++
++		if (ts->alarmtimer) {
++			if (!--ts->alarmtimer) {
++				docheck++;
++				ts->span.alarms &= ~(DAHDI_ALARM_RECOVER);
++			}
++		}
++		spin_unlock(&wc->reglock);
++		if (docheck) {
++			t4_check_alarms(wc, span);
++			dahdi_alarm_notify(&ts->span);
++		}
++	}
++}
++
++static inline void __handle_leds(struct t4 *wc)
++{
++	int x;
++
++	wc->blinktimer++;
++	for (x=0;x<wc->numspans;x++) {
++		struct t4_span *ts = wc->tspans[x];
++		if (ts->span.flags & DAHDI_FLAG_RUNNING) {
++			if ((ts->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) || ts->losalarmcount) {
++#ifdef FANCY_ALARM
++				if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
++					__t4_set_led(wc, x, WC_RED);
++				}
++				if (wc->blinktimer == 0xf) {
++					__t4_set_led(wc, x, WC_OFF);
++				}
++#else
++				if (wc->blinktimer == 160) {
++					__t4_set_led(wc, x, WC_RED);
++				} else if (wc->blinktimer == 480) {
++					__t4_set_led(wc, x, WC_OFF);
++				}
++#endif
++			} else if (ts->span.alarms & DAHDI_ALARM_YELLOW) {
++				/* Yellow Alarm */
++				__t4_set_led(wc, x, WC_YELLOW);
++			} else if (ts->span.mainttimer || ts->span.maintstat) {
++#ifdef FANCY_ALARM
++				if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
++					__t4_set_led(wc, x, WC_GREEN);
++				}
++				if (wc->blinktimer == 0xf) {
++					__t4_set_led(wc, x, WC_OFF);
++				}
++#else
++				if (wc->blinktimer == 160) {
++					__t4_set_led(wc, x, WC_GREEN);
++				} else if (wc->blinktimer == 480) {
++					__t4_set_led(wc, x, WC_OFF);
++				}
++#endif
++			} else {
++				/* No Alarm */
++				__t4_set_led(wc, x, WC_GREEN);
++			}
++		}	else
++				__t4_set_led(wc, x, WC_OFF);
++
++	}
++#ifdef FANCY_ALARM
++	if (wc->blinktimer == 0xf) {
++		wc->blinktimer = -1;
++		wc->alarmpos++;
++		if (wc->alarmpos >= (sizeof(altab) / sizeof(altab[0])))
++			wc->alarmpos = 0;
++	}
++#else
++	if (wc->blinktimer == 480)
++		wc->blinktimer = 0;
++#endif
++}
++
++static inline void t4_framer_interrupt(struct t4 *wc, int span)
++{
++	unsigned char gis, isr0, isr1, isr2, isr3, isr4;
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++	/* Check interrupts for a given span */
++	unsigned char reg;
++#endif
++	int readsize = -1;
++	struct t4_span *ts = wc->tspans[span];
++	struct dahdi_chan *sigchan;
++	unsigned long flags;
++
++
++	/* 1st gen cards isn't used interrupts */
++	gis = t4_framer_in(wc, span, FRMR_GIS);
++	isr0 = (gis & FRMR_GIS_ISR0) ? t4_framer_in(wc, span, FRMR_ISR0) : 0;
++	isr1 = (gis & FRMR_GIS_ISR1) ? t4_framer_in(wc, span, FRMR_ISR1) : 0;
++	isr2 = (gis & FRMR_GIS_ISR2) ? t4_framer_in(wc, span, FRMR_ISR2) : 0;
++	isr3 = (gis & FRMR_GIS_ISR3) ? t4_framer_in(wc, span, FRMR_ISR3) : 0;
++	isr4 = (gis & FRMR_GIS_ISR4) ? t4_framer_in(wc, span, FRMR_ISR4) : 0;
++
++ 	if ((debug & DEBUG_FRAMER) && !(isr3 & ISR3_SEC)) {
++ 		dev_info(&wc->dev->dev, "gis: %02x, isr0: %02x, isr1: %02x, "\
++ 			"isr2: %02x, isr3: %08x, isr4: %02x, intcount=%u\n",
++ 			gis, isr0, isr1, isr2, isr3, isr4, wc->intcount);
++ 	}
++ 
++#if (defined(DAHDI_SPAN_OPS) || defined(DAHDI_SPAN_MODULE) )
++	/* Collect performance counters once per second */
++ 	if (isr3 & ISR3_SEC) {
++ 		ts->span.count.fe += t4_framer_in(wc, span, FECL_T);
++ 		ts->span.count.crc4 += t4_framer_in(wc, span, CEC1L_T);
++ 		ts->span.count.cv += t4_framer_in(wc, span, CVCL_T);
++ 		ts->span.count.ebit += t4_framer_in(wc, span, EBCL_T);
++ 		ts->span.count.be += t4_framer_in(wc, span, BECL_T);
++ 		ts->span.count.prbs = t4_framer_in(wc, span, FRS1_T);
++ 	}
++ 
++	/* Collect errored second counter once per second */
++ 	if (isr3 & ISR3_ES) {
++ 		ts->span.count.errsec += 1;
++ 	}
++ 
++ 	if (isr3 & 0x08) {
++ 		reg = t4_framer_in(wc, span, FRS1_T);
++		dev_info(&wc->dev->dev, "FRS1: %d\n", reg);
++ 		if (reg & LLBDD) {
++ 			dev_info(&wc->dev->dev, "Line loop-back activation "\
++ 					"signal detected with status: %01d "\
++ 					"for span %d\n", reg & LLBAD, span+1);
++ 		}
++ 	}
++#endif
++
++	if (isr0)
++		t4_check_sigbits(wc, span);
++
++	if (ts->spantype == TYPE_E1) {
++		/* E1 checks */
++		if ((isr3 & 0x38) || isr2 || isr1)
++			t4_check_alarms(wc, span);
++	} else {
++		/* T1 checks */
++		if (isr2 || (isr3 & 0x08))
++			t4_check_alarms(wc, span);
++	}
++	if (!ts->span.alarms) {
++		if ((isr3 & 0x3) || (isr4 & 0xc0))
++			ts->span.timingslips++;
++
++		if (debug & DEBUG_MAIN) {
++			if (isr3 & 0x02)
++				dev_notice(&wc->dev->dev, "opvxd115: RECEIVE "
++					"slip NEGATIVE on span %d\n",
++					span + 1);
++			if (isr3 & 0x01)
++				dev_notice(&wc->dev->dev, "opvxd115: RECEIVE "
++					"slip POSITIVE on span %d\n",
++					span + 1);
++			if (isr4 & 0x80)
++				dev_notice(&wc->dev->dev, "opvxd115: TRANSMIT "
++					"slip POSITIVE on span %d\n",
++					span + 1);
++			if (isr4 & 0x40)
++				dev_notice(&wc->dev->dev, "opvxd115: TRANSMIT "
++					"slip NEGATIVE on span %d\n",
++					span + 1);
++		}
++	} else
++		ts->span.timingslips = 0;
++
++	spin_lock_irqsave(&wc->reglock, flags);
++	/* HDLC controller checks - receive side */
++	if (!ts->sigchan) {
++		spin_unlock_irqrestore(&wc->reglock, flags);
++		return;
++	}
++
++	sigchan = ts->sigchan;
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	if (isr0 & FRMR_ISR0_RME) {
++		readsize = (t4_framer_in(wc, span, FRMR_RBCH) << 8) | t4_framer_in(wc, span, FRMR_RBCL);
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "Received data length is %d "
++				"(%d)\n", readsize,
++				readsize & FRMR_RBCL_MAX_SIZE);
++		/* RPF isn't set on last part of frame */
++		if ((readsize > 0) && ((readsize &= FRMR_RBCL_MAX_SIZE) == 0))
++			readsize = FRMR_RBCL_MAX_SIZE + 1;
++	} else if (isr0 & FRMR_ISR0_RPF)
++		readsize = FRMR_RBCL_MAX_SIZE + 1;
++
++	if (readsize > 0) {
++		int i;
++		unsigned char readbuf[FRMR_RBCL_MAX_SIZE + 1];
++
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "Framer %d: Got RPF/RME! "
++				"readsize is %d\n", sigchan->span->offset,
++				readsize);
++
++		for (i = 0; i < readsize; i++)
++			readbuf[i] = t4_framer_in(wc, span, FRMR_RXFIFO);
++
++		/* Tell the framer to clear the RFIFO */
++		t4_framer_cmd_wait(wc, span, FRMR_CMDR_RMC);
++
++		if (debug & DEBUG_FRAMER) {
++			dev_notice(&wc->dev->dev, "RX(");
++			for (i = 0; i < readsize; i++)
++				dev_notice(&wc->dev->dev, "%s%02x",
++					(i ? " " : ""), readbuf[i]);
++			dev_notice(&wc->dev->dev, ")\n");
++		}
++
++		if (isr0 & FRMR_ISR0_RME) {
++			/* Do checks for HDLC problems */
++			unsigned char rsis = readbuf[readsize-1];
++#if 0
++			unsigned int olddebug = debug;
++#endif
++			unsigned char rsis_reg = t4_framer_in(wc, span, FRMR_RSIS);
++
++#if 0
++			if ((rsis != 0xA2) || (rsis != rsis_reg))
++				debug |= DEBUG_FRAMER;
++#endif
++
++			++ts->frames_in;
++			if ((debug & DEBUG_FRAMER) && !(ts->frames_in & 0x0f))
++				dev_notice(&wc->dev->dev, "Received %d frames "
++					"on span %d\n", ts->frames_in, span);
++			if (debug & DEBUG_FRAMER)
++				dev_notice(&wc->dev->dev, "Received HDLC frame"
++					" %d.  RSIS = 0x%x (%x)\n",
++					ts->frames_in, rsis, rsis_reg);
++			if (!(rsis & FRMR_RSIS_CRC16)) {
++				if (debug & DEBUG_FRAMER)
++					dev_notice(&wc->dev->dev, "CRC check "
++							"failed %d\n", span);
++				dahdi_hdlc_abort(sigchan, DAHDI_EVENT_BADFCS);
++			} else if (rsis & FRMR_RSIS_RAB) {
++				if (debug & DEBUG_FRAMER)
++					dev_notice(&wc->dev->dev, "ABORT of "
++						"current frame due to "
++						"overflow %d\n", span);
++				dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT);
++			} else if (rsis & FRMR_RSIS_RDO) {
++				if (debug & DEBUG_FRAMER)
++					dev_notice(&wc->dev->dev, "HDLC "
++						"overflow occured %d\n",
++						span);
++				dahdi_hdlc_abort(sigchan, DAHDI_EVENT_OVERRUN);
++			} else if (!(rsis & FRMR_RSIS_VFR)) {
++				if (debug & DEBUG_FRAMER)
++					dev_notice(&wc->dev->dev, "Valid Frame"
++						" check failed on span %d\n",
++						span);
++				dahdi_hdlc_abort(sigchan, DAHDI_EVENT_ABORT);
++			} else {
++				dahdi_hdlc_putbuf(sigchan, readbuf, readsize - 1);
++				dahdi_hdlc_finish(sigchan);
++				if (debug & DEBUG_FRAMER)
++					dev_notice(&wc->dev->dev, "Received "
++						"valid HDLC frame on span %d"
++						"\n", span);
++			}
++#if 0
++			debug = olddebug;
++#endif
++		} else if (isr0 & FRMR_ISR0_RPF)
++			dahdi_hdlc_putbuf(sigchan, readbuf, readsize);
++	}
++
++	/* Transmit side */
++	if (isr1 & FRMR_ISR1_XDU) {
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "XDU: Resetting signal "
++					"controller!\n");
++		t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
++	} else if (isr1 & FRMR_ISR1_XPR) {
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "Sigchan %d is %p\n",
++					sigchan->chanpos, sigchan);
++
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "Framer %d: Got XPR!\n",
++					sigchan->span->offset);
++		t4_hdlc_xmit_fifo(wc, span, ts);
++	}
++
++	if (isr1 & FRMR_ISR1_ALLS) {
++		if (debug & DEBUG_FRAMER)
++			dev_notice(&wc->dev->dev, "ALLS received\n");
++	}
++}
++
++#ifdef SUPPORT_GEN1
++DAHDI_IRQ_HANDLER(t4_interrupt)
++{
++	struct t4 *wc = dev_id;
++	unsigned long flags;
++	int x;
++	
++	unsigned int status;
++	unsigned int status2;
++
++#if 0
++	if (wc->intcount < 20)
++		dev_notice(&wc->dev->dev, "Pre-interrupt\n");
++#endif
++	
++	/* Make sure it's really for us */
++	status = __t4_pci_in(wc, WC_INTR);
++
++	/* Process framer interrupts */
++	status2 = t4_framer_in(wc, 0, FRMR_CIS);
++	if (status2 & 0x0f) {
++		for (x = 0; x < wc->numspans; ++x) {
++			if (status2 & (1 << x))
++				t4_framer_interrupt(wc, x);
++		}
++	}
++
++	/* Ignore if it's not for us */
++	if (!status)
++		return IRQ_NONE;
++
++	__t4_pci_out(wc, WC_INTR, 0);
++
++	if (!wc->spansstarted) {
++		dev_notice(&wc->dev->dev, "Not prepped yet!\n");
++		return IRQ_NONE;
++	}
++
++	wc->intcount++;
++#if 0
++	if (wc->intcount < 20)
++		dev_notice(&wc->dev->dev, "Got interrupt, status = %08x\n",
++				status);
++#endif		
++
++	if (status & 0x3) {
++		t4_receiveprep(wc, status);
++		t4_transmitprep(wc, status);
++	}
++	
++#if 0
++	if ((wc->intcount < 10) || !(wc->intcount % 1000)) {
++		status2 = t4_framer_in(wc, 0, FRMR_CIS);
++		dev_notice(&wc->dev->dev, "Status2: %04x\n", status2);
++		for (x = 0;x<wc->numspans;x++) {
++			status2 = t4_framer_in(wc, x, FRMR_FRS0);
++			dev_notice(&wc->dev->dev, "FRS0/%d: %04x\n", x,
++					status2);
++		}
++	}
++#endif
++	t4_do_counters(wc);
++
++	x = wc->intcount & 15 /* 63 */;
++	switch(x) {
++	case 0:
++	case 1:
++	case 2:
++	case 3:
++		t4_check_sigbits(wc, x);
++		break;
++	case 4:
++	case 5:
++	case 6:
++	case 7:
++		t4_check_alarms(wc, x - 4);
++		break;
++	}
++
++	spin_lock_irqsave(&wc->reglock, flags);
++
++	__handle_leds(wc);
++
++	if (test_bit(T4_CHECK_TIMING, &wc->checkflag))
++		__t4_set_timing_source_auto(wc);
++
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	return IRQ_RETVAL(1);
++}
++#endif
++
++static int t4_allocate_buffers(struct t4 *wc, int numbufs, volatile unsigned int **oldalloc, dma_addr_t *oldwritedma)
++{
++	volatile unsigned int *alloc;
++	dma_addr_t writedma;
++
++	alloc =
++		/* 32 channels, Double-buffer, Read/Write, 4 spans */
++		(unsigned int *)pci_alloc_consistent(wc->dev, numbufs * T4_BASE_SIZE * 2, &writedma);
++
++	if (!alloc) {
++		dev_notice(&wc->dev->dev, "wct%dxxp: Unable to allocate "
++				"DMA-able memory\n", wc->numspans);
++		return -ENOMEM;
++	}
++
++	if (oldwritedma)
++		*oldwritedma = wc->writedma;
++	if (oldalloc)
++		*oldalloc = wc->writechunk;
++
++	wc->writechunk = alloc;
++	wc->writedma = writedma;
++
++	/* Read is after the whole write piece (in words) */
++	wc->readchunk = wc->writechunk + (T4_BASE_SIZE * numbufs) / 4;
++	
++	/* Same thing but in bytes...  */
++	wc->readdma = wc->writedma + (T4_BASE_SIZE * numbufs);
++
++	wc->numbufs = numbufs;
++	
++	/* Initialize Write/Buffers to all blank data */
++	memset((void *)wc->writechunk,0x00, T4_BASE_SIZE * numbufs);
++	memset((void *)wc->readchunk,0xff, T4_BASE_SIZE * numbufs);
++
++	dev_notice(&wc->dev->dev, "DMA memory base of size %d at %p.  Read: "
++		"%p and Write %p\n", numbufs * T4_BASE_SIZE * 2,
++		wc->writechunk, wc->readchunk, wc->writechunk);
++
++	return 0;
++}
++
++static void t4_increase_latency(struct t4 *wc, int newlatency)
++{
++	unsigned long flags;
++	volatile unsigned int *oldalloc;
++	dma_addr_t oldaddr;
++	int oldbufs;
++
++	spin_lock_irqsave(&wc->reglock, flags);
++
++	__t4_pci_out(wc, WC_DMACTRL, 0x00000000);
++	/* Acknowledge any pending interrupts */
++	__t4_pci_out(wc, WC_INTR, 0x00000000);
++
++	__t4_pci_in(wc, WC_VERSION);
++
++	oldbufs = wc->numbufs;
++
++	if (t4_allocate_buffers(wc, newlatency, &oldalloc, &oldaddr)) {
++		dev_info(&wc->dev->dev, "Error allocating latency buffers for "
++				"latency of %d\n", newlatency);
++		__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++		spin_unlock_irqrestore(&wc->reglock, flags);
++		return;
++	}
++
++	__t4_pci_out(wc, WC_RDADDR, wc->readdma);
++	__t4_pci_out(wc, WC_WRADDR, wc->writedma);
++
++	__t4_pci_in(wc, WC_VERSION);
++
++	__t4_pci_out(wc, 5, (ms_per_irq << 16) | newlatency);
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++
++	__t4_pci_in(wc, WC_VERSION);
++
++	wc->rxident = 0;
++	wc->lastindex = 0;
++
++	spin_unlock_irqrestore(&wc->reglock, flags);
++
++	pci_free_consistent(wc->dev, T4_BASE_SIZE * oldbufs * 2, (void *)oldalloc, oldaddr);
++
++	dev_info(&wc->dev->dev, "Increased latency to %d\n", newlatency);
++
++}
++
++static void t4_isr_bh(unsigned long data)
++{
++	struct t4 *wc = (struct t4 *)data;
++
++	if (test_bit(T4_CHANGE_LATENCY, &wc->checkflag)) {
++		if (wc->needed_latency != wc->numbufs) {
++			t4_increase_latency(wc, wc->needed_latency);
++			clear_bit(T4_CHANGE_LATENCY, &wc->checkflag);
++		}
++	}
++#ifdef VPM_SUPPORT
++	if (wc->vpm) {
++		if (test_and_clear_bit(T4_CHECK_VPM, &wc->checkflag)) {
++			if (wc->vpm450m) {
++				/* How stupid is it that the octasic can't generate an
++				   interrupt when there's a tone, in spite of what their
++				   documentation says? */
++				t4_check_vpm450(wc);
++			} else
++				t4_check_vpm400(wc, wc->vpm400checkstatus);
++		}
++	}
++#endif
++}
++
++DAHDI_IRQ_HANDLER(t4_interrupt_gen2)
++{
++	struct t4 *wc = dev_id;
++	unsigned int status;
++	unsigned char rxident, expected;
++	
++	/* Check this first in case we get a spurious interrupt */
++	if (unlikely(test_bit(T4_STOP_DMA, &wc->checkflag))) {
++		/* Stop DMA cleanly if requested */
++		wc->dmactrl = 0x0;
++		t4_pci_out(wc, WC_DMACTRL, 0x00000000);
++		/* Acknowledge any pending interrupts */
++		t4_pci_out(wc, WC_INTR, 0x00000000);
++		spin_lock(&wc->reglock);
++		__t4_set_sclk_src(wc, WC_SELF, 0, 0);
++		spin_unlock(&wc->reglock);
++		return IRQ_RETVAL(1);
++	}
++
++	/* Make sure it's really for us */
++	status = __t4_pci_in(wc, WC_INTR);
++
++	/* Ignore if it's not for us */
++	if (!(status & 0x7)) {
++		return IRQ_NONE;
++	}
++
++#ifdef ENABLE_WORKQUEUES
++	__t4_pci_out(wc, WC_INTR, status & 0x00000008);
++#endif
++
++	if (unlikely(!wc->spansstarted)) {
++		dev_info(&wc->dev->dev, "Not prepped yet!\n");
++		return IRQ_NONE;
++	}
++
++	wc->intcount++;
++
++	if ((wc->flags & FLAG_5THGEN) && (status & 0x2)) {
++		rxident = (status >> 16) & 0x7f;
++		expected = (wc->rxident + ms_per_irq) % 128;
++	
++		if ((rxident != expected) && !test_bit(T4_IGNORE_LATENCY, &wc->checkflag)) {
++			int needed_latency;
++			int smallest_max;
++
++			if (debug & DEBUG_MAIN)
++				dev_warn(&wc->dev->dev, "Missed interrupt.  "
++					"Expected ident of %d and got ident "
++					"of %d\n", expected, rxident);
++
++			if (test_bit(T4_IGNORE_LATENCY, &wc->checkflag)) {
++				dev_info(&wc->dev->dev,
++					"Should have ignored latency\n");
++			}
++			if (rxident > wc->rxident) {
++				needed_latency = rxident - wc->rxident;
++			} else {
++				needed_latency = (128 - wc->rxident) + rxident;
++			}
++
++			needed_latency += 1;
++
++			smallest_max = (max_latency >= GEN5_MAX_LATENCY) ? GEN5_MAX_LATENCY : max_latency;
++
++			if (needed_latency > smallest_max) {
++				dev_info(&wc->dev->dev, "Truncating latency "
++					"request to %d instead of %d\n",
++					smallest_max, needed_latency);
++				needed_latency = smallest_max;
++			}
++
++			if (needed_latency > wc->numbufs) {
++				int x;
++
++				dev_info(&wc->dev->dev, "Need to increase "
++					"latency.  Estimated latency should "
++					"be %d\n", needed_latency);
++				for (x = 0; x < wc->numspans; x++)
++					wc->tspans[x]->span.irqmisses++;
++				wc->needed_latency = needed_latency;
++				__t4_pci_out(wc, WC_DMACTRL, 0x00000000);
++				set_bit(T4_CHANGE_LATENCY, &wc->checkflag);
++				goto out;
++			}
++		}
++	
++		wc->rxident = rxident;
++	}
++
++	if (unlikely((wc->intcount < 20)))
++
++		dev_info(&wc->dev->dev, "2G: Got interrupt, status = %08x, "
++			"CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS));
++
++	if (likely(status & 0x2)) {
++#ifdef ENABLE_WORKQUEUES
++		int cpus = num_online_cpus();
++		atomic_set(&wc->worklist, wc->numspans);
++		if (wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)
++			t4_queue_work(wc->workq, &wc->tspans[0]->swork, 0);
++		else
++			atomic_dec(&wc->worklist);
++#else
++#if 1
++		unsigned int reg5 = __t4_pci_in(wc, 5);
++		if (wc->intcount < 20) {
++
++			dev_info(&wc->dev->dev, "Reg 5 is %08x\n", reg5);
++		}
++#endif
++
++		if (wc->flags & FLAG_5THGEN) {
++			unsigned int current_index = (reg5 >> 8) & 0x7f;
++
++			while (((wc->lastindex + 1) % wc->numbufs) != current_index) {
++				wc->lastindex = (wc->lastindex + 1) % wc->numbufs;
++				setup_chunks(wc, wc->lastindex);
++				t4_prep_gen2(wc);
++			}
++		} else {
++			t4_prep_gen2(wc);
++		}
++
++#endif
++		t4_do_counters(wc);
++		spin_lock(&wc->reglock);
++		__handle_leds(wc);
++		spin_unlock(&wc->reglock);
++
++	}
++
++	if (unlikely(status & 0x1)) {
++		unsigned char cis;
++
++		cis = t4_framer_in(wc, 0, FRMR_CIS);
++		if (cis & FRMR_CIS_GIS1)
++			t4_framer_interrupt(wc, 0);
++		if (cis & FRMR_CIS_GIS2)
++			t4_framer_interrupt(wc, 1);
++		if (cis & FRMR_CIS_GIS3)
++			t4_framer_interrupt(wc, 2);
++		if (cis & FRMR_CIS_GIS4)
++			t4_framer_interrupt(wc, 3);
++	}
++
++	if (wc->vpm && vpmdtmfsupport) {
++		if (wc->vpm450m) {
++			/* How stupid is it that the octasic can't generate an
++			   interrupt when there's a tone, in spite of what their
++			   documentation says? */
++			if (!(wc->intcount & 0xf)) {
++				set_bit(T4_CHECK_VPM, &wc->checkflag);
++			}
++		} else if ((status & 0xff00) != 0xff00) {
++			wc->vpm400checkstatus = (status & 0xff00) >> 8;
++			set_bit(T4_CHECK_VPM, &wc->checkflag);
++		}
++	}
++
++	spin_lock(&wc->reglock);
++
++	if (unlikely(test_bit(T4_CHECK_TIMING, &wc->checkflag))) {
++		__t4_set_timing_source_auto(wc);
++	}
++
++	spin_unlock(&wc->reglock);
++
++out:
++	if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag) || test_bit(T4_CHECK_VPM, &wc->checkflag)))
++		tasklet_schedule(&wc->t4_tlet);
++
++#ifndef ENABLE_WORKQUEUES
++	__t4_pci_out(wc, WC_INTR, 0);
++#endif	
++
++	return IRQ_RETVAL(1);
++}
++
++#ifdef SUPPORT_GEN1
++static int t4_reset_dma(struct t4 *wc)
++{
++	/* Turn off DMA and such */
++	wc->dmactrl = 0x0;
++	t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	t4_pci_out(wc, WC_COUNT, 0);
++	t4_pci_out(wc, WC_RDADDR, 0);
++	t4_pci_out(wc, WC_WRADDR, 0);
++	t4_pci_out(wc, WC_INTR, 0);
++	/* Turn it all back on */
++	t4_pci_out(wc, WC_RDADDR, wc->readdma);
++	t4_pci_out(wc, WC_WRADDR, wc->writedma);
++	t4_pci_out(wc, WC_COUNT, ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 2));
++	t4_pci_out(wc, WC_INTR, 0);
++#ifdef VPM_SUPPORT
++	wc->dmactrl = 0xc0000000 | (1 << 29) | wc->vpm;
++#else	
++	wc->dmactrl = 0xc0000000 | (1 << 29);
++#endif
++	if (noburst)
++		wc->dmactrl |= (1 << 26);
++	t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	return 0;
++}
++#endif
++
++#ifdef VPM_SUPPORT
++static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold)
++{
++	unsigned int x;
++
++	for (x = 0; x < 8; x++) {
++		t4_vpm_out(wc, x, 0xC4, (threshold >> 8) & 0xFF);
++		t4_vpm_out(wc, x, 0xC5, (threshold & 0xFF));
++	}
++	dev_info(&wc->dev->dev, "VPM: DTMF threshold set to %d\n", threshold);
++}
++
++static unsigned int t4_vpm_mask(int chip)
++{
++	unsigned int mask=0;
++	switch(vpmspans) {
++	case 4:
++		mask = 0x55555555 << (chip >> 2);
++		break;
++	case 2:
++		mask = 0x11111111 << (chip >> 1);
++		break;
++	case 1:
++		mask = 0x01010101 << chip;
++		break;
++	}
++	return mask;
++}
++
++static int t4_vpm_spanno(int chip)
++{
++	int spanno = 0;
++	switch(vpmspans) {
++	case 4:
++		spanno = chip & 0x3;
++		break;
++	case 2:
++		spanno = chip & 0x1;
++		break;
++	/* Case 1 is implicit */
++	}
++	return spanno;
++}
++
++static int t4_vpm_echotail(void)
++{
++	int echotail = 0x01ff;
++	switch(vpmspans) {
++	case 4:
++		echotail = 0x007f;
++		break;
++	case 2:
++		echotail = 0x00ff;
++		break;
++	/* Case 1 is implicit */
++	}
++	return echotail;
++}
++
++static void t4_vpm450_init(struct t4 *wc)
++{
++	unsigned int check1, check2;
++	int laws[1] = { 0, };
++	int x;
++	unsigned int vpm_capacity;
++	struct firmware embedded_firmware;
++	const struct firmware *firmware = &embedded_firmware;
++#if !defined(HOTPLUG_FIRMWARE)
++	extern void _binary_dahdi_fw_oct6114_032_bin_size;
++	extern void _binary_dahdi_fw_oct6114_064_bin_size;
++	extern void _binary_dahdi_fw_oct6114_128_bin_size;
++	extern u8 _binary_dahdi_fw_oct6114_032_bin_start[];
++	extern u8 _binary_dahdi_fw_oct6114_064_bin_start[];
++	extern u8 _binary_dahdi_fw_oct6114_128_bin_start[];
++#else
++	static const char oct032_firmware[] = "dahdi-fw-oct6114-032.bin";
++	static const char oct064_firmware[] = "dahdi-fw-oct6114-064.bin";
++	static const char oct128_firmware[] = "dahdi-fw-oct6114-128.bin";
++#endif
++
++	if (!vpmsupport) {
++		dev_info(&wc->dev->dev, "VPM450: Support Disabled\n");
++		return;
++	}
++
++	/* Turn on GPIO/DATA mux if supported */
++	t4_gpio_setdir(wc, (1 << 24), (1 << 24));
++	__t4_raw_oct_out(wc, 0x000a, 0x5678);
++	__t4_raw_oct_out(wc, 0x0004, 0x1234);
++	check1 = __t4_raw_oct_in(wc, 0x0004);
++	check2 = __t4_raw_oct_in(wc, 0x000a);
++	if (debug)
++		dev_notice(&wc->dev->dev, "OCT Result: %04x/%04x\n",
++			__t4_raw_oct_in(wc, 0x0004),
++			__t4_raw_oct_in(wc, 0x000a));
++	if (__t4_raw_oct_in(wc, 0x0004) != 0x1234) {
++		dev_notice(&wc->dev->dev, "VPM450: Not Present\n");
++		return;
++	}
++
++	/* Setup alaw vs ulaw rules */
++	for (x = 0;x < wc->numspans; x++) {
++		if (wc->tspans[x]->span.channels > 24)
++			laws[x] = 1;
++	}
++
++	switch ((vpm_capacity = get_vpm450m_capacity(wc))) {
++	case 32:
++#if defined(HOTPLUG_FIRMWARE)
++		if ((request_firmware(&firmware, oct032_firmware, &wc->dev->dev) != 0) ||
++		    !firmware) {
++			dev_notice(&wc->dev->dev, "VPM450: firmware %s not "
++				"available from userspace\n", oct032_firmware);
++			return;
++		}
++#else
++		embedded_firmware.data = _binary_dahdi_fw_oct6114_032_bin_start;
++		/* Yes... this is weird. objcopy gives us a symbol containing
++		   the size of the firmware, not a pointer a variable containing
++		   the size. The only way we can get the value of the symbol
++		   is to take its address, so we define it as a pointer and
++		   then cast that value to the proper type.
++	      */
++		embedded_firmware.size = (size_t) &_binary_dahdi_fw_oct6114_032_bin_size;
++#endif
++		break;
++	case 64:
++#if defined(HOTPLUG_FIRMWARE)
++		if ((request_firmware(&firmware, oct064_firmware, &wc->dev->dev) != 0) ||
++		    !firmware) {
++			dev_notice(&wc->dev->dev, "VPM450: firmware %s not "
++				"available from userspace\n", oct064_firmware);
++			return;
++		}
++#else
++		embedded_firmware.data = _binary_dahdi_fw_oct6114_064_bin_start;
++		/* Yes... this is weird. objcopy gives us a symbol containing
++		   the size of the firmware, not a pointer a variable containing
++		   the size. The only way we can get the value of the symbol
++		   is to take its address, so we define it as a pointer and
++		   then cast that value to the proper type.
++	      */
++		embedded_firmware.size = (size_t) &_binary_dahdi_fw_oct6114_064_bin_size;
++#endif
++		break;
++	case 128:
++#if defined(HOTPLUG_FIRMWARE)
++		if ((request_firmware(&firmware, oct128_firmware, &wc->dev->dev) != 0) ||
++		    !firmware) {
++			dev_notice(&wc->dev->dev, "VPM450: firmware %s not "
++				"available from userspace\n", oct128_firmware);
++			return;
++		}
++#else
++		embedded_firmware.data = _binary_dahdi_fw_oct6114_128_bin_start;
++		/* Yes... this is weird. objcopy gives us a symbol containing
++		   the size of the firmware, not a pointer a variable containing
++		   the size. The only way we can get the value of the symbol
++		   is to take its address, so we define it as a pointer and
++		   then cast that value to the proper type.
++		*/
++		embedded_firmware.size = (size_t) &_binary_dahdi_fw_oct6114_128_bin_size;
++#endif
++		break;
++	default:
++		dev_notice(&wc->dev->dev, "Unsupported channel capacity found "
++				"on VPM module (%d).\n", vpm_capacity);
++		return;
++	}
++
++	if (!(wc->vpm450m = init_vpm450m(wc, laws, wc->numspans, firmware))) {
++		dev_notice(&wc->dev->dev, "VPM450: Failed to initialize\n");
++		if (firmware != &embedded_firmware)
++			release_firmware(firmware);
++		return;
++	}
++
++	if (firmware != &embedded_firmware)
++		release_firmware(firmware);
++
++	if (vpmdtmfsupport == -1) {
++		dev_notice(&wc->dev->dev, "VPM450: hardware DTMF disabled.\n");
++		vpmdtmfsupport = 0;
++	}
++
++	wc->vpm = T4_VPM_PRESENT;
++	dev_info(&wc->dev->dev, "VPM450: Present and operational servicing %d "
++			"span(s)\n", wc->numspans);
++		
++}
++
++static void t4_vpm400_init(struct t4 *wc)
++{
++	unsigned char reg;
++	unsigned int mask;
++	unsigned int ver;
++	unsigned int i, x, y, gen2vpm=0;
++
++	if (!vpmsupport) {
++		dev_info(&wc->dev->dev, "VPM400: Support Disabled\n");
++		return;
++	}
++
++	switch(vpmspans) {
++	case 4:
++	case 2:
++	case 1:
++		break;
++	default:
++		dev_notice(&wc->dev->dev, "VPM400: %d is not a valid vpmspans "
++				"value, using 4\n", vpmspans);
++		vpmspans = 1;
++	}
++
++	for (x=0;x<8;x++) {
++		int spanno = t4_vpm_spanno(x);
++		struct t4_span *ts = wc->tspans[spanno];
++		int echotail = t4_vpm_echotail();
++
++		ver = t4_vpm_in(wc, x, 0x1a0); /* revision */
++		if ((ver != 0x26) && (ver != 0x33)) {
++			if (x)
++				dev_notice(&wc->dev->dev,
++					"VPM400: Inoperable\n");
++			return;
++		}
++		if (ver == 0x33) {
++			if (x && !gen2vpm) {
++				dev_notice(&wc->dev->dev,
++					"VPM400: Inconsistent\n");
++				return;
++			}
++			ts->spanflags |= FLAG_VPM2GEN;
++			gen2vpm++;
++		} else if (gen2vpm) {
++			dev_notice(&wc->dev->dev,
++				"VPM400: Inconsistent\n");
++			return;
++		}
++
++
++		/* Setup GPIO's */
++		for (y=0;y<4;y++) {
++			t4_vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
++			t4_vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
++			t4_vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
++		}
++
++		/* Setup TDM path - sets fsync and tdm_clk as inputs */
++		reg = t4_vpm_in(wc, x, 0x1a3); /* misc_con */
++		t4_vpm_out(wc, x, 0x1a3, reg & ~2);
++
++		/* Setup timeslots */
++		t4_vpm_out(wc, x, 0x02f, 0x20 | (spanno << 3)); 
++
++		/* Setup Echo length (128 taps) */
++		t4_vpm_out(wc, x, 0x022, (echotail >> 8));
++		t4_vpm_out(wc, x, 0x023, (echotail & 0xff));
++		
++		/* Setup the tdm channel masks for all chips*/
++		mask = t4_vpm_mask(x);
++		for (i = 0; i < 4; i++)
++			t4_vpm_out(wc, x, 0x30 + i, (mask >> (i << 3)) & 0xff);
++
++		/* Setup convergence rate */
++		reg = t4_vpm_in(wc,x,0x20);
++		reg &= 0xE0;
++		if (ts->spantype == TYPE_E1) {
++			if (x < vpmspans)
++				dev_info(&wc->dev->dev, "VPM400: Span %d "
++						"A-law mode\n", spanno);
++			reg |= 0x01;
++		} else {
++			if (x < vpmspans)
++				dev_info(&wc->dev->dev, "VPM400: Span %d "
++						"U-law mode\n", spanno);
++			reg &= ~0x01;
++		}
++		t4_vpm_out(wc,x,0x20,(reg | 0x20));
++		
++		/* Initialize echo cans */
++		for (i = 0 ; i < MAX_TDM_CHAN; i++) {
++			if (mask & (0x00000001 << i))
++				t4_vpm_out(wc,x,i,0x00);
++		}
++
++		wait_a_little();
++
++		/* Put in bypass mode */
++		for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
++			if (mask & (0x00000001 << i)) {
++				t4_vpm_out(wc,x,i,0x01);
++			}
++		}
++
++		/* Enable bypass */
++		for (i = 0 ; i < MAX_TDM_CHAN ; i++) {
++			if (mask & (0x00000001 << i))
++				t4_vpm_out(wc,x,0x78 + i,0x01);
++		}
++      
++		/* set DTMF detection threshold */
++		t4_vpm_set_dtmf_threshold(wc, dtmfthreshold);
++
++		/* Enable DTMF detectors (always DTMF detect all spans) */
++		for (i = 0; i < MAX_DTMF_DET; i++) {
++			t4_vpm_out(wc, x, 0x98 + i, 0x40 | (i * 2) | ((x < 4) ? 0 : 1));
++		}
++		for (i = 0x34; i < 0x38; i++)
++			t4_vpm_out(wc, x, i, 0x00);
++		for (i = 0x3C; i < 0x40; i++)
++			t4_vpm_out(wc, x, i, 0x00);
++
++		for (i = 0x48; i < 0x4B; i++)
++			t4_vpm_out(wc, x, i, 0x00);
++		for (i = 0x50; i < 0x53; i++)
++			t4_vpm_out(wc, x, i, 0x00);
++		for (i = 0xB8; i < 0xBE; i++)
++			t4_vpm_out(wc, x, i, 0xFF);
++		if (gen2vpm) {
++			for (i = 0xBE; i < 0xC0; i++)
++				t4_vpm_out(wc, x, i, 0xFF);
++		} else {
++			for (i = 0xBE; i < 0xC0; i++)
++				t4_vpm_out(wc, x, i, 0x00);
++		}
++		for (i = 0xC0; i < 0xC4; i++)
++			t4_vpm_out(wc, x, i, (x < 4) ? 0x55 : 0xAA);
++
++	} 
++	if (vpmdtmfsupport == -1) {
++		dev_info(&wc->dev->dev, "VPM400: hardware DTMF enabled.\n");
++		vpmdtmfsupport = 0;
++	}
++	dev_info(&wc->dev->dev, "VPM400%s: Present and operational servicing "
++		"%d span(s)\n", (gen2vpm ? " (2nd Gen)" : ""), wc->numspans);
++	wc->vpm = T4_VPM_PRESENT;
++}
++
++#endif
++
++static void t4_tsi_reset(struct t4 *wc) 
++{
++	int x;
++	for (x=0;x<128;x++) {
++		wc->dmactrl &= ~0x00007fff;
++		wc->dmactrl |= (0x00004000 | (x << 7));
++		t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	}
++	wc->dmactrl &= ~0x00007fff;
++	t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++}
++
++/* Note that channels here start from 1 */
++static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan)
++{
++	unsigned long flags;
++	int fromts, tots;
++
++	fromts = (fromspan << 5) |(fromchan);
++	tots = (tospan << 5) | (tochan);
++
++	if (!wc->t1e1) {
++		fromts += 4;
++		tots += 4;
++	}
++	spin_lock_irqsave(&wc->reglock, flags);
++	wc->dmactrl &= ~0x00007fff;
++	wc->dmactrl |= (0x00004000 | (tots << 7) | (fromts));
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	wc->dmactrl &= ~0x00007fff;
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++
++static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan)
++{
++	unsigned long flags;
++	int tots;
++
++	tots = (tospan << 5) | (tochan);
++
++	if (!wc->t1e1) 
++		tots += 4;
++	spin_lock_irqsave(&wc->reglock, flags);
++	wc->dmactrl &= ~0x00007fff;
++	wc->dmactrl |= (0x00004000 | (tots << 7));
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	if (debug & DEBUG_TSI)
++		dev_notice(&wc->dev->dev, "Sending '%08x\n", wc->dmactrl);
++	wc->dmactrl &= ~0x00007fff;
++	__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++}
++#ifdef CONFIG_EXTENDED_RESET
++static void t4_extended_reset(struct t4 *wc)
++{
++	unsigned int oldreg = t4_pci_in(wc, 0x4);
++
++	udelay(1000);
++
++	t4_pci_out(wc, 0x4, 0x42000000);
++	t4_pci_out(wc, 0xa, 0x42000000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0xa, 0x00080000);
++	t4_pci_out(wc, 0xa, 0x00180000);
++	t4_pci_out(wc, 0x4, oldreg);
++
++	udelay(1000);
++}
++#endif
++
++static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
++{
++	unsigned int version;
++
++	version = t4_pci_in(wc, WC_VERSION);
++	dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version);
++	dev_info(&wc->dev->dev, "Burst Mode: %s\n",
++		(!(cardflags & FLAG_BURST) && noburst) ? "Off" : "On");
++#ifdef ENABLE_WORKQUEUES
++	dev_info(&wc->dev->dev, "Work Queues: Enabled\n");
++#endif
++
++#ifdef CONFIG_EXTENDED_RESET
++	t4_extended_reset(wc);
++#endif
++
++	/* Make sure DMA engine is not running and interrupts are acknowledged */
++	wc->dmactrl = 0x0;
++	t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
++	/* Reset Framer and friends */
++	t4_pci_out(wc, WC_LEDS, 0x00000000);
++
++	/* Set DMA addresses */
++	t4_pci_out(wc, WC_RDADDR, wc->readdma);
++	t4_pci_out(wc, WC_WRADDR, wc->writedma);
++
++	/* Setup counters, interrupt flags (ignored in Gen2) */
++	if (cardflags & FLAG_2NDGEN) {
++		t4_tsi_reset(wc);
++	} else {
++		t4_pci_out(wc, WC_COUNT, ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 18) | ((DAHDI_MAX_CHUNKSIZE * 2 * 32 - 1) << 2));
++	}
++	
++	/* Reset pending interrupts */
++	t4_pci_out(wc, WC_INTR, 0x00000000);
++
++	/* Read T1/E1 status */
++	if (t1e1override > -1)
++		wc->t1e1 = t1e1override;
++	else
++		wc->t1e1 = ((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8;
++	wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28;
++	order_index[wc->order]++;
++	return 0;
++}
++
++static int t4_hardware_init_2(struct t4 *wc)
++{
++	int x;
++	unsigned int regval;
++
++	if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) {
++		wc->tspans[0]->spanflags |= FLAG_OCTOPT;
++		dev_info(&wc->dev->dev, "Octasic Optimizations: Enabled\n");
++	}
++	/* Setup LEDS, take out of reset */
++	t4_pci_out(wc, WC_LEDS, 0x000000ff);
++	t4_activate(wc);
++
++	/* 
++	 * In order to find out the QFALC framer version, we have to temporarily term off compat
++	 * mode and take a peak at VSTR.  We turn compat back on when we are done.
++	 */
++	if (t4_framer_in(wc, 0, 0x4a) != 0x05)
++		dev_info(&wc->dev->dev, "WARNING: FALC framer not intialized "
++				"in compatibility mode.\n");
++	regval = t4_framer_in(wc, 0 ,0xd6);
++	regval |= (1 << 5); /* set COMP_DIS*/
++	t4_framer_out(wc, 0, 0xd6, regval);
++	regval = t4_framer_in(wc, 0, 0x4a);
++	if (regval == 0x05)
++		dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or "
++				"earlier\n");
++	else if (regval == 0x20) {
++		dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n");
++		wc->falc31 = 1;
++	} else
++		dev_info(&wc->dev->dev, "FALC Framer Version: Unknown "
++				"(VSTR = 0x%02x)\n", regval);
++	regval = t4_framer_in(wc, 0 ,0xd6);
++	regval &= ~(1 << 5); /* clear COMP_DIS*/
++	t4_framer_out(wc, 0, 0xd6, regval);
++	
++	t4_framer_out(wc, 0, 0x4a, 0xaa);
++	dev_info(&wc->dev->dev, "Board ID: %02x\n", wc->order);
++
++	for (x=0;x< 11;x++)
++		dev_info(&wc->dev->dev, "Reg %d: 0x%08x\n", x,
++				t4_pci_in(wc, x));
++	return 0;
++}
++
++static int __devinit t4_launch(struct t4 *wc)
++{
++	int x;
++	unsigned long flags;
++	if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags))
++		return 0;
++	dev_info(&wc->dev->dev, "opvxd115: Launching card: %d\n",
++			wc->order);
++
++	/* Setup serial parameters and system interface */
++	for (x=0;x<PORTS_PER_FRAMER;x++)
++		t4_serial_setup(wc, x);
++
++	if (dahdi_register(&wc->tspans[0]->span, 0)) {
++		dev_err(&wc->dev->dev, "Unable to register span %s\n",
++				wc->tspans[0]->span.name);
++		return -1;
++	}
++	set_bit(T4_CHECK_TIMING, &wc->checkflag);
++	spin_lock_irqsave(&wc->reglock, flags);
++	__t4_set_sclk_src(wc, WC_SELF, 0, 0);
++	spin_unlock_irqrestore(&wc->reglock, flags);
++	tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
++	return 0;
++}
++
++static void free_wc(struct t4 *wc)
++{
++	unsigned int x, y;
++
++	for (x = 0; x < sizeof(wc->tspans)/sizeof(wc->tspans[0]); x++) {
++		if (!wc->tspans[x]) {
++			continue;
++		}
++
++		for (y = 0; y < sizeof(wc->tspans[x]->chans)/sizeof(wc->tspans[x]->chans[0]); y++) {
++			if (wc->tspans[x]->chans[y]) {
++				kfree(wc->tspans[x]->chans[y]);
++			}
++			if (wc->tspans[x]->ec[y])
++				kfree(wc->tspans[x]->ec[y]);
++		}
++		kfree(wc->tspans[x]);
++	}
++	kfree(wc);
++}
++
++static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
++{
++	struct t4 *wc;
++	struct devtype *dt;
++	unsigned int x, f;
++	int init_latency;
++	
++	if (pci_enable_device(pdev)) {
++		return -EIO;
++	}
++
++	if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) {
++		return -ENOMEM;
++	}
++
++	memset(wc, 0x0, sizeof(*wc));
++	spin_lock_init(&wc->reglock);
++	dt = (struct devtype *) (ent->driver_data);
++
++	wc->flags = dt->flags;
++
++	wc->numspans = 1;
++	
++	wc->variety = dt->desc;
++	
++	wc->memaddr = pci_resource_start(pdev, 0);
++	wc->memlen = pci_resource_len(pdev, 0);
++	wc->membase = ioremap(wc->memaddr, wc->memlen);
++	/* This rids of the Double missed interrupt message after loading */
++	wc->last0 = 1;
++#if 0
++	if (!request_mem_region(wc->memaddr, wc->memlen, wc->variety))
++		dev_info(&wc->dev->dev, "opvxd115: Unable to request memory "
++				"region :(, using anyway...\n");
++#endif
++	if (pci_request_regions(pdev, wc->variety))
++		dev_info(&pdev->dev, "opvxd115: Unable to request regions\n");
++	
++	dev_info(&pdev->dev, "Found opvxd115 at base address %08lx, remapped "
++			"to %p\n", wc->memaddr, wc->membase);
++	
++	wc->dev = pdev;
++	
++	/* Enable bus mastering */
++	pci_set_master(pdev);
++
++	/* Keep track of which device we are */
++	pci_set_drvdata(pdev, wc);
++
++	if (wc->flags & FLAG_5THGEN) {
++		if ((ms_per_irq > 1) && (latency <= ((ms_per_irq) << 1))) {
++			init_latency = ms_per_irq << 1;
++		} else {
++			if (latency > 2)
++				init_latency = latency;
++			else
++				init_latency = 2;
++		}
++		dev_info(&wc->dev->dev, "5th gen card with initial latency of "
++			"%d and %d ms per IRQ\n", init_latency, ms_per_irq);
++	} else {
++		if (wc->flags & FLAG_2NDGEN)
++			init_latency = 1;
++		else
++			init_latency = 2;
++	}
++
++	if (max_latency < init_latency) {
++		printk(KERN_INFO "maxlatency must be set to something greater than %d ms, increasing it to %d\n", init_latency, init_latency);
++		max_latency = init_latency;
++	}
++	
++	if (t4_allocate_buffers(wc, init_latency, NULL, NULL)) {
++		return -ENOMEM;
++	}
++
++	/* Initialize hardware */
++	t4_hardware_init_1(wc, wc->flags);
++	
++	for(x = 0; x < MAX_T4_CARDS; x++) {
++		if (!cards[x])
++			break;
++	}
++	
++	if (x >= MAX_T4_CARDS) {
++		dev_notice(&wc->dev->dev, "No cards[] slot available!!\n");
++		kfree(wc);
++		return -ENOMEM;
++	}
++	
++	wc->num = x;
++	cards[x] = wc;
++	
++#ifdef ENABLE_WORKQUEUES
++	if (wc->flags & FLAG_2NDGEN) {
++		char tmp[20];
++
++		sprintf(tmp, "opvxd115");
++		wc->workq = create_workqueue(tmp);
++	}
++#endif			
++
++	/* Allocate pieces we need here */
++	for (x = 0; x < PORTS_PER_FRAMER; x++) {
++		if (!(wc->tspans[x] = kmalloc(sizeof(*wc->tspans[x]), GFP_KERNEL))) {
++			free_wc(wc);
++			return -ENOMEM;
++		}
++
++		memset(wc->tspans[x], 0, sizeof(*wc->tspans[x]));
++
++		if (wc->t1e1 & (1 << x)) {
++			wc->tspans[x]->spantype = TYPE_E1;
++		} else {
++			if (j1mode)
++				wc->tspans[x]->spantype = TYPE_J1;
++			else
++				wc->tspans[x]->spantype = TYPE_T1;
++		}
++
++		for (f = 0; f < (wc->tspans[x]->spantype == TYPE_E1 ? 31 : 24); f++) {
++			if (!(wc->tspans[x]->chans[f] = kmalloc(sizeof(*wc->tspans[x]->chans[f]), GFP_KERNEL))) {
++				free_wc(wc);
++				return -ENOMEM;
++			}
++			memset(wc->tspans[x]->chans[f], 0, sizeof(*wc->tspans[x]->chans[f]));
++			if (!(wc->tspans[x]->ec[f] = kmalloc(sizeof(*wc->tspans[x]->ec[f]), GFP_KERNEL))) {
++				free_wc(wc);
++				return -ENOMEM;
++			}
++			memset(wc->tspans[x]->ec[f], 0, sizeof(*wc->tspans[x]->ec[f]));
++		}
++
++#ifdef ENABLE_WORKQUEUES
++		INIT_WORK(&wc->tspans[x]->swork, workq_handlespan, wc->tspans[x]);
++#endif				
++		wc->tspans[x]->spanflags |= wc->flags;
++	}
++	
++	/* Continue hardware intiialization */
++	t4_hardware_init_2(wc);
++	
++#ifdef SUPPORT_GEN1
++	if (request_irq(pdev->irq, (wc->flags & FLAG_2NDGEN) ? t4_interrupt_gen2 :t4_interrupt, DAHDI_IRQ_SHARED_DISABLED, "opvxd115", wc)) 
++#else
++		if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) {
++			dev_notice(&wc->dev->dev, "This driver does not "
++					"support 1st gen modules\n");
++			free_wc(wc);
++			return -ENODEV;
++		}	
++			if (request_irq(pdev->irq, t4_interrupt_gen2, DAHDI_IRQ_SHARED_DISABLED, "opvxd115", wc)) 
++#endif
++	{
++		dev_notice(&wc->dev->dev, "opvxd115: Unable to request IRQ %d\n",
++				pdev->irq);
++		free_wc(wc);
++		return -EIO;
++	}
++	
++	init_spans(wc);
++	/* get the current number of probed cards and run a slice of a tail
++	 * insertion sort */
++	for (x = 0; x < MAX_T4_CARDS; x++) {
++		if (!cards[x+1])
++			break;
++	}
++	for ( ; x > 0; x--) {
++		if (cards[x]->order < cards[x-1]->order) {
++			struct t4 *tmp = cards[x];
++			cards[x] = cards[x-1];
++			cards[x-1] = tmp;
++		} else {
++			/* if we're not moving it, we won't move any more
++			 * since all cards are sorted on addition */
++			break;
++		}
++	}
++	
++	dev_info(&wc->dev->dev, "Found an OpenVox Card: %s\n", wc->variety);
++	wc->gpio = 0x00000000;
++	t4_pci_out(wc, WC_GPIO, wc->gpio);
++	t4_gpio_setdir(wc, (1 << 17), (1 << 17));
++	t4_gpio_setdir(wc, (0xff), (0xff));
++
++	create_sysfs_files(wc);
++	
++#if 0
++	for (x=0;x<0x10000;x++) {
++		__t4_raw_oct_out(wc, 0x0004, x);
++		__t4_raw_oct_out(wc, 0x000a, x ^ 0xffff);
++		if (__t4_raw_oct_in(wc, 0x0004) != x) 
++			dev_notice(&wc->dev->dev, "Register 4 failed %04x\n",
++					x);
++		if (__t4_raw_oct_in(wc, 0x000a) != (x ^ 0xffff))
++			dev_notice(&wc->dev->dev, "Register 10 failed %04x\n",
++					x);
++	}
++#endif
++
++	return 0;
++}
++
++static int t4_hardware_stop(struct t4 *wc)
++{
++
++	/* Turn off DMA, leave interrupts enabled */
++	set_bit(T4_STOP_DMA, &wc->checkflag);
++
++	/* Wait for interrupts to stop */
++	msleep(25);
++
++	/* Turn off counter, address, etc */
++	if (wc->tspans[0]->spanflags & FLAG_2NDGEN) {
++		t4_tsi_reset(wc);
++	} else {
++		t4_pci_out(wc, WC_COUNT, 0x000000);
++	}
++	t4_pci_out(wc, WC_RDADDR, 0x0000000);
++	t4_pci_out(wc, WC_WRADDR, 0x0000000);
++	wc->gpio = 0x00000000;
++	t4_pci_out(wc, WC_GPIO, wc->gpio);
++	t4_pci_out(wc, WC_LEDS, 0x00000000);
++
++	dev_notice(&wc->dev->dev, "\nStopped opvxd115, Turned off DMA\n");
++	return 0;
++}
++
++static void __devexit t4_remove_one(struct pci_dev *pdev)
++{
++	struct t4 *wc = pci_get_drvdata(pdev);
++	struct dahdi_span *span;
++	int basesize;
++	int i;
++
++	if (!wc) {
++		return;
++	}
++
++	remove_sysfs_files(wc);
++
++	/* Stop hardware */
++	t4_hardware_stop(wc);
++	
++	/* Release vpm450m */
++	if (wc->vpm450m)
++		release_vpm450m(wc->vpm450m);
++	wc->vpm450m = NULL;
++	/* Unregister spans */
++
++	basesize = DAHDI_MAX_CHUNKSIZE * 32 * 4;
++	if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN))
++		basesize = basesize * 2;
++
++	for (i = 0; i < wc->numspans; ++i) {
++		span = &wc->tspans[i]->span;
++		if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags))
++			dahdi_unregister(span);
++	}
++#ifdef ENABLE_WORKQUEUES
++	if (wc->workq) {
++		flush_workqueue(wc->workq);
++		destroy_workqueue(wc->workq);
++	}
++#endif			
++	
++	free_irq(pdev->irq, wc);
++	
++	if (wc->membase)
++		iounmap(wc->membase);
++	
++	pci_release_regions(pdev);		
++	
++	/* Immediately free resources */
++	pci_free_consistent(pdev, T4_BASE_SIZE * wc->numbufs * 2, (void *)wc->writechunk, wc->writedma);
++	
++	order_index[wc->order]--;
++	
++	cards[wc->num] = NULL;
++	pci_set_drvdata(pdev, NULL);
++	free_wc(wc);
++}
++
++
++static struct pci_device_id t4_pci_tbl[] __devinitdata =
++{
++	{ 0x1b74, 0x0115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&opvxd115 }, /* OpenVox D115P/D115E */
++	{ 0x1b74, 0xd130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&opvxd130 }, /* OpenVox D130P/D130E */
++	{ 0, }
++};
++
++static struct pci_driver t4_driver = {
++	.name = "opvxd115",
++	.probe = t4_init_one,
++	.remove = __devexit_p(t4_remove_one),
++	.id_table = t4_pci_tbl,
++};
++
++static int __init t4_init(void)
++{
++	int res;
++	res = dahdi_pci_module(&t4_driver);
++	if (res)
++		return -ENODEV;
++	/* initialize cards since we have all of them */
++	/* warn for missing zero and duplicate numbers */
++	if (cards[0] && cards[0]->order != 0) {
++		printk(KERN_NOTICE "opvxd115: Ident of first card is not zero (%d)\n",
++			cards[0]->order);
++	}
++	for (res = 0; cards[res]; res++) {
++		/* warn the user of duplicate ident values it is probably
++		 * unintended */
++		if (debug && res < 15 && cards[res+1] &&
++		    cards[res]->order == cards[res+1]->order) {
++			printk(KERN_NOTICE "opvxd115: Duplicate ident value found (%d)\n",
++				cards[res]->order);
++		}
++		t4_launch(cards[res]);
++	}
++	return 0;
++}
++
++static void __exit t4_cleanup(void)
++{
++	pci_unregister_driver(&t4_driver);
++}
++
++
++MODULE_AUTHOR("mark.liu <mark.liu at openvox.cn>");
++MODULE_DESCRIPTION("Unified OpenVox Single T1/E1/J1 Card Driver");
++MODULE_ALIAS("opvxd115");
++MODULE_LICENSE("GPL v2");
++
++module_param(pedanticpci, int, 0600);
++module_param(debug, int, 0600);
++module_param(noburst, int, 0600);
++module_param(timingcable, int, 0600);
++module_param(t1e1override, int, 0600);
++module_param(alarmdebounce, int, 0600);
++module_param(losalarmdebounce, int, 0600);
++module_param(aisalarmdebounce, int, 0600);
++module_param(yelalarmdebounce, int, 0600);
++module_param(max_latency, int, 0600);
++module_param(j1mode, int, 0600);
++module_param(sigmode, int, 0600);
++module_param(latency, int, 0600);
++module_param(ms_per_irq, int, 0600);
++#ifdef VPM_SUPPORT
++module_param(vpmsupport, int, 0600);
++module_param(vpmdtmfsupport, int, 0600);
++module_param(vpmspans, int, 0600);
++module_param(dtmfthreshold, int, 0600);
++#endif
++
++MODULE_DEVICE_TABLE(pci, t4_pci_tbl);
++
++module_init(t4_init);
++module_exit(t4_cleanup);
+diff --git a/drivers/dahdi/opvxd115/opvxd115-diag.c b/drivers/dahdi/opvxd115/opvxd115-diag.c
+new file mode 100644
+index 0000000..7d1dfdb
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/opvxd115-diag.c
+@@ -0,0 +1,427 @@
++/*
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ */
++
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/ioctl.h>
++#include <errno.h>
++#include <string.h>
++#include <dahdi/user.h>
++#include "opvxd115.h"
++
++struct t4_reg_def {
++	int reg;
++	char *name;
++	int global;
++};
++static struct t4_reg_def xreginfo[] = {
++	{ 0x00, "RDADDR" },
++	{ 0x01, "WRADDR" },
++	{ 0x02, "COUNT" },
++	{ 0x03, "DMACTRL" },
++	{ 0x04, "WCINTR" },
++	{ 0x06, "VERSION" },
++	{ 0x07, "LEDS" },
++	{ 0x08, "GPIOCTL" },
++	{ 0x09, "GPIO" }, 
++	{ 0x0A, "LADDR" },
++	{ 0x0b, "LDATA" },
++};
++
++static struct t4_reg_def reginfo[] = {
++	{ 0x00, "XFIFO" },
++	{ 0x01, "XFIFO" },
++	{ 0x02, "CMDR" },
++	{ 0x03, "MODE" },
++	{ 0x04, "RAH1" },
++	{ 0x05, "RAH2" },
++	{ 0x06, "RAL1" },
++	{ 0x07, "RAL2" },
++	{ 0x08, "IPC", 1 },
++	{ 0x09, "CCR1" },
++	{ 0x0a, "CCR2" },
++	{ 0x0c, "RTR1" },
++	{ 0x0d, "RTR2" },
++	{ 0x0e, "RTR3" },
++	{ 0x0f, "RTR4" },
++	{ 0x10, "TTR1" },
++	{ 0x11, "TTR2" },
++	{ 0x12, "TTR3" },
++	{ 0x13, "TTR4" },
++	{ 0x14, "IMR0" },
++	{ 0x15, "IMR1" },
++	{ 0x16, "IMR2" },
++	{ 0x17, "IMR3" },
++	{ 0x18, "IMR4" },
++	{ 0x1b, "IERR" },
++	{ 0x1c, "FMR0" },
++	{ 0x1d, "FMR1" },
++	{ 0x1e, "FMR2" },
++	{ 0x1f, "LOOP" },
++	{ 0x20, "XSW" },
++	{ 0x21, "XSP" },
++	{ 0x22, "XC0" },
++	{ 0x23, "XC1" },
++	{ 0x24, "RC0" },
++	{ 0x25, "RC1" },
++	{ 0x26, "XPM0" },
++	{ 0x27, "XPM1" },
++	{ 0x28, "XPM2" },
++	{ 0x29, "TSWM" },
++	{ 0x2b, "IDLE" },
++	{ 0x2c, "XSA4" },
++	{ 0x2d, "XSA5" },
++	{ 0x2e, "XSA6" },
++	{ 0x2f, "XSA7" },
++	{ 0x30, "XSA8" },
++	{ 0x31, "FMR3" },
++	{ 0x32, "ICB1" },
++	{ 0x33, "ICB2" },
++	{ 0x34, "ICB3" },
++	{ 0x35, "ICB4" },
++	{ 0x36, "LIM0" },
++	{ 0x37, "LIM1" },
++	{ 0x38, "PCD" },
++	{ 0x39, "PCR" },
++	{ 0x3a, "LIM2" },
++	{ 0x3b, "LCR1" },
++	{ 0x3c, "LCR2" },
++	{ 0x3d, "LCR3" },
++	{ 0x3e, "SIC1" },
++	{ 0x3f, "SIC2" },
++	{ 0x40, "SIC3" },
++	{ 0x44, "CMR1" },
++	{ 0x45, "CMR2" },
++	{ 0x46, "GCR" },
++	{ 0x47, "ESM" },
++	{ 0x60, "DEC" },
++	{ 0x70, "XS1" },
++	{ 0x71, "XS2" },
++	{ 0x72, "XS3" },
++	{ 0x73, "XS4" },
++	{ 0x74, "XS5" },
++	{ 0x75, "XS6" },
++	{ 0x76, "XS7" },
++	{ 0x77, "XS8" },
++	{ 0x78, "XS9" },
++	{ 0x79, "XS10" },
++	{ 0x7a, "XS11" },
++	{ 0x7b, "XS12" },
++	{ 0x7c, "XS13" },
++	{ 0x7d, "XS14" },
++	{ 0x7e, "XS15" },
++	{ 0x7f, "XS16" },
++	{ 0x80, "PC1" },
++	{ 0x81, "PC2" },
++	{ 0x82, "PC3" },
++	{ 0x83, "PC4" },
++	{ 0x84, "PC5" },
++	{ 0x85, "GPC1", 1 },
++	{ 0x87, "CMDR2" },
++	{ 0x8d, "CCR5" },
++	{ 0x92, "GCM1", 1 },
++	{ 0x93, "GCM2", 1 },
++	{ 0x94, "GCM3", 1 },
++	{ 0x95, "GCM4", 1 },
++	{ 0x96, "GCM5", 1 },
++	{ 0x97, "GCM6", 1 },
++	{ 0x98, "GCM7", 1 },
++	{ 0x99, "GCM8", 1 },
++	{ 0xa0, "TSEO" },
++	{ 0xa1, "TSBS1" },
++	{ 0xa8, "TPC0" },	
++};
++
++static struct t4_reg_def t1_reginfo[] = {
++	{ 0x00, "XFIFO" },
++	{ 0x01, "XFIFO" },
++	{ 0x02, "CMDR" },
++	{ 0x03, "MODE" },
++	{ 0x04, "RAH1" },
++	{ 0x05, "RAH2" },
++	{ 0x06, "RAL1" },
++	{ 0x07, "RAL2" },
++	{ 0x08, "IPC", 1 },
++	{ 0x09, "CCR1" },
++	{ 0x0a, "CCR2" },
++	{ 0x0c, "RTR1" },
++	{ 0x0d, "RTR2" },
++	{ 0x0e, "RTR3" },
++	{ 0x0f, "RTR4" },
++	{ 0x10, "TTR1" },
++	{ 0x11, "TTR2" },
++	{ 0x12, "TTR3" },
++	{ 0x13, "TTR4" },
++	{ 0x14, "IMR0" },
++	{ 0x15, "IMR1" },
++	{ 0x16, "IMR2" },
++	{ 0x17, "IMR3" },
++	{ 0x18, "IMR4" },
++	{ 0x1b, "IERR" },
++	{ 0x1c, "FMR0" },
++	{ 0x1d, "FMR1" },
++	{ 0x1e, "FMR2" },
++	{ 0x1f, "LOOP" },
++	{ 0x20, "FMR4" },
++	{ 0x21, "FMR5" },
++	{ 0x22, "XC0" },
++	{ 0x23, "XC1" },
++	{ 0x24, "RC0" },
++	{ 0x25, "RC1" },
++	{ 0x26, "XPM0" },
++	{ 0x27, "XPM1" },
++	{ 0x28, "XPM2" },
++	{ 0x2b, "IDLE" },
++	{ 0x2c, "XDL1" },
++	{ 0x2d, "XDL2" },
++	{ 0x2e, "XDL3" },
++	{ 0x2f, "CCB1" },
++	{ 0x30, "CCB2" },
++	{ 0x31, "CCB3" },
++	{ 0x32, "ICB1" },
++	{ 0x33, "ICB2" },
++	{ 0x34, "ICB3" },
++	{ 0x36, "LIM0" },
++	{ 0x37, "LIM1" },
++	{ 0x38, "PCD" },
++	{ 0x39, "PCR" },
++	{ 0x3a, "LIM2" },
++	{ 0x3b, "LCR1" },
++	{ 0x3c, "LCR2" },
++	{ 0x3d, "LCR3" },
++	{ 0x3e, "SIC1" },
++	{ 0x3f, "SIC2" },
++	{ 0x40, "SIC3" },
++	{ 0x44, "CMR1" },
++	{ 0x45, "CMR2" },
++	{ 0x46, "GCR" },
++	{ 0x47, "ESM" },
++	{ 0x60, "DEC" },
++	{ 0x70, "XS1" },
++	{ 0x71, "XS2" },
++	{ 0x72, "XS3" },
++	{ 0x73, "XS4" },
++	{ 0x74, "XS5" },
++	{ 0x75, "XS6" },
++	{ 0x76, "XS7" },
++	{ 0x77, "XS8" },
++	{ 0x78, "XS9" },
++	{ 0x79, "XS10" },
++	{ 0x7a, "XS11" },
++	{ 0x7b, "XS12" },
++	{ 0x80, "PC1" },
++	{ 0x81, "PC2" },
++	{ 0x82, "PC3" },
++	{ 0x83, "PC4" },
++	{ 0x84, "PC5" },
++	{ 0x85, "GPC1", 1 },
++	{ 0x87, "CMDR2" },
++	{ 0x8d, "CCR5" },
++	{ 0x92, "GCM1", 1 },
++	{ 0x93, "GCM2", 1 },
++	{ 0x94, "GCM3", 1 },
++	{ 0x95, "GCM4", 1 },
++	{ 0x96, "GCM5", 1 },
++	{ 0x97, "GCM6", 1 },
++	{ 0x98, "GCM7", 1 },
++	{ 0x99, "GCM8", 1 },
++	{ 0xa0, "TSEO" },
++	{ 0xa1, "TSBS1" },
++	{ 0xa8, "TPC0" },	
++};
++
++static struct t4_reg_def t1_sreginfo[] = {
++	{ 0x00, "RFIFO" },
++	{ 0x01, "RFIFO" },
++	{ 0x49, "RBD" },
++	{ 0x4a, "VSTR", 1 },
++	{ 0x4b, "RES" },
++	{ 0x4c, "FRS0" },
++	{ 0x4d, "FRS1" },
++	{ 0x4e, "FRS2" },
++	{ 0x4f, "Old FRS1" },
++	{ 0x50, "FECL" },
++	{ 0x51, "FECH" },
++	{ 0x52, "CVCL" },
++	{ 0x53, "CVCH" },
++	{ 0x54, "CECL" },
++	{ 0x55, "CECH" },
++	{ 0x56, "EBCL" },
++	{ 0x57, "EBCH" },
++	{ 0x58, "BECL" },
++	{ 0x59, "BECH" },
++	{ 0x5a, "COEC" },
++	{ 0x5c, "RDL1" },
++	{ 0x5d, "RDL2" },
++	{ 0x5e, "RDL3" },
++	{ 0x62, "RSP1" },
++	{ 0x63, "RSP2" },
++	{ 0x64, "SIS" },
++	{ 0x65, "RSIS" },
++	{ 0x66, "RBCL" },
++	{ 0x67, "RBCH" },
++	{ 0x68, "ISR0" },
++	{ 0x69, "ISR1" },
++	{ 0x6a, "ISR2" },
++	{ 0x6b, "ISR3" },
++	{ 0x6c, "ISR4" },
++	{ 0x6e, "GIS" },
++	{ 0x6f, "CIS", 1 },
++	{ 0x70, "RS1" },
++	{ 0x71, "RS2" },
++	{ 0x72, "RS3" },
++	{ 0x73, "RS4" },
++	{ 0x74, "RS5" },
++	{ 0x75, "RS6" },
++	{ 0x76, "RS7" },
++	{ 0x77, "RS8" },
++	{ 0x78, "RS9" },
++	{ 0x79, "RS10" },
++	{ 0x7a, "RS11" },
++	{ 0x7b, "RS12" },
++};
++
++static struct t4_reg_def sreginfo[] = {
++	{ 0x00, "RFIFO" },
++	{ 0x01, "RFIFO" },
++	{ 0x49, "RBD" },
++	{ 0x4a, "VSTR", 1 },
++	{ 0x4b, "RES" },
++	{ 0x4c, "FRS0" },
++	{ 0x4d, "FRS1" },
++	{ 0x4e, "RSW" },
++	{ 0x4f, "RSP" },
++	{ 0x50, "FECL" },
++	{ 0x51, "FECH" },
++	{ 0x52, "CVCL" },
++	{ 0x53, "CVCH" },
++	{ 0x54, "CEC1L" },
++	{ 0x55, "CEC1H" },
++	{ 0x56, "EBCL" },
++	{ 0x57, "EBCH" },
++	{ 0x58, "CEC2L" },
++	{ 0x59, "CEC2H" },
++	{ 0x5a, "CEC3L" },
++	{ 0x5b, "CEC3H" },
++	{ 0x5c, "RSA4" },
++	{ 0x5d, "RSA5" },
++	{ 0x5e, "RSA6" },
++	{ 0x5f, "RSA7" },
++	{ 0x60, "RSA8" },
++	{ 0x61, "RSA6S" },
++	{ 0x62, "RSP1" },
++	{ 0x63, "RSP2" },
++	{ 0x64, "SIS" },
++	{ 0x65, "RSIS" },
++	{ 0x66, "RBCL" },
++	{ 0x67, "RBCH" },
++	{ 0x68, "ISR0" },
++	{ 0x69, "ISR1" },
++	{ 0x6a, "ISR2" },
++	{ 0x6b, "ISR3" },
++	{ 0x6c, "ISR4" },
++	{ 0x6e, "GIS" },
++	{ 0x6f, "CIS", 1 },
++	{ 0x70, "RS1" },
++	{ 0x71, "RS2" },
++	{ 0x72, "RS3" },
++	{ 0x73, "RS4" },
++	{ 0x74, "RS5" },
++	{ 0x75, "RS6" },
++	{ 0x76, "RS7" },
++	{ 0x77, "RS8" },
++	{ 0x78, "RS9" },
++	{ 0x79, "RS10" },
++	{ 0x7a, "RS11" },
++	{ 0x7b, "RS12" },
++	{ 0x7c, "RS13" },
++	{ 0x7d, "RS14" },
++	{ 0x7e, "RS15" },
++	{ 0x7f, "RS16" },
++};
++
++static char *tobin(int x)
++{
++	static char s[9] = "";
++	int y,z=0;
++	for (y=7;y>=0;y--) {
++		if (x & (1 << y))
++			s[z++] = '1';
++		else
++			s[z++] = '0';
++	}
++	s[z] = '\0';
++	return s;
++}
++
++static char *tobin32(unsigned int x)
++{
++	static char s[33] = "";
++	int y,z=0;
++	for (y=31;y>=0;y--) {
++		if (x & (1 << y))
++			s[z++] = '1';
++		else
++			s[z++] = '0';
++	}
++	s[z] = '\0';
++	return s;
++}
++
++int main(int argc, char *argv[])
++{
++	int fd;
++	int x;
++	char fn[256];
++	struct t4_regs regs;
++	if ((argc < 2) || ((*(argv[1]) != '/') && !atoi(argv[1]))) {
++		fprintf(stderr, "Usage: opvxd115-diag <channel>\n");
++		exit(1);
++	}
++	if (*(argv[1]) == '/')
++		dahdi_copy_string(fn, argv[1], sizeof(fn));
++	else
++		snprintf(fn, sizeof(fn), "/dev/dahdi/%d", atoi(argv[1]));
++	fd = open(fn, O_RDWR);
++	if (fd <0) {
++		fprintf(stderr, "Unable to open '%s': %s\n", fn, strerror(errno));
++		exit(1);
++	}
++	if (ioctl(fd, WCT4_GET_REGS, &regs)) {
++		fprintf(stderr, "Unable to get registers: %s\n", strerror(errno));
++		exit(1);
++	}
++	printf("PCI Registers:\n");
++	for (x=0;x<sizeof(xreginfo) / sizeof(xreginfo[0]);x++) {
++		fprintf(stdout, "%s (%02x): %08x (%s)\n", xreginfo[x].name, xreginfo[x].reg, regs.pci[xreginfo[x].reg], tobin32(regs.pci[xreginfo[x].reg]));
++	}
++	printf("\nE1 Control Registers:\n");
++	for (x=0;x<sizeof(reginfo) / sizeof(reginfo[0]);x++) {
++		fprintf(stdout, "%s (%02x): %02x (%s)\n", reginfo[x].name, reginfo[x].reg, regs.regs[reginfo[x].reg], tobin(regs.regs[reginfo[x].reg]));
++	}
++	printf("\nE1 Status Registers:\n");
++	for (x=0;x<sizeof(sreginfo) / sizeof(sreginfo[0]);x++) {
++		fprintf(stdout, "%s (%02x): %02x (%s)\n", sreginfo[x].name, sreginfo[x].reg, regs.regs[sreginfo[x].reg], tobin(regs.regs[sreginfo[x].reg]));
++	}
++	printf("\nT1 Control Registers:\n");
++	for (x=0;x<sizeof(t1_reginfo) / sizeof(t1_reginfo[0]);x++) {
++		fprintf(stdout, "%s (%02x): %02x (%s)\n", t1_reginfo[x].name, t1_reginfo[x].reg, regs.regs[t1_reginfo[x].reg], tobin(regs.regs[t1_reginfo[x].reg]));
++	}
++	printf("\nT1 Status Registers:\n");
++	for (x=0;x<sizeof(t1_sreginfo) / sizeof(t1_sreginfo[0]);x++) {
++		fprintf(stdout, "%s (%02x): %02x (%s)\n", t1_sreginfo[x].name, t1_sreginfo[x].reg, regs.regs[t1_sreginfo[x].reg], tobin(regs.regs[t1_sreginfo[x].reg]));
++	}
++	exit(0);
++}
+diff --git a/drivers/dahdi/opvxd115/opvxd115.h b/drivers/dahdi/opvxd115/opvxd115.h
+new file mode 100644
+index 0000000..d89d5b3
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/opvxd115.h
+@@ -0,0 +1,124 @@
++/*
++ * Wildcard T400P FXS Interface Driver for DAHDI Telephony interface
++ *
++ * Written by Mark Spencer <markster at linux-support.net>
++ *
++ * Copyright (C) 2001-2008, Digium, Inc.
++ *
++ * All rights reserved.
++ *
++ */
++
++/*
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ */
++
++#include <linux/ioctl.h>
++
++#define FRMR_TTR_BASE 0x10
++#define FRMR_RTR_BASE 0x0c
++#define FRMR_TSEO 0xa0
++#define FRMR_TSBS1 0xa1
++#define FRMR_CCR1 0x09
++#define FRMR_CCR1_ITF 0x08
++#define FRMR_CCR1_EITS 0x10
++#define FRMR_CCR2 0x0a
++#define FRMR_CCR2_RCRC 0x04
++#define FRMR_CCR2_RADD 0x10
++#define FRMR_MODE 0x03
++#define FRMR_MODE_NO_ADDR_CMP 0x80
++#define FRMR_MODE_SS7 0x20
++#define FRMR_MODE_HRAC 0x08
++#define FRMR_IMR0 0x14
++#define FRMR_IMR0_RME 0x80
++#define FRMR_IMR0_RPF 0x01
++#define FRMR_IMR1 0x15
++#define FRMR_IMR1_ALLS 0x20
++#define FRMR_IMR1_XDU 0x10
++#define FRMR_IMR1_XPR 0x01
++#define FRMR_XC0 0x22
++#define FRMR_XC1 0x23
++#define FRMR_RC0 0x24
++#define FRMR_RC1 0x25
++#define FRMR_SIC1 0x3e
++#define FRMR_SIC2 0x3f
++#define FRMR_SIC3 0x40
++#define FRMR_CMR1 0x44
++#define FRMR_CMR2 0x45
++#define FRMR_GCR 0x46
++#define FRMR_ISR0 0x68
++#define FRMR_ISR0_RME 0x80
++#define FRMR_ISR0_RPF 0x01
++#define FRMR_ISR1 0x69
++#define FRMR_ISR1_ALLS 0x20
++#define FRMR_ISR1_XDU 0x10
++#define FRMR_ISR1_XPR 0x01
++#define FRMR_ISR2 0x6a
++#define FRMR_ISR3 0x6b
++#define FRMR_ISR4 0x6c
++#define FRMR_GIS  0x6e
++#define FRMR_GIS_ISR0 0x01
++#define FRMR_GIS_ISR1 0x02
++#define FRMR_GIS_ISR2 0x04
++#define FRMR_GIS_ISR3 0x08
++#define FRMR_GIS_ISR4 0x10
++#define FRMR_CIS 0x6f
++#define FRMR_CIS_GIS1 0x01
++#define FRMR_CIS_GIS2 0x02
++#define FRMR_CIS_GIS3 0x04
++#define FRMR_CIS_GIS4 0x08
++#define FRMR_CMDR 0x02
++#define FRMR_CMDR_SRES 0x01
++#define FRMR_CMDR_XRES 0x10
++#define FRMR_CMDR_RMC 0x80
++#define FRMR_CMDR_XTF 0x04
++#define FRMR_CMDR_XHF 0x08
++#define FRMR_CMDR_XME 0x02
++#define FRMR_RSIS 0x65
++#define FRMR_RSIS_VFR 0x80
++#define FRMR_RSIS_RDO 0x40
++#define FRMR_RSIS_CRC16 0x20
++#define FRMR_RSIS_RAB 0x10
++#define FRMR_RBCL 0x66
++#define FRMR_RBCL_MAX_SIZE 0x1f
++#define FRMR_RBCH 0x67
++#define FRMR_RXFIFO 0x00
++#define FRMR_SIS 0x64
++#define FRMR_SIS_XFW 0x40
++#define FRMR_TXFIFO 0x00
++
++#define FRS0 0x4c
++#define FRS0_LOS (1<<7)
++#define FRS0_LFA (1<<5)
++#define FRS0_LMFA (1<<1)
++
++#define FRS1 0x4d
++#define FRS1_XLS (1<<1)
++#define FRS1_XLO (1<<0)
++
++#define NUM_REGS 0xa9
++#define NUM_PCI 12
++
++struct t4_regs {
++	unsigned int pci[NUM_PCI];
++	unsigned char regs[NUM_REGS];
++};
++
++#define T4_CHECK_VPM		0
++#define T4_LOADING_FW		1
++#define T4_STOP_DMA		2
++#define T4_CHECK_TIMING		3
++#define T4_CHANGE_LATENCY	4
++#define T4_IGNORE_LATENCY	5
++
++#define WCT4_GET_REGS	_IOW (DAHDI_CODE, 60, struct t4_regs)
++
+diff --git a/drivers/dahdi/opvxd115/vpm450m.c b/drivers/dahdi/opvxd115/vpm450m.c
+new file mode 100644
+index 0000000..f1ed421
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/vpm450m.c
+@@ -0,0 +1,587 @@
++/*
++ * Copyright (C) 2005-2006 Digium, Inc.
++ *
++ * Mark Spencer <markster at digium.com>
++ * Modified by mark.liu at openvox.cn 06/16/2009
++ 
++ * All Rights Reserved
++ */
++
++/*
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ */
++
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/string.h>
++#include <linux/time.h>
++#include <linux/version.h>
++
++#include "vpm450m.h"
++#include "oct6100api/oct6100_api.h"
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++#include <linux/config.h>
++#endif
++
++/* API for Octasic access */
++UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
++{
++	/* Why couldn't they just take a timeval like everyone else? */
++	struct timeval tv;
++	unsigned long long total_usecs;
++	unsigned int mask = ~0;
++	
++	do_gettimeofday(&tv);
++	total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) + 
++				  (((unsigned long long)(tv.tv_usec)));
++	f_pTime->aulWallTimeUs[0] = (total_usecs & mask);
++	f_pTime->aulWallTimeUs[1] = (total_usecs >> 32);
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength)
++{
++	memset(f_pAddress, f_ulPattern, f_ulLength);
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength)
++{
++	memcpy(f_pDestination, f_pSource, f_ulLength);
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
++{
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
++{
++#ifdef OCTASIC_DEBUG
++	printk(KERN_DEBUG "I should never be called! (destroy serialize object)\n");
++#endif
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
++{
++	/* Not needed */
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
++{
++	/* Not needed */
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
++{
++	oct_set_reg(f_pWriteParams->pProcessContext, f_pWriteParams->ulWriteAddress, f_pWriteParams->usWriteData);
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
++{
++	unsigned int x;
++	for (x=0;x<f_pSmearParams->ulWriteLength;x++) {
++		oct_set_reg(f_pSmearParams->pProcessContext, f_pSmearParams->ulWriteAddress + (x << 1), f_pSmearParams->usWriteData);
++	}
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams)
++{
++	unsigned int x;
++	for (x=0;x<f_pBurstParams->ulWriteLength;x++) {
++		oct_set_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulWriteAddress + (x << 1), f_pBurstParams->pusWriteData[x]);
++	}
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
++{
++	*(f_pReadParams->pusReadData) = oct_get_reg(f_pReadParams->pProcessContext, f_pReadParams->ulReadAddress);
++	return cOCT6100_ERR_OK;
++}
++
++UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
++{
++	unsigned int x;
++	for (x=0;x<f_pBurstParams->ulReadLength;x++) {
++		f_pBurstParams->pusReadData[x] = oct_get_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulReadAddress + (x << 1));
++	}
++	return cOCT6100_ERR_OK;
++}
++
++#define SOUT_G168_1100GB_ON 0x40000004
++#define SOUT_DTMF_1 0x40000011
++#define SOUT_DTMF_2 0x40000012
++#define SOUT_DTMF_3 0x40000013
++#define SOUT_DTMF_A 0x4000001A
++#define SOUT_DTMF_4 0x40000014
++#define SOUT_DTMF_5 0x40000015
++#define SOUT_DTMF_6 0x40000016
++#define SOUT_DTMF_B 0x4000001B
++#define SOUT_DTMF_7 0x40000017
++#define SOUT_DTMF_8 0x40000018
++#define SOUT_DTMF_9 0x40000019
++#define SOUT_DTMF_C 0x4000001C
++#define SOUT_DTMF_STAR 0x4000001E
++#define SOUT_DTMF_0 0x40000010
++#define SOUT_DTMF_POUND 0x4000001F
++#define SOUT_DTMF_D 0x4000001D
++
++#define ROUT_G168_2100GB_ON 0x10000000
++#define ROUT_G168_2100GB_WSPR 0x10000002
++#define ROUT_SOUT_G168_2100HB_END 0x50000003
++#define ROUT_G168_1100GB_ON 0x10000004
++
++#define ROUT_DTMF_1 0x10000011
++#define ROUT_DTMF_2 0x10000012
++#define ROUT_DTMF_3 0x10000013
++#define ROUT_DTMF_A 0x1000001A
++#define ROUT_DTMF_4 0x10000014
++#define ROUT_DTMF_5 0x10000015
++#define ROUT_DTMF_6 0x10000016
++#define ROUT_DTMF_B 0x1000001B
++#define ROUT_DTMF_7 0x10000017
++#define ROUT_DTMF_8 0x10000018
++#define ROUT_DTMF_9 0x10000019
++#define ROUT_DTMF_C 0x1000001C
++#define ROUT_DTMF_STAR 0x1000001E
++#define ROUT_DTMF_0 0x10000010
++#define ROUT_DTMF_POUND 0x1000001F
++#define ROUT_DTMF_D 0x1000001D
++
++#if 0 
++#define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_HT_FREEZE
++#else
++#define cOCT6100_ECHO_OP_MODE_DIGITAL cOCT6100_ECHO_OP_MODE_POWER_DOWN
++#endif
++
++struct vpm450m {
++	tPOCT6100_INSTANCE_API pApiInstance;
++	UINT32 aulEchoChanHndl[ 128 ];
++	int chanflags[128];
++	int ecmode[128];
++	int numchans;
++};
++
++#define FLAG_DTMF	 (1 << 0)
++#define FLAG_MUTE	 (1 << 1)
++#define FLAG_ECHO	 (1 << 2)
++
++static unsigned int tones[] = {
++	SOUT_DTMF_1,
++	SOUT_DTMF_2,
++	SOUT_DTMF_3,
++	SOUT_DTMF_A,
++	SOUT_DTMF_4,
++	SOUT_DTMF_5,
++	SOUT_DTMF_6,
++	SOUT_DTMF_B,
++	SOUT_DTMF_7,
++	SOUT_DTMF_8,
++	SOUT_DTMF_9,
++	SOUT_DTMF_C,
++	SOUT_DTMF_STAR,
++	SOUT_DTMF_0,
++	SOUT_DTMF_POUND,
++	SOUT_DTMF_D,
++	SOUT_G168_1100GB_ON,
++
++	ROUT_DTMF_1,
++	ROUT_DTMF_2,
++	ROUT_DTMF_3,
++	ROUT_DTMF_A,
++	ROUT_DTMF_4,
++	ROUT_DTMF_5,
++	ROUT_DTMF_6,
++	ROUT_DTMF_B,
++	ROUT_DTMF_7,
++	ROUT_DTMF_8,
++	ROUT_DTMF_9,
++	ROUT_DTMF_C,
++	ROUT_DTMF_STAR,
++	ROUT_DTMF_0,
++	ROUT_DTMF_POUND,
++	ROUT_DTMF_D,
++	ROUT_G168_1100GB_ON,
++};
++
++static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode)
++{
++	tOCT6100_CHANNEL_MODIFY *modify;
++	UINT32 ulResult;
++
++	if (vpm450m->ecmode[channel] == mode)
++		return;
++	modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
++	if (!modify) {
++		printk(KERN_NOTICE "opvxd115: Unable to allocate memory for setec!\n");
++		return;
++	}
++	Oct6100ChannelModifyDef(modify);
++	modify->ulEchoOperationMode = mode;
++	modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel];
++	ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify);
++	if (ulResult != GENERIC_OK) {
++		printk(KERN_NOTICE "Failed to apply echo can changes on channel %d!\n", channel);
++	} else {
++#ifdef OCTASIC_DEBUG
++		printk(KERN_DEBUG "Echo can on channel %d set to %d\n", channel, mode);
++#endif
++		vpm450m->ecmode[channel] = mode;
++	}
++	kfree(modify);
++}
++
++void vpm450m_setdtmf(struct vpm450m *vpm450m, int channel, int detect, int mute)
++{
++	tOCT6100_CHANNEL_MODIFY *modify;
++	UINT32 ulResult;
++
++	modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL);
++	if (!modify) {
++		printk(KERN_NOTICE "opvxd115: Unable to allocate memory for setdtmf!\n");
++		return;
++	}
++	Oct6100ChannelModifyDef(modify);
++	modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel];
++	if (mute) {
++		vpm450m->chanflags[channel] |= FLAG_MUTE;
++		modify->VqeConfig.fDtmfToneRemoval = TRUE;
++	} else {
++		vpm450m->chanflags[channel] &= ~FLAG_MUTE;
++		modify->VqeConfig.fDtmfToneRemoval = FALSE;
++	}
++	if (detect)
++		vpm450m->chanflags[channel] |= FLAG_DTMF;
++	else
++		vpm450m->chanflags[channel] &= ~FLAG_DTMF;
++	if (vpm450m->chanflags[channel] & (FLAG_DTMF|FLAG_MUTE)) {
++		if (!(vpm450m->chanflags[channel] & FLAG_ECHO)) {
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE);
++		}
++	} else {
++		if (!(vpm450m->chanflags[channel] & FLAG_ECHO))
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL);
++	}
++
++	ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify);
++	if (ulResult != GENERIC_OK) {
++		printk(KERN_NOTICE "Failed to apply dtmf mute changes on channel %d!\n", channel);
++	}
++/*	printk(KERN_DEBUG "VPM450m: Setting DTMF on channel %d: %s / %s\n", channel, (detect ? "DETECT" : "NO DETECT"), (mute ? "MUTE" : "NO MUTE")); */
++	kfree(modify);
++}
++
++void vpm450m_setec(struct vpm450m *vpm450m, int channel, int eclen)
++{
++	if (eclen) {
++		vpm450m->chanflags[channel] |= FLAG_ECHO;
++		vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
++		vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_NORMAL);
++	} else {
++		vpm450m->chanflags[channel] &= ~FLAG_ECHO;
++		if (vpm450m->chanflags[channel] & (FLAG_DTMF | FLAG_MUTE)) {
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE);
++		} else
++			vpm450m_setecmode(vpm450m, channel, cOCT6100_ECHO_OP_MODE_DIGITAL);
++	}
++/*	printk(KERN_DEBUG "VPM450m: Setting EC on channel %d to %d\n", channel, eclen); */
++}
++
++int vpm450m_checkirq(struct vpm450m *vpm450m)
++{
++	tOCT6100_INTERRUPT_FLAGS InterruptFlags;
++	
++	Oct6100InterruptServiceRoutineDef(&InterruptFlags);
++	Oct6100InterruptServiceRoutine(vpm450m->pApiInstance, &InterruptFlags);
++
++	return InterruptFlags.fToneEventsPending ? 1 : 0;
++}
++
++int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start)
++{
++	tOCT6100_TONE_EVENT tonefound;
++	tOCT6100_EVENT_GET_TONE tonesearch;
++	UINT32 ulResult;
++	
++	Oct6100EventGetToneDef(&tonesearch);
++	tonesearch.pToneEvent = &tonefound;
++	tonesearch.ulMaxToneEvent = 1;
++	ulResult = Oct6100EventGetTone(vpm450m->pApiInstance, &tonesearch);
++	if (tonesearch.ulNumValidToneEvent) {
++		if (channel)
++			*channel = tonefound.ulUserChanId;
++		if (tone) {
++			switch(tonefound.ulToneDetected) {
++			case SOUT_DTMF_1:
++				*tone = '1';
++				break;
++			case SOUT_DTMF_2:
++				*tone = '2';
++				break;
++			case SOUT_DTMF_3:
++				*tone = '3';
++				break;
++			case SOUT_DTMF_A:
++				*tone = 'A';
++				break;
++			case SOUT_DTMF_4:
++				*tone = '4';
++				break;
++			case SOUT_DTMF_5:
++				*tone = '5';
++				break;
++			case SOUT_DTMF_6:
++				*tone = '6';
++				break;
++			case SOUT_DTMF_B:
++				*tone = 'B';
++				break;
++			case SOUT_DTMF_7:
++				*tone = '7';
++				break;
++			case SOUT_DTMF_8:
++				*tone = '8';
++				break;
++			case SOUT_DTMF_9:
++				*tone = '9';
++				break;
++			case SOUT_DTMF_C:
++				*tone = 'C';
++				break;
++			case SOUT_DTMF_STAR:
++				*tone = '*';
++				break;
++			case SOUT_DTMF_0:
++				*tone = '0';
++				break;
++			case SOUT_DTMF_POUND:
++				*tone = '#';
++				break;
++			case SOUT_DTMF_D:
++				*tone = 'D';
++				break;
++			case SOUT_G168_1100GB_ON:
++				*tone = 'f';
++				break;
++			default:
++#ifdef OCTASIC_DEBUG
++				printk(KERN_DEBUG "Unknown tone value %08x\n", tonefound.ulToneDetected);
++#endif
++				*tone = 'u';
++				break;
++			}
++		}
++		if (start)
++			*start = (tonefound.ulEventType == cOCT6100_TONE_PRESENT);
++		return 1;
++	}
++	return 0;
++}
++
++unsigned int get_vpm450m_capacity(void *wc)
++{
++	UINT32 ulResult;
++
++	tOCT6100_API_GET_CAPACITY_PINS CapacityPins;
++
++	Oct6100ApiGetCapacityPinsDef(&CapacityPins);
++	CapacityPins.pProcessContext = wc;
++	CapacityPins.ulMemoryType = cOCT6100_MEM_TYPE_DDR;
++	CapacityPins.fEnableMemClkOut = TRUE;
++	CapacityPins.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
++
++	ulResult = Oct6100ApiGetCapacityPins(&CapacityPins);
++	if (ulResult != cOCT6100_ERR_OK) {
++		printk(KERN_DEBUG "Failed to get chip capacity, code %08x!\n", ulResult);
++		return 0;
++	}
++
++	return CapacityPins.ulCapacityValue;
++}
++
++struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware)
++{
++	tOCT6100_CHIP_OPEN *ChipOpen;
++	tOCT6100_GET_INSTANCE_SIZE InstanceSize;
++	tOCT6100_CHANNEL_OPEN *ChannelOpen;
++	UINT32 ulResult;
++	struct vpm450m *vpm450m;
++	int x,y,law;
++#ifdef CONFIG_4KSTACKS
++	unsigned long flags;
++#endif
++	
++	if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL)))
++		return NULL;
++
++	memset(vpm450m, 0, sizeof(struct vpm450m));
++
++	if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
++		kfree(vpm450m);
++		return NULL;
++	}
++
++	memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN));
++
++	if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) {
++		kfree(vpm450m);
++		kfree(ChipOpen);
++		return NULL;
++	}
++
++	memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN));
++
++	for (x=0;x<128;x++)
++		vpm450m->ecmode[x] = -1;
++
++	vpm450m->numchans = numspans * 32;
++	printk(KERN_INFO "VPM450: echo cancellation for %d channels\n", vpm450m->numchans);
++		
++	Oct6100ChipOpenDef(ChipOpen);
++
++	/* Setup Chip Open Parameters */
++	ChipOpen->ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ;
++	Oct6100GetInstanceSizeDef(&InstanceSize);
++
++	ChipOpen->pProcessContext = wc;
++
++	ChipOpen->pbyImageFile = firmware->data;
++	ChipOpen->ulImageSize = firmware->size;
++	ChipOpen->fEnableMemClkOut = TRUE;
++	ChipOpen->ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
++	ChipOpen->ulMaxChannels = vpm450m->numchans;
++	ChipOpen->ulMemoryType = cOCT6100_MEM_TYPE_DDR;
++	ChipOpen->ulMemoryChipSize = cOCT6100_MEMORY_CHIP_SIZE_32MB;
++	ChipOpen->ulNumMemoryChips = 1;
++	ChipOpen->ulMaxTdmStreams = 4;
++	ChipOpen->aulTdmStreamFreqs[0] = cOCT6100_TDM_STREAM_FREQ_8MHZ;
++	ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE;
++#if 0
++	ChipOpen->fEnableAcousticEcho = TRUE;
++#endif		
++
++	ulResult = Oct6100GetInstanceSize(ChipOpen, &InstanceSize);
++	if (ulResult != cOCT6100_ERR_OK) {
++		printk(KERN_NOTICE "Failed to get instance size, code %08x!\n", ulResult);
++		kfree(vpm450m);
++		kfree(ChipOpen);
++		kfree(ChannelOpen);
++		return NULL;
++	}
++	
++	
++	vpm450m->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize);
++	if (!vpm450m->pApiInstance) {
++		printk(KERN_NOTICE "Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize);
++		kfree(vpm450m);
++		kfree(ChipOpen);
++		kfree(ChannelOpen);
++		return NULL;
++	}
++
++	/* I don't know what to curse more in this comment, the problems caused by
++	 * the 4K kernel stack limit change or the octasic API for being so darn
++	 * stack unfriendly.  Stupid, stupid, stupid.  So we disable IRQs so we
++	 * don't run the risk of overflowing the stack while we initialize the
++	 * octasic. */
++#ifdef CONFIG_4KSTACKS
++	local_irq_save(flags);
++#endif
++	ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen);
++	if (ulResult != cOCT6100_ERR_OK) {
++		printk(KERN_NOTICE "Failed to open chip, code %08x!\n", ulResult);
++#ifdef CONFIG_4KSTACKS
++		local_irq_restore(flags);
++#endif
++		kfree(vpm450m);
++		kfree(ChipOpen);
++		kfree(ChannelOpen);
++		return NULL;
++	}
++	for (x=0;x<128;x++) {
++		if ((x & 0x03) < numspans) {
++			/* span timeslots are interleaved 12341234... 
++		 	*  therefore, the lower 2 bits tell us which span this 
++			*  timeslot/channel
++		 	*/
++			if (isalaw[x & 0x03]) 
++				law = cOCT6100_PCM_A_LAW;
++			else
++				law = cOCT6100_PCM_U_LAW;
++			Oct6100ChannelOpenDef(ChannelOpen);
++			ChannelOpen->pulChannelHndl = &vpm450m->aulEchoChanHndl[x];
++			ChannelOpen->ulUserChanId = x;
++			ChannelOpen->TdmConfig.ulRinPcmLaw = law;
++			ChannelOpen->TdmConfig.ulRinStream = 0;
++			ChannelOpen->TdmConfig.ulRinTimeslot = x;
++			ChannelOpen->TdmConfig.ulSinPcmLaw = law;
++			ChannelOpen->TdmConfig.ulSinStream = 1;
++			ChannelOpen->TdmConfig.ulSinTimeslot = x;
++			ChannelOpen->TdmConfig.ulSoutPcmLaw = law;
++			ChannelOpen->TdmConfig.ulSoutStream = 2;
++			ChannelOpen->TdmConfig.ulSoutTimeslot = x;
++			ChannelOpen->TdmConfig.ulRoutPcmLaw = law;
++			ChannelOpen->TdmConfig.ulRoutStream = 3;
++			ChannelOpen->TdmConfig.ulRoutTimeslot = x;
++			ChannelOpen->VqeConfig.fEnableNlp = TRUE;
++			ChannelOpen->VqeConfig.fRinDcOffsetRemoval = TRUE;
++			ChannelOpen->VqeConfig.fSinDcOffsetRemoval = TRUE;
++			
++			ChannelOpen->fEnableToneDisabler = TRUE;
++			ChannelOpen->ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_DIGITAL;
++			
++			ulResult = Oct6100ChannelOpen(vpm450m->pApiInstance, ChannelOpen);
++			if (ulResult != GENERIC_OK) {
++				printk(KERN_NOTICE "Failed to open channel %d!\n", x);
++			}
++			for (y=0;y<sizeof(tones) / sizeof(tones[0]); y++) {
++				tOCT6100_TONE_DETECTION_ENABLE enable;
++				Oct6100ToneDetectionEnableDef(&enable);
++				enable.ulChannelHndl = vpm450m->aulEchoChanHndl[x];
++				enable.ulToneNumber = tones[y];
++				if (Oct6100ToneDetectionEnable(vpm450m->pApiInstance, &enable) != GENERIC_OK) 
++					printk(KERN_NOTICE "Failed to enable tone detection on channel %d for tone %d!\n", x, y);
++			}
++		}
++	}
++
++#ifdef CONFIG_4KSTACKS
++	local_irq_restore(flags);
++#endif
++	kfree(ChipOpen);
++	kfree(ChannelOpen);
++	return vpm450m;
++}
++
++void release_vpm450m(struct vpm450m *vpm450m)
++{
++	UINT32 ulResult;
++	tOCT6100_CHIP_CLOSE ChipClose;
++
++	Oct6100ChipCloseDef(&ChipClose);
++	ulResult = Oct6100ChipClose(vpm450m->pApiInstance, &ChipClose);
++	if (ulResult != cOCT6100_ERR_OK) {
++		printk(KERN_NOTICE "Failed to close chip, code %08x!\n", ulResult);
++	}
++	vfree(vpm450m->pApiInstance);
++	kfree(vpm450m);
++}
+diff --git a/drivers/dahdi/opvxd115/vpm450m.h b/drivers/dahdi/opvxd115/vpm450m.h
+new file mode 100644
+index 0000000..735a2cc
+--- /dev/null
++++ b/drivers/dahdi/opvxd115/vpm450m.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) 2005-2006 Digium, Inc.
++ *
++ * Mark Spencer <markster at digium.com>
++ *
++ * All Rights Reserved
++ *
++ */
++
++/*
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ */
++
++#ifndef _VPM450M_H
++#define _VPM450M_H
++
++#include <linux/firmware.h>
++
++struct vpm450m;
++
++/* From driver */
++unsigned int oct_get_reg(void *data, unsigned int reg);
++void oct_set_reg(void *data, unsigned int reg, unsigned int val);
++
++/* From vpm450m */
++struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware);
++unsigned int get_vpm450m_capacity(void *wc);
++void vpm450m_setec(struct vpm450m *instance, int channel, int eclen);
++void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int dtmfmute);
++int vpm450m_checkirq(struct vpm450m *vpm450m);
++int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start);
++void release_vpm450m(struct vpm450m *instance);
++
++#endif
+diff --git a/drivers/dahdi/wcopenpci.c b/drivers/dahdi/wcopenpci.c
+new file mode 100644
+index 0000000..e5567ca
+--- /dev/null
++++ b/drivers/dahdi/wcopenpci.c
 @@ -0,0 +1,1850 @@
 +/*
 + * Voicetronix OpenPCI Interface Driver for Zapata Telephony interface
@@ -7929,9 +14193,27 @@
 +MODULE_VERSION(DAHDI_VERSION);
 +MODULE_LICENSE("GPL");
 +
-diff -urN dahdi-svn-orig/drivers/dahdi/zaphfc/base.c dahdi-svn-new/drivers/dahdi/zaphfc/base.c
---- dahdi-svn-orig/drivers/dahdi/zaphfc/base.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/zaphfc/base.c	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/zaphfc/Kbuild b/drivers/dahdi/zaphfc/Kbuild
+new file mode 100644
+index 0000000..960fb3a
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/Kbuild
+@@ -0,0 +1,10 @@
++obj-m += zaphfc.o
++
++EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
++
++zaphfc-objs := base.o fifo.o
++
++$(obj)/base.o: $(src)/zaphfc.h
++$(obj)/fifo.o: $(src)/fifo.h
++
++
+diff --git a/drivers/dahdi/zaphfc/base.c b/drivers/dahdi/zaphfc/base.c
+new file mode 100644
+index 0000000..0996b51
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/base.c
 @@ -0,0 +1,1710 @@
 +/*
 + * zaphfc.c - Dahdi driver for HFC-S PCI A based ISDN BRI cards
@@ -9643,9 +15925,11 @@
 +#ifdef DEBUG
 +MODULE_PARM_DESC(debug_level, "Debug verbosity level");
 +#endif
-diff -urN dahdi-svn-orig/drivers/dahdi/zaphfc/fifo.c dahdi-svn-new/drivers/dahdi/zaphfc/fifo.c
---- dahdi-svn-orig/drivers/dahdi/zaphfc/fifo.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/zaphfc/fifo.c	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/zaphfc/fifo.c b/drivers/dahdi/zaphfc/fifo.c
+new file mode 100644
+index 0000000..8c23fa3
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/fifo.c
 @@ -0,0 +1,375 @@
 +/*
 + * fifo.c - HFC FIFO management routines
@@ -10022,9 +16306,11 @@
 +	}
 +}
 +
-diff -urN dahdi-svn-orig/drivers/dahdi/zaphfc/fifo.h dahdi-svn-new/drivers/dahdi/zaphfc/fifo.h
---- dahdi-svn-orig/drivers/dahdi/zaphfc/fifo.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/zaphfc/fifo.h	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/zaphfc/fifo.h b/drivers/dahdi/zaphfc/fifo.h
+new file mode 100644
+index 0000000..1866f30
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/fifo.h
 @@ -0,0 +1,139 @@
 +/*
 + * fifo.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
@@ -10165,23 +16451,11 @@
 +void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan);
 +
 +#endif
-diff -urN dahdi-svn-orig/drivers/dahdi/zaphfc/Kbuild dahdi-svn-new/drivers/dahdi/zaphfc/Kbuild
---- dahdi-svn-orig/drivers/dahdi/zaphfc/Kbuild	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/zaphfc/Kbuild	2011-03-07 11:52:51.411050187 +0200
-@@ -0,0 +1,10 @@
-+obj-m += zaphfc.o
-+
-+EXTRA_CFLAGS := -I$(src)/.. -Wno-undef
-+
-+zaphfc-objs := base.o fifo.o
-+
-+$(obj)/base.o: $(src)/zaphfc.h
-+$(obj)/fifo.o: $(src)/fifo.h
-+
-+
-diff -urN dahdi-svn-orig/drivers/dahdi/zaphfc/zaphfc.h dahdi-svn-new/drivers/dahdi/zaphfc/zaphfc.h
---- dahdi-svn-orig/drivers/dahdi/zaphfc/zaphfc.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/dahdi/zaphfc/zaphfc.h	2011-03-07 11:52:51.411050187 +0200
+diff --git a/drivers/dahdi/zaphfc/zaphfc.h b/drivers/dahdi/zaphfc/zaphfc.h
+new file mode 100644
+index 0000000..29dd304
+--- /dev/null
++++ b/drivers/dahdi/zaphfc/zaphfc.h
 @@ -0,0 +1,418 @@
 +/*
 + * zaphfc.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
@@ -10601,9 +16875,23 @@
 +}
 +
 +#endif
-diff -urN dahdi-svn-orig/drivers/staging/echo/echo.c dahdi-svn-new/drivers/staging/echo/echo.c
---- dahdi-svn-orig/drivers/staging/echo/echo.c	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/echo.c	2011-03-07 11:52:51.415060067 +0200
+diff --git a/drivers/staging/echo/Kbuild b/drivers/staging/echo/Kbuild
+new file mode 100644
+index 0000000..f813006
+--- /dev/null
++++ b/drivers/staging/echo/Kbuild
+@@ -0,0 +1,6 @@
++ifdef DAHDI_USE_MMX
++EXTRA_CFLAGS += -DUSE_MMX
++endif
++
++# An explicit 'obj-m' , unlike the Makefile
++obj-m += echo.o
+diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c
+new file mode 100644
+index 0000000..4cc4f2e
+--- /dev/null
++++ b/drivers/staging/echo/echo.c
 @@ -0,0 +1,662 @@
 +/*
 + * SpanDSP - a series of DSP components for telephony
@@ -11267,9 +17555,11 @@
 +MODULE_AUTHOR("David Rowe");
 +MODULE_DESCRIPTION("Open Source Line Echo Canceller");
 +MODULE_VERSION("0.3.0");
-diff -urN dahdi-svn-orig/drivers/staging/echo/echo.h dahdi-svn-new/drivers/staging/echo/echo.h
---- dahdi-svn-orig/drivers/staging/echo/echo.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/echo.h	2011-03-07 11:52:51.415060067 +0200
+diff --git a/drivers/staging/echo/echo.h b/drivers/staging/echo/echo.h
+new file mode 100644
+index 0000000..754e66d
+--- /dev/null
++++ b/drivers/staging/echo/echo.h
 @@ -0,0 +1,175 @@
 +/*
 + * SpanDSP - a series of DSP components for telephony
@@ -11446,9 +17736,11 @@
 +};
 +
 +#endif /* __ECHO_H */
-diff -urN dahdi-svn-orig/drivers/staging/echo/fir.h dahdi-svn-new/drivers/staging/echo/fir.h
---- dahdi-svn-orig/drivers/staging/echo/fir.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/fir.h	2011-03-07 11:52:51.415060067 +0200
+diff --git a/drivers/staging/echo/fir.h b/drivers/staging/echo/fir.h
+new file mode 100644
+index 0000000..288bffc
+--- /dev/null
++++ b/drivers/staging/echo/fir.h
 @@ -0,0 +1,286 @@
 +/*
 + * SpanDSP - a series of DSP components for telephony
@@ -11736,19 +18028,11 @@
 +}
 +
 +#endif
-diff -urN dahdi-svn-orig/drivers/staging/echo/Kbuild dahdi-svn-new/drivers/staging/echo/Kbuild
---- dahdi-svn-orig/drivers/staging/echo/Kbuild	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/Kbuild	2011-03-07 11:52:51.415060067 +0200
-@@ -0,0 +1,6 @@
-+ifdef DAHDI_USE_MMX
-+EXTRA_CFLAGS += -DUSE_MMX
-+endif
-+
-+# An explicit 'obj-m' , unlike the Makefile
-+obj-m += echo.o
-diff -urN dahdi-svn-orig/drivers/staging/echo/mmx.h dahdi-svn-new/drivers/staging/echo/mmx.h
---- dahdi-svn-orig/drivers/staging/echo/mmx.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/mmx.h	2011-03-07 11:52:51.415060067 +0200
+diff --git a/drivers/staging/echo/mmx.h b/drivers/staging/echo/mmx.h
+new file mode 100644
+index 0000000..c030cdf
+--- /dev/null
++++ b/drivers/staging/echo/mmx.h
 @@ -0,0 +1,288 @@
 +/*
 + * mmx.h
@@ -12038,9 +18322,11 @@
 +
 +
 +#endif /* AVCODEC_I386MMX_H */
-diff -urN dahdi-svn-orig/drivers/staging/echo/oslec.h dahdi-svn-new/drivers/staging/echo/oslec.h
---- dahdi-svn-orig/drivers/staging/echo/oslec.h	1970-01-01 02:00:00.000000000 +0200
-+++ dahdi-svn-new/drivers/staging/echo/oslec.h	2011-03-07 11:52:51.415060067 +0200
+diff --git a/drivers/staging/echo/oslec.h b/drivers/staging/echo/oslec.h
+new file mode 100644
+index 0000000..f417536
+--- /dev/null
++++ b/drivers/staging/echo/oslec.h
 @@ -0,0 +1,94 @@
 +/*
 + *  OSLEC - A line echo canceller.  This code is being developed

Added: dahdi-linux/trunk/debian/patches/define_spinlock
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/patches/define_spinlock?rev=8989&op=file
==============================================================================
--- dahdi-linux/trunk/debian/patches/define_spinlock (added)
+++ dahdi-linux/trunk/debian/patches/define_spinlock Sun Jun 19 17:03:58 2011
@@ -1,0 +1,298 @@
+From: Shaun Ruffell <sruffell at digium.com>
+Date: Fri, 27 May 2011 16:48:46 +0000
+Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9411
+Subject: Move test for DEFINE_SPINLOCK into include/dahdi/kernel.h
+
+The check for DEFINE_SPINLOCK was spread throughout the source tree. If
+not defined we can just define it in inlucde/dahdi/kernel.h.  Now
+include/dahdi/kernel.h is the only place that references
+SPIN_LOCK_UNLOCKED (which breaks lockdep checking if DEFINE_SPINLOCK is
+otherwise defined in the kernel).
+
+Signed-off-by: Shaun Ruffell <sruffell at digium.com>
+Acked-by: Kinsey Moore <kmoore at digium.com>
+Acked-by: Russ Meyerriecks <rmeyerriecks at digium.com>
+Acked-by: Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+Review: https://reviewboard.asterisk.org/r/940/
+
+Already included in upstream branch 2.4 and should be included in any
+new release.
+
+Fixes build issues with newer kernels.
+
+---
+ drivers/dahdi/dahdi-base.c          |    5 -----
+ drivers/dahdi/dahdi_dynamic.c       |    5 -----
+ drivers/dahdi/dahdi_dynamic_eth.c   |    4 ----
+ drivers/dahdi/dahdi_dynamic_ethmf.c |    6 +-----
+ drivers/dahdi/dahdi_dynamic_loc.c   |    4 ----
+ drivers/dahdi/dahdi_transcode.c     |    2 +-
+ drivers/dahdi/tor2.c                |    4 ----
+ drivers/dahdi/wct4xxp/base.c        |    4 ----
+ drivers/dahdi/wcte12xp/base.c       |    1 -
+ drivers/dahdi/wcte12xp/wcte12xp.h   |    2 --
+ drivers/dahdi/xpp/mmapdrv.c         |    2 +-
+ drivers/dahdi/xpp/parport_debug.c   |    2 +-
+ drivers/dahdi/xpp/xbus-core.c       |    4 ++--
+ drivers/dahdi/xpp/xbus-pcm.c        |    4 ++--
+ drivers/dahdi/xpp/xpp_usb.c         |    2 +-
+ include/dahdi/kernel.h              |    4 ++++
+ 16 files changed, 13 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
+index b98cf35..cc04a60 100644
+--- a/drivers/dahdi/dahdi-base.c
++++ b/drivers/dahdi/dahdi-base.c
+@@ -386,13 +386,8 @@ struct dahdi_timer {
+ 
+ static LIST_HEAD(zaptimers);
+ 
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(zaptimerlock);
+ static DEFINE_SPINLOCK(bigzaplock);
+-#else
+-static spinlock_t zaptimerlock = SPIN_LOCK_UNLOCKED;
+-static spinlock_t bigzaplock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ struct dahdi_zone {
+ 	atomic_t refcount;
+diff --git a/drivers/dahdi/dahdi_dynamic.c b/drivers/dahdi/dahdi_dynamic.c
+index 31a6c30..f0b61ff 100644
+--- a/drivers/dahdi/dahdi_dynamic.c
++++ b/drivers/dahdi/dahdi_dynamic.c
+@@ -113,13 +113,8 @@ struct dahdi_dynamic {
+ 	struct list_head list;
+ };
+ 
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(dspan_lock);
+ static DEFINE_SPINLOCK(driver_lock);
+-#else
+-static spinlock_t dspan_lock = SPIN_LOCK_UNLOCKED;
+-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ static LIST_HEAD(dspan_list);
+ static LIST_HEAD(driver_list);
+diff --git a/drivers/dahdi/dahdi_dynamic_eth.c b/drivers/dahdi/dahdi_dynamic_eth.c
+index 449a971..31566d6 100644
+--- a/drivers/dahdi/dahdi_dynamic_eth.c
++++ b/drivers/dahdi/dahdi_dynamic_eth.c
+@@ -42,11 +42,7 @@ struct ztdeth_header {
+ 
+ /* We take the raw message, put it in an ethernet frame, and add a
+    two byte addressing header at the top for future use */
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(zlock);
+-#else
+-static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ static struct sk_buff_head skbs;
+ 
+diff --git a/drivers/dahdi/dahdi_dynamic_ethmf.c b/drivers/dahdi/dahdi_dynamic_ethmf.c
+index f8670c8..126001f 100644
+--- a/drivers/dahdi/dahdi_dynamic_ethmf.c
++++ b/drivers/dahdi/dahdi_dynamic_ethmf.c
+@@ -129,11 +129,7 @@ struct ztdeth {
+ /**
+  * Lock for adding and removing items in ethmf_list
+  */
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(ethmf_lock);
+-#else
+-static spinlock_t ethmf_lock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ /**
+  * The active list of all running spans
+@@ -401,7 +397,7 @@ static int ztdethmf_transmit(void *pvt, unsigned char *msg, int msglen)
+ 	unsigned char addr[ETH_ALEN];
+ 	int spans_ready = 0, index = 0;
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
+-	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
++	static DEFINE_SPINLOCK(lock);
+ 	unsigned long flags;
+ #endif
+ 
+diff --git a/drivers/dahdi/dahdi_dynamic_loc.c b/drivers/dahdi/dahdi_dynamic_loc.c
+index 913f278..876cba4 100644
+--- a/drivers/dahdi/dahdi_dynamic_loc.c
++++ b/drivers/dahdi/dahdi_dynamic_loc.c
+@@ -57,11 +57,7 @@
+ 
+ #include <dahdi/kernel.h>
+ 
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(zlock);
+-#else
+-static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ static struct ztdlocal {
+ 	unsigned short key;
+diff --git a/drivers/dahdi/dahdi_transcode.c b/drivers/dahdi/dahdi_transcode.c
+index f5e749b..958e036 100644
+--- a/drivers/dahdi/dahdi_transcode.c
++++ b/drivers/dahdi/dahdi_transcode.c
+@@ -46,7 +46,7 @@ static LIST_HEAD(registration_list);
+  * is used as a simplistic way to spread the load amongst the different hardware
+  * transcoders in the system. */
+ static LIST_HEAD(active_list);
+-static spinlock_t translock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(translock);
+ 
+ EXPORT_SYMBOL(dahdi_transcoder_register);
+ EXPORT_SYMBOL(dahdi_transcoder_unregister);
+diff --git a/drivers/dahdi/tor2.c b/drivers/dahdi/tor2.c
+index 5b1dcf7..f30f9f7 100644
+--- a/drivers/dahdi/tor2.c
++++ b/drivers/dahdi/tor2.c
+@@ -1129,11 +1129,7 @@ static void tor2_tasklet(unsigned long data)
+ static int syncsrc = 0;
+ static int syncnum = 0 /* -1 */;
+ static int syncspan = 0;
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(synclock);
+-#else
+-static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ static int tor2_findsync(struct tor2 *tor)
+ {
+diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
+index 72858c3..81ef89e 100644
+--- a/drivers/dahdi/wct4xxp/base.c
++++ b/drivers/dahdi/wct4xxp/base.c
+@@ -2231,11 +2231,7 @@ static void t4_serial_setup(struct t4 *wc, int unit)
+ static int syncsrc = 0;
+ static int syncnum = 0 /* -1 */;
+ static int syncspan = 0;
+-#ifdef DEFINE_SPINLOCK
+ static DEFINE_SPINLOCK(synclock);
+-#else
+-static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+-#endif
+ 
+ static void __t4_set_rclk_src(struct t4 *wc, int span)
+ {
+diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
+index bb88691..5f720a1 100644
+--- a/drivers/dahdi/wcte12xp/base.c
++++ b/drivers/dahdi/wcte12xp/base.c
+@@ -88,7 +88,6 @@ static const struct dahdi_echocan_ops vpm150m_ec_ops = {
+ };
+ 
+ static struct t1 *ifaces[WC_MAX_IFACES];
+-spinlock_t ifacelock = SPIN_LOCK_UNLOCKED;
+ 
+ struct t1_desc {
+ 	const char *name;
+diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h
+index 8c04afe..094ce91 100644
+--- a/drivers/dahdi/wcte12xp/wcte12xp.h
++++ b/drivers/dahdi/wcte12xp/wcte12xp.h
+@@ -77,8 +77,6 @@
+ #define TYPE_T1	1
+ #define TYPE_E1	2
+ 
+-extern spinlock_t ifacelock;
+-
+ struct command {
+ 	struct list_head node;
+ 	struct completion complete;
+diff --git a/drivers/dahdi/xpp/mmapdrv.c b/drivers/dahdi/xpp/mmapdrv.c
+index 6f38587..1ca3140 100644
+--- a/drivers/dahdi/xpp/mmapdrv.c
++++ b/drivers/dahdi/xpp/mmapdrv.c
+@@ -68,7 +68,7 @@ struct counter {
+ 
+ static xbus_t *global_xbus;
+ static bool tx_ready = 1;
+-static spinlock_t tx_ready_lock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(tx_ready_lock);
+ static struct xframe_queue txpool;
+ static unsigned int pcm_in_pool_count;
+ static bool disconnecting;
+diff --git a/drivers/dahdi/xpp/parport_debug.c b/drivers/dahdi/xpp/parport_debug.c
+index 93049ef..23c0b41 100644
+--- a/drivers/dahdi/xpp/parport_debug.c
++++ b/drivers/dahdi/xpp/parport_debug.c
+@@ -36,7 +36,7 @@ static int		parport_toggles[8];	/* 8 bit flip-flop */
+ void flip_parport_bit(unsigned char bitnum)
+ {
+ 	static unsigned char	last_value;
+-	spinlock_t	lock = SPIN_LOCK_UNLOCKED;
++	DEFINE_SPINLOCK(lock);
+ 	unsigned long	flags;
+ 	unsigned char	mask;
+ 	unsigned char	value;
+diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
+index 542d578..ebc7cba 100644
+--- a/drivers/dahdi/xpp/xbus-core.c
++++ b/drivers/dahdi/xpp/xbus-core.c
+@@ -78,7 +78,7 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s
+ static void transport_destroy(xbus_t *xbus);
+ 
+ /* Data structures */
+-static spinlock_t		xbuses_lock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(xbuses_lock);
+ #ifdef	CONFIG_PROC_FS
+ static struct proc_dir_entry	*proc_xbuses = NULL;
+ #endif
+@@ -405,7 +405,7 @@ xpacket_t *xframe_next_packet(xframe_t *frm, int len)
+ 	return (xpacket_t *)(frm->packets + newlen - len);
+ }
+ 
+-static spinlock_t serialize_dump_xframe = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(serialize_dump_xframe);
+ 
+ static void do_hexdump(const char msg[], byte *data, uint16_t len)
+ {
+diff --git a/drivers/dahdi/xpp/xbus-pcm.c b/drivers/dahdi/xpp/xbus-pcm.c
+index 39b772b..cad61fb 100644
+--- a/drivers/dahdi/xpp/xbus-pcm.c
++++ b/drivers/dahdi/xpp/xbus-pcm.c
+@@ -55,8 +55,8 @@ static struct xpp_ticker	dahdi_ticker;
+  * I.e: one of our AB or dahdi_ticker
+  */
+ static struct xpp_ticker	*ref_ticker = NULL;
+-static spinlock_t		ref_ticker_lock = SPIN_LOCK_UNLOCKED;
+-static spinlock_t		elect_syncer_lock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(ref_ticker_lock);
++static DEFINE_SPINLOCK(elect_syncer_lock);
+ static bool			force_dahdi_sync = 0;	/* from /sys/bus/astribanks/drivers/xppdrv/sync */
+ static xbus_t			*global_ticker;
+ static struct xpp_ticker	global_ticks_series;
+diff --git a/drivers/dahdi/xpp/xpp_usb.c b/drivers/dahdi/xpp/xpp_usb.c
+index 83fba83..7f370ee 100644
+--- a/drivers/dahdi/xpp/xpp_usb.c
++++ b/drivers/dahdi/xpp/xpp_usb.c
+@@ -242,7 +242,7 @@ struct xusb {
+ 
+ };
+ 
+-static	spinlock_t	xusb_lock = SPIN_LOCK_UNLOCKED;
++static DEFINE_SPINLOCK(xusb_lock);
+ static xusb_t *xusb_array[MAX_BUSES] = {};
+ static unsigned bus_count = 0;
+ 
+diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
+index 1819e13..f5980f7 100644
+--- a/include/dahdi/kernel.h
++++ b/include/dahdi/kernel.h
+@@ -1285,6 +1285,10 @@ wait_for_completion_interruptible_timeout(struct completion *x,
+ 	const struct pci_device_id _x[] __devinitdata
+ #endif
+ 
++#ifndef DEFINE_SPINLOCK
++#define DEFINE_SPINLOCK(x)      spinlock_t x = SPIN_LOCK_UNLOCKED
++#endif
++
+ #ifndef DMA_BIT_MASK
+ #define DMA_BIT_MASK(n)	(((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+ #endif
+-- 
+1.7.5.3
+

Modified: dahdi-linux/trunk/debian/patches/series
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/patches/series?rev=8989&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/patches/series (original)
+++ dahdi-linux/trunk/debian/patches/series Sun Jun 19 17:03:58 2011
@@ -4,3 +4,4 @@
 no_firmware_download
 chanmute
 wcb4xxp_bn4s0e
+define_spinlock

Modified: dahdi-linux/trunk/debian/rules
URL: http://svn.debian.org/wsvn/pkg-voip/dahdi-linux/trunk/debian/rules?rev=8989&op=diff
==============================================================================
--- dahdi-linux/trunk/debian/rules (original)
+++ dahdi-linux/trunk/debian/rules Sun Jun 19 17:03:58 2011
@@ -43,14 +43,12 @@
 # the generated headers as part of the source:
 GENERATED_SOURCES := include/dahdi/version.h
 
-EXTRA_MODS=opvxa1200
+EXTRA_MODS=dahdi_echocan_oslec
+EXTRA_SUBDIRS = ap400 opvxa1200 opvxd115 zaphfc ../staging/echo
 
 ifneq (,$(filter-out powerpc m68k armeb mips,$(shell dpkg-architecture -qDEB_HOST_ARCH)))
 EXTRA_MODS += wcopenpci
 endif
-
-EXTRA_SUBDIRS += zaphfc ../staging/echo
-EXTRA_MODS += dahdi_echocan_oslec
 
 MOD_ARGS=MODULES_EXTRA="$(EXTRA_MODS)" SUBDIRS_EXTRA="$(EXTRA_SUBDIRS)"
 




More information about the Pkg-voip-commits mailing list