aboutsummaryrefslogtreecommitdiff
path: root/system/dahdi-complete
diff options
context:
space:
mode:
Diffstat (limited to 'system/dahdi-complete')
-rw-r--r--system/dahdi-complete/dahdi-complete.SlackBuild20
-rw-r--r--system/dahdi-complete/dahdi-complete.info6
-rw-r--r--system/dahdi-complete/dahdi-tools-3.1.0-fno-common.patch43
-rw-r--r--system/dahdi-complete/doinst.sh7
-rw-r--r--system/dahdi-complete/patches/01-no-depmod.patch12
-rw-r--r--system/dahdi-complete/patches/02-parallel-make.patch34
-rw-r--r--system/dahdi-complete/patches/04-dahdi-3.1.0-kernel-5.4-support.patch15
-rw-r--r--system/dahdi-complete/patches/05-dahdi-3.1.0-r1-div_s64-for-32-bit-arches.patch11
-rw-r--r--system/dahdi-complete/patches/06-non-digium-hardware-and-oslec.patch18351
-rw-r--r--system/dahdi-complete/patches/07-dahdi-3.1.0-r1-kernel5.6.patch392
-rw-r--r--system/dahdi-complete/patches/08-digium-restore-old-hardwareids.patch29
-rw-r--r--system/dahdi-complete/patches/09-dahdi-3.1.0-r3-remove-32bit-userspace-on-64bit-support.patch94
-rw-r--r--system/dahdi-complete/patches/10-dahdi-3.1.0-r3-ioctl-kernel-5.9.patch155
-rw-r--r--system/dahdi-complete/patches/11-dahdi-3.1.0-r3-clang.patch115
14 files changed, 57 insertions, 19227 deletions
diff --git a/system/dahdi-complete/dahdi-complete.SlackBuild b/system/dahdi-complete/dahdi-complete.SlackBuild
index 89bcd3ee72fdf..db7da3730dbdd 100644
--- a/system/dahdi-complete/dahdi-complete.SlackBuild
+++ b/system/dahdi-complete/dahdi-complete.SlackBuild
@@ -12,7 +12,7 @@
cd $(dirname $0) ; CWD=$(pwd)
PRGNAM=dahdi-complete
-VERSION=${VERSION:-3.1.0}
+VERSION=${VERSION:-20201116_5c840cf}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
PKGTYPE=${PKGTYPE:-tgz}
@@ -61,9 +61,9 @@ set -e
rm -rf $PKG
mkdir -p $TMP $PKG $OUTPUT
cd $TMP
-rm -rf $ARCHIVE_NAME-$VERSION+$VERSION
-tar zxvf $CWD/$ARCHIVE_NAME-$VERSION+$VERSION.tar.gz
-cd $ARCHIVE_NAME-$VERSION+$VERSION
+rm -rf $ARCHIVE_NAME-$VERSION
+tar xvf $CWD/$ARCHIVE_NAME-$VERSION.tar.?z
+cd $ARCHIVE_NAME-$VERSION
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 \
@@ -75,18 +75,21 @@ sed -i -e 's/ -Werror//' tools/acinclude.m4 tools/xpp/Makefile.am
sed -i -e 's/-Werror //' tools/Makefile.am
# Fix Perl install location (otherwise it installs to /usr/local/share/perl5)
-sed -i -e 's/sitelib/vendorlib/' linux/build_tools/live_dahdi tools/xpp/Makefile.am
+sed -i -e 's/sitelib/vendorlib/' linux/build_tools/live_dahdi tools/xpp/Makefile.am || exit 1
cd linux
# thanks Gentoo for the patches!
-for i in $CWD/patches/* ; do patch -p1 < $i ; done
+#for i in $CWD/patches/* ; do patch -p1 < $i ; done
make all
+make install DESTDIR=$PKG
cd ../tools
+# thanks debian for this patch!
+patch -p1 < $CWD/dahdi-tools-3.1.0-fno-common.patch
./bootstrap.sh
autoreconf -fi
CPPFLAGS="-I$(pwd)/../linux/include" \
-CFLAGS="$SLKCFLAGS -w -Wl,--allow-multiple-definition" \
+CFLAGS="$SLKCFLAGS" \
CXXFLAGS="$SLKCFLAGS" \
./configure \
--prefix=/usr \
@@ -101,7 +104,6 @@ CXXFLAGS="$SLKCFLAGS" \
make
make install DESTDIR=$PKG
cd ..
-make config DESTDIR=$PKG
mkdir -p $PKG/usr/share/perl5/vendor_perl
mv $PKG/usr/local/share/perl5/* $PKG/usr/share/perl5/vendor_perl/
@@ -113,7 +115,7 @@ for file in $(find . -type f); do
mv $file "$file.new"
done
-install -D -m 0644 $TMP/$ARCHIVE_NAME-$VERSION+$VERSION/tools/dahdi.init $PKG/etc/rc.d/rc.dahdi.new
+install -D -m 0644 $TMP/$ARCHIVE_NAME-$VERSION/tools/dahdi.init $PKG/etc/rc.d/rc.dahdi.new
find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
| cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true
diff --git a/system/dahdi-complete/dahdi-complete.info b/system/dahdi-complete/dahdi-complete.info
index 4babd84a54001..ca4750d0dfcd0 100644
--- a/system/dahdi-complete/dahdi-complete.info
+++ b/system/dahdi-complete/dahdi-complete.info
@@ -1,8 +1,8 @@
PRGNAM="dahdi-complete"
-VERSION="3.1.0"
+VERSION="20201116_5c840cf"
HOMEPAGE="http://www.asterisk.org/downloads/dahdi"
-DOWNLOAD="http://downloads.asterisk.org/pub/telephony/dahdi-linux-complete/releases/dahdi-linux-complete-3.1.0+3.1.0.tar.gz"
-MD5SUM="04f04b7986ad5fedd5d5602d55764015"
+DOWNLOAD="https://ponce.cc/slackware/sources/repo/dahdi-linux-complete-20201116_5c840cf.tar.xz"
+MD5SUM="b1f710e9b8c8b607722b39f58d3ae091"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES=""
diff --git a/system/dahdi-complete/dahdi-tools-3.1.0-fno-common.patch b/system/dahdi-complete/dahdi-tools-3.1.0-fno-common.patch
new file mode 100644
index 0000000000000..f9dd5a49bd04f
--- /dev/null
+++ b/system/dahdi-complete/dahdi-tools-3.1.0-fno-common.patch
@@ -0,0 +1,43 @@
+From: Jaco Kroon <jaco@uls.co.za>
+Subject: Remove unused union names that break build
+Bug: https://issues.asterisk.org/jira/browse/DAHTOOL-85
+
+diff --git a/xpp/mpptalk.c b/xpp/mpptalk.c
+index fdb34f1..8fb3687 100644
+--- a/xpp/mpptalk.c
++++ b/xpp/mpptalk.c
+@@ -237,7 +237,7 @@ union XTALK_PDATA(MPP) {
+ MEMBER(MPP, TWS_PORT_GET_REPLY);
+ MEMBER(MPP, TWS_PWR_GET);
+ MEMBER(MPP, TWS_PWR_GET_REPLY);
+-} PACKED members;
++} PACKED;
+
+ /*
+ * Statuses
+diff --git a/xpp/xtalk/xtalk_raw.c b/xpp/xtalk/xtalk_raw.c
+index 49e47d5..251a502 100644
+--- a/xpp/xtalk/xtalk_raw.c
++++ b/xpp/xtalk/xtalk_raw.c
+@@ -48,7 +48,7 @@ CMD_DEF(XTALK, ACK,
+
+ union XTALK_PDATA(XTALK) {
+ MEMBER(XTALK, ACK);
+-} PACKED members;
++} PACKED;
+
+ const struct xtalk_protocol xtalk_raw_proto = {
+ .name = "XTALK-RAW",
+diff --git a/xpp/xtalk/xtalk_sync.c b/xpp/xtalk/xtalk_sync.c
+index 18a5cad..ffa79d2 100644
+--- a/xpp/xtalk/xtalk_sync.c
++++ b/xpp/xtalk/xtalk_sync.c
+@@ -60,7 +60,7 @@ union XTALK_PDATA(XTALK) {
+ MEMBER(XTALK, ACK);
+ MEMBER(XTALK, PROTO_GET);
+ MEMBER(XTALK, PROTO_GET_REPLY);
+-} PACKED members;
++} PACKED;
+
+ const struct xtalk_protocol xtalk_sync_proto = {
+ .name = "XTALK-SYNC",
diff --git a/system/dahdi-complete/doinst.sh b/system/dahdi-complete/doinst.sh
index 33374db8b9d03..f60ce1aa4bbdf 100644
--- a/system/dahdi-complete/doinst.sh
+++ b/system/dahdi-complete/doinst.sh
@@ -29,15 +29,8 @@ preserve_perms etc/rc.d/rc.dahdi.new
config etc/udev/rules.d/xpp.rules.new
config etc/udev/rules.d/dahdi.rules.new
-config etc/hotplug/usb/xpp_fxloader.usermap.new
-config etc/dahdi/system.conf.new
config etc/dahdi/assigned-spans.conf.sample.new
config etc/dahdi/span-types.conf.sample.new
-config etc/dahdi/init.conf.new
-config etc/dahdi/modules.new
-config etc/dahdi/genconf_parameters.new
config etc/bash_completion.d/dahdi.new
-config etc/modprobe.d/dahdi.conf.new
-config etc/modprobe.d/dahdi.blacklist.conf.new
chroot . /sbin/depmod -a
diff --git a/system/dahdi-complete/patches/01-no-depmod.patch b/system/dahdi-complete/patches/01-no-depmod.patch
deleted file mode 100644
index d4286c35ad97a..0000000000000
--- a/system/dahdi-complete/patches/01-no-depmod.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -uNr dahdi-linux-2.8.0.ORIG//Makefile dahdi-linux-2.8.0/Makefile
---- dahdi-linux-2.8.0.ORIG//Makefile 2010-09-09 14:41:11.000000000 +0100
-+++ dahdi-linux-2.8.0/Makefile 2010-09-09 14:41:27.000000000 +0100
-@@ -139,7 +139,7 @@
- build_tools/uninstall-modules dahdi $(KVERS)
- endif
- $(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=dahdi modules_install
-- [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
-+# [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
-
- uninstall-modules:
- ifdef DESTDIR
diff --git a/system/dahdi-complete/patches/02-parallel-make.patch b/system/dahdi-complete/patches/02-parallel-make.patch
deleted file mode 100644
index 946780c2669b3..0000000000000
--- a/system/dahdi-complete/patches/02-parallel-make.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-diff -uNr dahdi-linux-2.8.0.ORIG//Makefile dahdi-linux-2.8.0/Makefile
---- dahdi-linux-2.8.0/Makefile.ORIG 2013-08-07 13:48:28.909267134 +0100
-+++ dahdi-linux-2.8.0/Makefile 2013-08-07 13:50:10.346268656 +0100
-@@ -71,7 +71,7 @@
- @echo "You do not appear to have the sources for the $(KVERS) kernel installed."
- @exit 1
- endif
-- $(KMAKE) modules DAHDI_BUILD_ALL=$(DAHDI_BUILD_ALL)
-+ +$(KMAKE) modules DAHDI_BUILD_ALL=$(DAHDI_BUILD_ALL)
-
- include/dahdi/version.h: FORCE
- @DAHDIVERSION="${DAHDIVERSION}" build_tools/make_version_h > $@.tmp
-@@ -138,7 +138,7 @@
- fi
- build_tools/uninstall-modules dahdi $(KVERS)
- endif
-- $(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=dahdi modules_install
-+ +$(KMAKE) INSTALL_MOD_PATH=$(DESTDIR) INSTALL_MOD_DIR=dahdi modules_install
- # [ `id -u` = 0 ] && /sbin/depmod -a $(KVERS) || :
-
- uninstall-modules:
-@@ -174,11 +174,11 @@
-
- clean:
- ifneq (no,$(HAS_KSRC))
-- $(KMAKE) clean
-+ +$(KMAKE) clean
- endif
- @rm -f $(GENERATED_DOCS)
- $(MAKE) -C drivers/dahdi/firmware clean
- $(MAKE) -C $(KSRC) M='$(PWD)/drivers/dahdi/oct612x' clean
-
- distclean: dist-clean
-
diff --git a/system/dahdi-complete/patches/04-dahdi-3.1.0-kernel-5.4-support.patch b/system/dahdi-complete/patches/04-dahdi-3.1.0-kernel-5.4-support.patch
deleted file mode 100644
index e7a2527f06055..0000000000000
--- a/system/dahdi-complete/patches/04-dahdi-3.1.0-kernel-5.4-support.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
-index 22b9b66..eacf6e0 100644
---- a/include/dahdi/kernel.h
-+++ b/include/dahdi/kernel.h
-@@ -59,8 +59,10 @@
- #include <linux/poll.h>
-
- #ifdef CONFIG_PCI
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)
- #include <linux/pci-aspm.h>
- #endif
-+#endif
-
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
- #define HAVE_NET_DEVICE_OPS
diff --git a/system/dahdi-complete/patches/05-dahdi-3.1.0-r1-div_s64-for-32-bit-arches.patch b/system/dahdi-complete/patches/05-dahdi-3.1.0-r1-div_s64-for-32-bit-arches.patch
deleted file mode 100644
index f9329edc2b7d4..0000000000000
--- a/system/dahdi-complete/patches/05-dahdi-3.1.0-r1-div_s64-for-32-bit-arches.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- dahdi-linux-3.1.0/drivers/dahdi/xpp/xpp_usb.c 2020-03-28 21:34:08.471611500 +0200
-+++ dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xpp_usb.c 2020-03-28 21:38:47.169161487 +0200
-@@ -882,7 +882,7 @@
- usec = 0; /* System clock jumped */
- if (usec > xusb->max_tx_delay)
- xusb->max_tx_delay = usec;
-- i = usec / USEC_BUCKET;
-+ i = div_s64(usec, USEC_BUCKET);
- if (i >= NUM_BUCKETS)
- i = NUM_BUCKETS - 1;
- xusb->usb_tx_delay[i]++;
diff --git a/system/dahdi-complete/patches/06-non-digium-hardware-and-oslec.patch b/system/dahdi-complete/patches/06-non-digium-hardware-and-oslec.patch
deleted file mode 100644
index 449f67f65cdd6..0000000000000
--- a/system/dahdi-complete/patches/06-non-digium-hardware-and-oslec.patch
+++ /dev/null
@@ -1,18351 +0,0 @@
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/ap400/ap400_drv.c dahdi-extra-dahdi-linux/drivers/dahdi/ap400/ap400_drv.c
---- dahdi-linux-2.7.0/drivers/dahdi/ap400/ap400_drv.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/ap400/ap400_drv.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,2341 @@
-+/*
-+ * AP4XX PCI Card Driver
-+ *
-+ * Written by Ronaldo Valiati <aligera@aligera.com.br>
-+ *
-+ * Based on previous works, designs, and architectures conceived and
-+ * written by Jim Dixon <jim@lambdatel.com> and Mark Spencer <markster@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/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/time.h>
-+#include <linux/delay.h>
-+#include <linux/proc_fs.h>
-+#include <dahdi/kernel.h>
-+#include <linux/moduleparam.h>
-+
-+#include "ap400.h"
-+
-+//#define AP400_DEBUG
-+#ifdef AP400_DEBUG
-+#define PDEBUG(fmt, args...) { \
-+ printk(KERN_DEBUG "AP400 (%d): ",__LINE__); \
-+ printk(fmt "\n", ## args); \
-+}
-+#else
-+#define PDEBUG(fmt, args...)
-+#endif
-+
-+/*
-+ * Tasklets provide better system interactive response at the cost of the
-+ * possibility of losing a frame of data at very infrequent intervals. If
-+ * you are more concerned with the performance of your machine, enable the
-+ * tasklets. If you are strict about absolutely no drops, then do not enable
-+ * tasklets.
-+ */
-+
-+/* #define ENABLE_TASKLETS */
-+
-+
-+/* 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 HDLC support by hardware */
-+#ifdef AP400_HDLC
-+#include "ap400_hdlc/ap400_hdlc.c"
-+#endif
-+
-+//#define APEC_SUPPORT
-+#ifdef APEC_SUPPORT
-+#include "apec.h"
-+#endif
-+
-+/* Workarounds */
-+#ifndef IRQF_SHARED
-+#define IRQF_SHARED SA_SHIRQ
-+#endif
-+#ifndef IRQF_DISABLED
-+#ifdef SA_INTERRUPT
-+#define IRQF_DISABLED SA_INTERRUPT
-+#else
-+#define IRQF_DISABLED 0x0
-+#endif
-+#endif
-+#ifndef __iomem
-+#define __iomem
-+#endif
-+
-+/* Enable prefetching may help performance */
-+#define ENABLE_PREFETCH
-+
-+/* Define to get more attention-grabbing but slightly more I/O using
-+ alarm status */
-+#define FANCY_ALARM
-+
-+#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)
-+
-+static int clock_source = -1;
-+static int tdm_loop = 0;
-+static int apec_enable = 1;
-+module_param(tdm_loop, int, 0600);
-+module_param(apec_enable, int, 0600);
-+
-+#ifdef ENABLE_WORKQUEUES
-+#include <linux/cpumask.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 {
-+ struct cpu_workqueue_struct cpu_wq[NR_CPUS];
-+ const char *name;
-+ struct list_head list; /* Empty if single thread */
-+};
-+
-+/* Preempt must be disabled. */
-+static void __ap4_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 ap4_queue_work(struct workqueue_struct *wq, struct work_struct *work, int cpu)
-+{
-+ int ret = 0;
-+
-+ if (!test_and_set_bit(0, &work->pending)) {
-+ BUG_ON(!list_empty(&work->entry));
-+ __ap4_queue_work(wq->cpu_wq + cpu, work);
-+ ret = 1;
-+ }
-+ return ret;
-+}
-+
-+#endif
-+
-+static int debug=0;
-+static int timingcable;
-+static int highestorder;
-+static int t1e1override = -1;
-+static int j1mode = 0;
-+static int loopback = 0;
-+static int alarmdebounce = 0;
-+
-+/* 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 = 1;
-+static int debugslips = 0;
-+static int polling = 0;
-+
-+#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 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 */
-+
-+struct devtype {
-+ char *desc;
-+ unsigned int flags;
-+};
-+
-+static struct devtype ap401 = { "Aligera AP401", 0 };
-+static struct devtype ap402 = { "Aligera AP402", 0 };
-+static struct devtype ap404 = { "Aligera AP404", 0 };
-+static struct devtype ape401 = { "Aligera APE401", 0 };
-+static struct devtype ape402 = { "Aligera APE402", 0 };
-+static struct devtype ape404 = { "Aligera APE404", 0 };
-+
-+struct ap4;
-+
-+struct ap4_span {
-+ struct ap4 *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 spanflags;
-+ int syncpos;
-+ int e1check; /* E1 check */
-+ int reload_cas;
-+ unsigned char casbuf[15];
-+ unsigned int slipcount;
-+ struct dahdi_span span;
-+ unsigned char txsigs[16]; /* Transmit sigs */
-+ int loopupcnt;
-+ int loopdowncnt;
-+ unsigned char ec_chunk1[31][DAHDI_CHUNKSIZE]; /* first EC chunk buffer */
-+ unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; /* second EC chunk buffer */
-+ int irqmisses;
-+#ifdef ENABLE_WORKQUEUES
-+ struct work_struct swork;
-+#endif
-+ struct dahdi_chan *chans[32]; /* Individual channels */
-+};
-+
-+struct ap4_regs {
-+ volatile u32 card_id; // 00h R0
-+ volatile u16 fpga_ver; // 04h R1
-+ volatile u16 span_num; // 06h R1
-+ u32 __unused; // 08h R2
-+ volatile u32 liu_config; // 0Ch R3
-+ volatile u32 e1_config; // 10h R4
-+ volatile u32 e1_status; // 14h R5
-+ volatile u32 leds; // 18h R6
-+ volatile u32 clock_source; // 1Ch R7
-+ u32 __unused3[8]; // 20h - 3Ch R8 - R15
-+ volatile u32 echo_ctrl; // 40h R16
-+ volatile u32 echo_data; // 44h R17
-+ volatile u32 t1_status; // 48h R18
-+ volatile u32 t1_config; // 4Ch R19
-+};
-+
-+struct ap4 {
-+ /* This structure exists one per card */
-+ struct pci_dev *dev; /* Pointer to PCI device */
-+ struct dahdi_device *ddev;
-+ struct ap4_regs *hw_regs;
-+ unsigned int intcount;
-+ int flag_1st_irq;
-+ int num; /* Which card we are */
-+ int fpgaver; /* version of FPGA */
-+ int hwid; /* hardware ID */
-+ int globalconfig; /* Whether global setup has been done */
-+ int syncsrc; /* active sync source */
-+ struct ap4_span *tspans[4]; /* Individual spans */
-+ int numspans; /* Number of spans on the card */
-+ int blinktimer[4];
-+#ifdef FANCY_ALARM
-+ int alarmpos[4];
-+#endif
-+ int irq; /* IRQ used by device */
-+ int order; /* Order */
-+ int flags; /* Device flags */
-+ int ledreg; /* LED Register */
-+ int e1recover; /* E1 recovery timer */
-+ unsigned long memaddr; /* Base address of card */
-+ unsigned long memlen;
-+ volatile unsigned int *membase; /* Base address of card */
-+ int spansstarted; /* number of spans started */
-+ /* spinlock_t lock; */ /* lock context */
-+ spinlock_t reglock; /* lock register access */
-+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
-+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
-+#ifdef ENABLE_WORKQUEUES
-+ atomic_t worklist;
-+ struct workqueue_struct *workq;
-+#else
-+#ifdef ENABLE_TASKLETS
-+ int taskletrun;
-+ int taskletsched;
-+ int taskletpending;
-+ int taskletexec;
-+ int txerrors;
-+ struct tasklet_struct ap4_tlet;
-+#endif
-+#endif
-+ unsigned int passno; /* number of interrupt passes */
-+ struct devtype *dt;
-+ char *variety;
-+ int last0; /* for detecting double-missed IRQ */
-+ int checktiming; /* Set >0 to cause the timing source to be checked */
-+#ifdef AP400_HDLC
-+ struct card_s *hdlc_card;
-+#endif
-+#ifdef APEC_SUPPORT
-+ int apec_enable;
-+ struct apec_s *apec;
-+#endif
-+};
-+
-+
-+static void __set_clear(struct ap4 *wc, int span);
-+static int ap4_startup(struct file *file, struct dahdi_span *span);
-+static int ap4_shutdown(struct dahdi_span *span);
-+static int ap4_rbsbits(struct dahdi_chan *chan, int bits);
-+static int ap4_maint(struct dahdi_span *span, int cmd);
-+static int ap4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data);
-+static void __ap4_set_timing_source(struct ap4 *wc, int unit);
-+static void __ap4_check_alarms(struct ap4 *wc, int span);
-+static void __ap4_check_sigbits(struct ap4 *wc, int span);
-+
-+
-+#define AP_ACTIVATE (1 << 12)
-+
-+#define AP_OFF (0)
-+#define AP_ON (1)
-+
-+#define MAX_AP4_CARDS 64
-+
-+#ifdef ENABLE_TASKLETS
-+static void ap4_tasklet(unsigned long data);
-+#endif
-+
-+static struct ap4 *cards[MAX_AP4_CARDS];
-+
-+//#define ap_debugk(fmt,args...) printk("ap400 -> %s: "fmt, __PRETTY_FUNCTION__, ##args)
-+#define ap_debugk(fmt,args...)
-+
-+//#define TIMER_DEBUG 1
-+
-+#ifdef TIMER_DEBUG
-+struct timer_list ap4xx_opt_timer;
-+unsigned int delay = 1000;
-+module_param(delay, uint, S_IRUGO);
-+#endif
-+
-+#define PCI_DEVICE_ID_AP4XX 0x1004
-+
-+static inline void __ap4_set_led(struct ap4 *wc, int span, int color)
-+{
-+ wc->ledreg &= ~(AP_ON << span);
-+ wc->ledreg |= (color << span);
-+ *(wc->membase+AP_LEDS_REG) &= ~0x0000000F;
-+ *(wc->membase+AP_LEDS_REG) |= ((wc->ledreg)&0x0F);
-+}
-+
-+static inline void ap4_activate(struct ap4 *wc)
-+{
-+ wc->ledreg |= AP_ACTIVATE;
-+}
-+
-+static void __set_clear(struct ap4 *wc, int span)
-+{
-+ int i,j;
-+ int oldnotclear;
-+ unsigned short val=0;
-+ struct ap4_span *ts = wc->tspans[span];
-+
-+ oldnotclear = ts->notclear;
-+ if (ts->spantype == TYPE_T1) {
-+ 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) {
-+ 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);
-+ }
-+ }
-+}
-+
-+#ifdef APEC_SUPPORT
-+
-+#define APEC_CTRL_RESET 0x80000000
-+#define APEC_CTRL_DDR_NCKE 0x40000000
-+#define APEC_CTRL_EC_DISABLE 0x20000000
-+#define APEC_CTRL_DAS 0x00080000
-+#define APEC_CTRL_RD 0x00040000
-+#define APEC_CTRL_REQ 0x00020000
-+#define APEC_CTRL_READY 0x00010000
-+
-+#define APEC_ACCESS_TIMEOUT 1000
-+
-+static inline u16 oct_raw_read (struct ap4_regs *regs, unsigned short addr)
-+{
-+ unsigned short data;
-+ // Poll ready bit
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+ // Write control bits and address
-+ regs->echo_ctrl = APEC_CTRL_RD | APEC_CTRL_REQ | (addr & 0xFFFF);
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+ data = regs->echo_data & 0xFFFF;
-+ //PDEBUG("Raw Read 0x%04hX @ 0x%08X", data, addr);
-+ return data;
-+}
-+
-+static inline void oct_raw_write (struct ap4_regs *regs, unsigned short addr,
-+ unsigned short data)
-+{
-+ // Poll ready bit
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+ // Write data, then control bits and address
-+ regs->echo_data = data & 0xFFFF;
-+ regs->echo_ctrl = APEC_CTRL_REQ | (addr & 0xFFFF);
-+ // Poll ready bit
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+ //PDEBUG("Raw Write 0x%04hX @ 0x%08X", data, addr);
-+ //oct_raw_read(regs, addr);
-+}
-+
-+static inline int oct_ext_wait (struct ap4_regs *regs)
-+{
-+ int i = APEC_ACCESS_TIMEOUT;
-+ while ((oct_raw_read(regs, 0x0) & 0x100) && (i-- > 0));
-+ if (i == -1) {
-+ printk(KERN_WARNING "Wait access_req timeout\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static inline u16 oct_ind_read (struct ap4_regs *regs, unsigned int addr)
-+{
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return 0;
-+ // Write extended indirect registers
-+ oct_raw_write(regs, 0x8, (addr >> 20) & 0x1FFF);
-+ oct_raw_write(regs, 0xA, (addr >> 4) & 0xFFFF);
-+ oct_raw_write(regs, 0x0, ((addr & 0xE) << 8) | 0x101);
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return 0;
-+ // Return data
-+ return oct_raw_read(regs, 0x4);
-+}
-+
-+static inline void oct_ind_write (struct ap4_regs *regs, unsigned int addr,
-+ unsigned short data)
-+{
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return;
-+ oct_raw_write(regs, 0x8, (addr >> 20) & 0x1FFF);
-+ oct_raw_write(regs, 0xA, (addr >> 4) & 0xFFFF);
-+ oct_raw_write(regs, 0x4, data);
-+ oct_raw_write(regs, 0x0, ((addr & 0xE) << 8) | 0x3101);
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return;
-+}
-+
-+static inline u16 oct_dir_read (struct ap4_regs *regs, unsigned int addr)
-+{
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return 0;
-+ // Write extended direct registers
-+ oct_raw_write(regs, 0x8, (addr >> 20) & 0x1FFF);
-+ oct_raw_write(regs, 0xA, (addr >> 4) & 0xFFFF);
-+ oct_raw_write(regs, 0x0, 0x1);
-+ regs->echo_ctrl = APEC_CTRL_DAS | APEC_CTRL_RD | APEC_CTRL_REQ | (addr & 0xFFFF);
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+ // Return data
-+ return regs->echo_data;
-+}
-+
-+static inline void oct_dir_write (struct ap4_regs *regs, unsigned int addr,
-+ unsigned short data)
-+{
-+ // Poll access_req bit
-+ if (oct_ext_wait(regs))
-+ return;
-+ // Write extended direct registers
-+ oct_raw_write(regs, 0x8, (addr >> 20) & 0x1FFF);
-+ oct_raw_write(regs, 0xA, (addr >> 4) & 0xFFFF);
-+ oct_raw_write(regs, 0x0, 0x3001);
-+ regs->echo_data = data & 0xFFFF;
-+ regs->echo_ctrl = APEC_CTRL_DAS | APEC_CTRL_REQ | (addr & 0xFFFF);
-+ while ((regs->echo_ctrl & APEC_CTRL_READY) == 0);
-+}
-+
-+
-+unsigned int oct_read (void *card, unsigned int addr)
-+{
-+ struct ap4 *wc = card;
-+ int flags;
-+ unsigned short data;
-+ spin_lock_irqsave(&wc->reglock, flags);
-+ data = oct_ind_read(wc->hw_regs, addr);
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+ PDEBUG("Read 0x%04hX @ 0x%08X", data, addr);
-+ return data;
-+}
-+
-+void oct_write (void *card, unsigned int addr, unsigned int data)
-+{
-+ struct ap4 *wc = card;
-+ int flags;
-+ spin_lock_irqsave(&wc->reglock, flags);
-+ oct_ind_write(wc->hw_regs, addr, data);
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+ PDEBUG("Write 0x%04hX @ 0x%08X", data, addr);
-+}
-+
-+static int ap4_apec_init(struct ap4 *wc)
-+{
-+ int laws[4];
-+ int i;
-+ unsigned int apec_capacity;
-+ struct firmware embedded_firmware;
-+ const struct firmware *firmware = &embedded_firmware;
-+#if !defined(HOTPLUG_FIRMWARE)
-+ extern void _binary_OCT6104E_64D_ima_size;
-+ extern u8 _binary_OCT6104E_64D_ima_start[];
-+ extern void _binary_OCT6104E_128D_ima_size;
-+ extern u8 _binary_OCT6104E_128D_ima_start[];
-+#else
-+ static const char oct64_firmware[] = "OCT6104E-64D.ima";
-+ static const char oct128_firmware[] = "OCT6104E-128D.ima";
-+#endif
-+
-+ // Enable DDR and Reset Octasic
-+ wc->hw_regs->echo_ctrl |= APEC_CTRL_RESET;
-+ wc->hw_regs->echo_ctrl |= APEC_CTRL_DDR_NCKE;
-+ udelay(500);
-+ wc->hw_regs->echo_ctrl &= APEC_CTRL_RESET;
-+ wc->hw_regs->echo_ctrl &= APEC_CTRL_DDR_NCKE;
-+ wc->hw_regs->echo_ctrl &= APEC_CTRL_EC_DISABLE;
-+
-+ /* Setup alaw vs ulaw rules */
-+ for (i = 0; i < wc->numspans; i++) {
-+ if (wc->tspans[i]->span.channels > 24)
-+ laws[i] = 1; // E1: alaw
-+ else
-+ laws[i] = 0; // T1: ulaw
-+ }
-+
-+ switch ((apec_capacity = apec_capacity_get(wc))) {
-+ case 64:
-+#if defined(HOTPLUG_FIRMWARE)
-+ if ((request_firmware(&firmware, oct64_firmware, &wc->dev->dev) != 0) ||
-+ !firmware) {
-+ printk("%s: firmware %s not available from userspace\n",
-+ wc->variety, oct64_firmware);
-+ return -1;
-+ }
-+#else
-+ embedded_firmware.data = _binary_OCT6104E_64D_ima_start;
-+ /* Yes... this is weird. objcopy gives us a symbol containing
-+ the size of the firmware, not a pointer to 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_OCT6104E_64D_ima_size;
-+#endif
-+ break;
-+ case 128:
-+#if defined(HOTPLUG_FIRMWARE)
-+ if ((request_firmware(&firmware, oct128_firmware, &wc->dev->dev) != 0) ||
-+ !firmware) {
-+ printk("%s: firmware %s not available from userspace\n",
-+ wc->variety, oct128_firmware);
-+ return -1;
-+ }
-+#else
-+ embedded_firmware.data = _binary_OCT6104E_128D_ima_start;
-+ /* Yes... this is weird. objcopy gives us a symbol containing
-+ the size of the firmware, not a pointer to 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_OCT6104E_128D_ima_size;
-+#endif
-+ break;
-+ default:
-+ printk(KERN_INFO "Unsupported channel capacity found on"
-+ "echo cancellation module (%d).\n", apec_capacity);
-+ return -1;
-+ }
-+
-+ if (!(wc->apec = apec_init(wc, laws, wc->numspans, firmware))) {
-+ printk(KERN_WARNING "APEC: Failed to initialize\n");
-+ if (firmware != &embedded_firmware)
-+ release_firmware(firmware);
-+ return -1;
-+ }
-+
-+ if (firmware != &embedded_firmware)
-+ release_firmware(firmware);
-+
-+ printk(KERN_INFO "APEC: Present and operational servicing %d span(s)\n", wc->numspans);
-+ return 0;
-+}
-+
-+void ap4_apec_release(struct ap4 *wc)
-+{
-+ // Disabel DDR and reset Octasic
-+ wc->hw_regs->echo_ctrl |= APEC_CTRL_RESET;
-+ wc->hw_regs->echo_ctrl |= APEC_CTRL_DDR_NCKE;
-+ wc->hw_regs->echo_ctrl |= APEC_CTRL_EC_DISABLE;
-+ if (wc->apec)
-+ apec_release(wc->apec);
-+}
-+
-+
-+static int ap4_echocan(struct dahdi_chan *chan, int eclen)
-+{
-+ struct ap4 *wc = chan->pvt;
-+ int channel;
-+
-+ if (!wc->apec)
-+ return -ENODEV;
-+ if (debug)
-+ printk(KERN_DEBUG "AP400: ap4_echocan @ Span %d Channel %d Length: %d\n",
-+ chan->span->offset, chan->chanpos, eclen);
-+ channel = (chan->chanpos << 2) | chan->span->offset;
-+ apec_setec(wc->apec, channel, eclen);
-+ return 0;
-+}
-+
-+#endif // APEC_SUPPORT
-+
-+
-+static int ap4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data)
-+{
-+ struct ap4 *wc = chan->pvt;
-+ int span = 0;
-+ int alarms = 0;
-+ unsigned char c, e1_cfg;
-+
-+ switch(cmd) {
-+ case AP4_GET_ALARMS:
-+ if (copy_from_user(&span, (int *)data, sizeof(int)))
-+ return -EFAULT;
-+ // span starts in zero
-+ span--;
-+ if (wc->tspans[span]->spantype == TYPE_E1) {
-+ /* le status e configuracao do E1 */
-+ c = ((*(wc->membase+AP_E1_STATUS_REG))>>(8*span));
-+ e1_cfg = ((*(wc->membase+AP_E1_CONFIG_REG))>>(8*span));
-+ if( c & AP_E1_LOS_STATUS) {
-+ alarms = 0x01;
-+ } else if( c & AP_E1_AIS_STATUS) {
-+ alarms = 0x02;
-+ } else if(!(c & AP_E1_BFAE_STATUS)) {
-+ alarms = 0x04;
-+ if (c & AP_E1_RAI_STATUS)
-+ alarms |= 0x08;
-+ // Erro de MFA: 00 - MFA desabilitado, 01 - erro de MFA, 10 - MFA OK
-+ if ( (c & AP_E1_MFAE_STATUS) && (e1_cfg & AP_E1_CRCEN_CONFIG) )
-+ alarms |= 0x10;
-+ else if ( (!(c & AP_E1_MFAE_STATUS)) && (e1_cfg & AP_E1_CRCEN_CONFIG) )
-+ alarms |= 0x20;
-+ // Erro de CAS: 00 - desabilitado, 01 - erro de CAS, 10 - CAS OK
-+ if ( (!(c & AP_E1_CAS_STATUS)) && (e1_cfg & AP_E1_PCM30_CONFIG))
-+ alarms |= 0x40;
-+ else if ( (c & AP_E1_CAS_STATUS) && (e1_cfg & AP_E1_PCM30_CONFIG))
-+ alarms |= 0x80;
-+ }
-+ } else {
-+ /* le status e configuracao do E1 */
-+ c = ((*(wc->membase+AP_E1_STATUS_REG))>>(8*span));
-+ if( c & AP_E1_LOS_STATUS)
-+ alarms = 0x01;
-+ else {
-+ c = wc->hw_regs->t1_status >> (8*span);
-+ if (!(c & AP4_T1_FRAME_SYNC))
-+ alarms = 0x04;
-+ }
-+ }
-+ if(debug) printk("AP4_GET_ALARMS: span = %d, alarms = 0x%02x\n", span+1, alarms);
-+ if (copy_to_user((int *)data, &alarms, sizeof(int)))
-+ return -EFAULT;
-+ break;
-+
-+ case AP4_GET_SLIPS:
-+ if (copy_from_user(&span, (int *)data, sizeof(int)))
-+ return -EFAULT;
-+ // span starts in zero
-+ span--;
-+ if((span < wc->numspans) && (span >=0))
-+ alarms = wc->tspans[span]->slipcount;
-+ if(debug) printk("AP4_GET_SLIPS: span = %d, slips = 0x%02x\n", span+1, alarms);
-+ if (copy_to_user((int *)data, &alarms, sizeof(int)))
-+ return -EFAULT;
-+ break;
-+
-+ default:
-+ PDEBUG("%s: Unknown IOCTL CODE!", wc->variety);
-+ return -ENOTTY;
-+ }
-+ return 0;
-+}
-+
-+static inline struct ap4_span* ap4_span_from_span(struct dahdi_span *span) {
-+ return container_of(span, struct ap4_span, span);
-+}
-+
-+static int ap4_maint(struct dahdi_span *span, int cmd)
-+{
-+ struct ap4_span *ts = ap4_span_from_span(span);
-+ struct ap4 *wc = ts->owner;
-+
-+
-+ if (ts->spantype == TYPE_E1) {
-+ switch(cmd) {
-+ case DAHDI_MAINT_NONE:
-+ printk("XXX Turn off local and remote loops E1 XXX\n");
-+ *(wc->membase+AP_E1_CONFIG_REG) &= ~(AP_E1_LOOP_CONFIG<<((span->spanno-1)*8));
-+ break;
-+ case DAHDI_MAINT_LOCALLOOP:
-+ printk("XXX Turn on local loopback E1 XXX\n");
-+ break;
-+ case DAHDI_MAINT_REMOTELOOP:
-+ printk("XXX Turn on remote loopback E1 XXX\n");
-+ break;
-+ case DAHDI_MAINT_LOOPUP:
-+ printk("XXX Turn on local loopback on E1 #%d instead of send loopup code XXX\n", span->spanno);
-+ *(wc->membase+AP_E1_CONFIG_REG) |= (AP_E1_LOOP_CONFIG<<((span->spanno-1)*8));
-+ break;
-+ case DAHDI_MAINT_LOOPDOWN:
-+ printk("XXX Turn on local loopback on E1 #%d instead of send loopdown code XXX\n", span->spanno);
-+ *(wc->membase+AP_E1_CONFIG_REG) |= (AP_E1_LOOP_CONFIG<<((span->spanno-1)*8));
-+ break;
-+ default:
-+ printk("%s: Unknown E1 maint command: %d\n", wc->variety, cmd);
-+ break;
-+ }
-+ } else {
-+ switch(cmd) {
-+ case DAHDI_MAINT_NONE:
-+ printk("XXX Turn off local and remote loops T1 XXX\n");
-+ break;
-+ case DAHDI_MAINT_LOCALLOOP:
-+ printk("XXX Turn on local loop and no remote loop XXX\n");
-+ break;
-+ case DAHDI_MAINT_REMOTELOOP:
-+ printk("XXX Turn on remote loopup XXX\n");
-+ break;
-+ case DAHDI_MAINT_LOOPUP:
-+ break;
-+ case DAHDI_MAINT_LOOPDOWN:
-+ break;
-+ default:
-+ printk("%s: Unknown T1 maint command: %d\n", wc->variety, cmd);
-+ break;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int ap4_rbsbits(struct dahdi_chan *chan, int bits)
-+{
-+ u_char m,c;
-+ int k,n,b;
-+ struct ap4 *wc = chan->pvt;
-+ struct ap4_span *ts = wc->tspans[chan->span->offset];
-+ unsigned long flags;
-+ volatile unsigned int *writecas = (wc->membase+AP_CAS_BASE);
-+ unsigned int allspansbits;
-+
-+ //ap_debugk("chan->channo = %d, int bits = 0x%08x\n", chan->channo, bits);
-+ if(debug & DEBUG_RBS) printk("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;
-+ /* monta a word de 32 bits com informacao de todos os spans */
-+ allspansbits = wc->tspans[0]->txsigs[b];
-+ if (wc->numspans > 1) {
-+ allspansbits |= (wc->tspans[1]->txsigs[b] << 8);
-+ }
-+ if (wc->numspans == 4) {
-+ allspansbits |= (wc->tspans[2]->txsigs[b] << 16) |
-+ (wc->tspans[3]->txsigs[b] << 24);
-+ }
-+ /* output them to the chip */
-+ writecas[b] = allspansbits;
-+ ap_debugk("escrito 0x%08x para ser transmitido pelo CAS (b = %d)\n", allspansbits, b);
-+#if 0
-+ } 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 */
-+ //__ap4_out( ... );
-+ } else if (ts->span.lineconfig & DAHDI_CONFIG_ESF) {
-+#endif
-+ } else {
-+ 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 */
-+ /* monta a word de 32 bits com informacao de todos os spans */
-+ allspansbits = wc->tspans[0]->txsigs[b];
-+ if (wc->numspans > 1) {
-+ allspansbits |= (wc->tspans[1]->txsigs[b] << 8);
-+ }
-+ if (wc->numspans == 4) {
-+ allspansbits |= (wc->tspans[2]->txsigs[b] << 16) |
-+ (wc->tspans[3]->txsigs[b] << 24);
-+ }
-+ /* output them to the chip */
-+ writecas[b] = allspansbits;
-+ ap_debugk("escrito 0x%08x para ser transmitido pelo CAS (b = %d)\n", allspansbits, b);
-+ }
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+ if (debug & DEBUG_RBS)
-+ printk("Finished setting RBS bits\n");
-+ return 0;
-+}
-+
-+static int ap4_shutdown(struct dahdi_span *span)
-+{
-+ int tspan;
-+ int wasrunning;
-+ unsigned long flags;
-+ struct ap4_span *ts = ap4_span_from_span(span);
-+ struct ap4 *wc = ts->owner;
-+
-+ tspan = span->offset + 1;
-+ if (tspan < 0) {
-+ printk("%s: '%d' isn't us?\n", wc->variety, span->spanno);
-+ return -1;
-+ }
-+
-+ spin_lock_irqsave(&wc->reglock, flags);
-+ wasrunning = span->flags & DAHDI_FLAG_RUNNING;
-+
-+ span->flags &= ~DAHDI_FLAG_RUNNING;
-+ if (wasrunning)
-+ wc->spansstarted--;
-+ __ap4_set_led(wc, span->offset, AP_OFF);
-+ if (((wc->numspans == 4) &&
-+ (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)) &&
-+ (!(wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)) &&
-+ (!(wc->tspans[2]->span.flags & DAHDI_FLAG_RUNNING)) &&
-+ (!(wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING)))
-+ ||
-+ ((wc->numspans == 2) &&
-+ (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)) &&
-+ (!(wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)))
-+ ||
-+ ((wc->numspans == 1) &&
-+ (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)))) {
-+ /* No longer in use, disable interrupts */
-+ printk("%s: Disabling interrupts since there are no active spans\n",
-+ wc->variety);
-+ } else wc->checktiming = 1;
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+ if (debug & DEBUG_MAIN)
-+ printk("Span %d (%s) shutdown\n", span->spanno, span->name);
-+ return 0;
-+}
-+
-+static int ap4_spanconfig(struct file *file, struct dahdi_span *span,
-+ struct dahdi_lineconfig *lc)
-+{
-+ int i;
-+ struct ap4_span *ts = ap4_span_from_span(span);
-+ struct ap4 *wc = ts->owner;
-+ unsigned int val;
-+
-+ printk("About to enter spanconfig!\n");
-+ if (debug & DEBUG_MAIN)
-+ printk("%s: Configuring span %d\n", wc->variety, span->spanno);
-+ /* XXX We assume lineconfig is okay and shouldn't XXX */
-+ span->lineconfig = lc->lineconfig;
-+ span->txlevel = lc->lbo;
-+ span->rxlevel = 0;
-+ if (lc->sync < 0)
-+ lc->sync = 0;
-+ if (lc->sync > 4)
-+ 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;
-+ }
-+ wc->checktiming = 1;
-+ /* If we're already running, then go ahead and apply the changes */
-+ if (span->flags & DAHDI_FLAG_RUNNING)
-+ return ap4_startup(file, span);
-+
-+ // Limpa contadores de slips, crc e bpv
-+ val = (*(wc->membase + AP_CNT_SLIP_REG));
-+ val = (*(wc->membase + AP_CNT_CRC_REG));
-+ val = (*(wc->membase + AP_CNT_CV_REG));
-+
-+ ap_debugk("habilitando interrupcao!\n");
-+ // Nao considera as primeiras interrupcoes na soma das IRQs perdidas
-+ wc->flag_1st_irq = 16;
-+ // Enable interrupt
-+ *(wc->membase + AP_INT_CONTROL_REG) |= AP_INT_CTL_ENABLE;
-+ // Limpa interrupcao da FPGA para forcar borda de subida na proxima
-+ val = *(wc->membase + AP_CLEAR_IRQ_REG);
-+
-+ printk("Done with spanconfig!\n");
-+ return 0;
-+}
-+
-+static int ap4_chanconfig(struct file *file, struct dahdi_chan *chan,
-+ int sigtype)
-+{
-+ int alreadyrunning;
-+ unsigned long flags;
-+ struct ap4 *wc = chan->pvt;
-+
-+ alreadyrunning = wc->tspans[chan->span->offset]->span.flags & DAHDI_FLAG_RUNNING;
-+ if (debug & DEBUG_MAIN) {
-+ if (alreadyrunning)
-+ printk("%s: Reconfigured channel %d (%s) sigtype %d\n",
-+ wc->variety, chan->channo, chan->name, sigtype);
-+ else
-+ printk("%s: Configured channel %d (%s) sigtype %d\n",
-+ wc->variety, 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);
-+ return 0;
-+}
-+
-+static int ap4_open(struct dahdi_chan *chan)
-+{
-+ try_module_get(THIS_MODULE);
-+ return 0;
-+}
-+
-+static int ap4_close(struct dahdi_chan *chan)
-+{
-+ module_put(THIS_MODULE);
-+ return 0;
-+}
-+
-+static const struct dahdi_span_ops ap4_span_ops = {
-+ .owner = THIS_MODULE,
-+ .spanconfig = ap4_spanconfig,
-+ .chanconfig = ap4_chanconfig,
-+ .startup = ap4_startup,
-+ .shutdown = ap4_shutdown,
-+ .rbsbits = ap4_rbsbits,
-+ .maint = ap4_maint,
-+ .open = ap4_open,
-+ .close = ap4_close,
-+#ifdef APEC_SUPPORT
-+ .echocan = ap4_echocan,
-+#endif
-+ .ioctl = ap4_ioctl
-+};
-+
-+static void init_spans(struct ap4 *wc)
-+{
-+ int x,y;
-+ struct ap4_span *ts;
-+
-+ for (x=0;x<wc->numspans;x++) {
-+ ts = wc->tspans[x];
-+ sprintf(ts->span.name, "AP4%d%d/%d/%d", 0, wc->numspans, wc->num, x + 1);
-+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, "AP4%d%d Card %d Span %d", 0, wc->numspans, wc->num+1, x+1);
-+ ts->span.ops = &ap4_span_ops;
-+ if (ts->spantype == TYPE_E1) {
-+ ts->span.channels = 31;
-+ ts->span.spantype = SPANTYPE_DIGITAL_E1;
-+ ts->span.linecompat = DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS | DAHDI_CONFIG_CRC4;
-+ ts->span.deflaw = DAHDI_LAW_ALAW;
-+ } else {
-+ ts->span.channels = 24;
-+ ts->span.spantype = SPANTYPE_DIGITAL_T1;
-+ ts->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF;
-+ ts->span.deflaw = DAHDI_LAW_MULAW;
-+ }
-+ 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);
-+ for (y=0;y<wc->tspans[x]->span.channels;y++) {
-+ struct dahdi_chan *mychans = ts->chans[y];
-+ sprintf(mychans->name, "AP4%d%d/%d/%d/%d", 0, wc->numspans, wc->num, x + 1, y + 1);
-+ mychans->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXSKS |
-+ DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_FXOKS | DAHDI_SIG_CAS | DAHDI_SIG_EM_E1 | DAHDI_SIG_DACS_RBS;
-+ mychans->pvt = wc;
-+ mychans->chanpos = y + 1;
-+ }
-+ }
-+ printk("%s: Spans initialized\n", wc->variety);
-+}
-+
-+
-+
-+static void __ap4_set_timing_source(struct ap4 *wc, int unit)
-+{
-+ unsigned int timing;
-+ int x;
-+
-+ if (unit != wc->syncsrc) {
-+ if ((unit > -1) && (unit < 4)) {
-+ /* define fonte de clock para interface escolhida */
-+ timing = *(wc->membase+AP_CLKSRC_REG);
-+ timing &= ~AP_CLKSRC_MASK;
-+ timing |= unit+1;
-+ *(wc->membase+AP_CLKSRC_REG) = timing;
-+ } else {
-+ /* define clock para interno */
-+ timing = *(wc->membase+AP_CLKSRC_REG);
-+ timing &= ~AP_CLKSRC_MASK;
-+ *(wc->membase+AP_CLKSRC_REG) = timing;
-+ }
-+ wc->syncsrc = unit;
-+ if ((unit < 0) || (unit > 3))
-+ unit = 0;
-+ else
-+ unit++;
-+ for (x=0;x<wc->numspans;x++)
-+ wc->tspans[x]->span.syncsrc = unit;
-+ } else {
-+ if (debug & DEBUG_MAIN)
-+ printk("%s: Timing source already set to %d\n",
-+ wc->variety, unit);
-+ }
-+ printk("%s: Timing source set to %d (clksrc_reg = 0x%08x)\n",
-+ wc->variety, unit, *(wc->membase+AP_CLKSRC_REG));
-+}
-+
-+static void __ap4_set_timing_source_auto(struct ap4 *wc)
-+{
-+ int x;
-+
-+ wc->checktiming = 0;
-+ for (x=0;x<wc->numspans;x++) {
-+ if (wc->tspans[x]->sync) {
-+ if ((wc->tspans[wc->tspans[x]->psync - 1]->span.flags & DAHDI_FLAG_RUNNING) &&
-+ !(wc->tspans[wc->tspans[x]->psync - 1]->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE) )) {
-+ /* Valid timing source */
-+ __ap4_set_timing_source(wc, wc->tspans[x]->psync - 1);
-+ return;
-+ }
-+ }
-+ }
-+ __ap4_set_timing_source(wc, 4);
-+}
-+
-+static void __ap4_configure_t1(struct ap4 *wc, int unit, int lineconfig, int txlevel)
-+{
-+ char *framing, *line;
-+ unsigned int config = 0;
-+ unsigned int param = 0;
-+ unsigned int linecode = 0;
-+
-+ wc->tspans[unit]->spantype = TYPE_T1;
-+ wc->tspans[unit]->span.channels = 24;
-+ wc->tspans[unit]->span.deflaw = DAHDI_LAW_MULAW;
-+
-+ /* Configure line code */
-+ if (unit < 2)
-+ linecode = AP_LIU1_LINECODE;
-+ else
-+ linecode = AP_LIU2_LINECODE;
-+ if (lineconfig & DAHDI_CONFIG_AMI) {
-+ *(wc->membase+AP_LEDS_REG) |= linecode;
-+ line = "AMI";
-+ } else {
-+ *(wc->membase+AP_LEDS_REG) &= ~linecode;
-+ line = "B8ZS";
-+ }
-+
-+ /* loopback test*/
-+ //wc->hw_regs->e1_config |= (AP_E1_LOOP_CONFIG << (8 * unit));
-+ //printk("E1 config = 0x%08x\n", wc->hw_regs->e1_config);
-+
-+ /* Configure T1 */
-+ config = wc->hw_regs->liu_config;
-+ config &= ~(0x000000ff << (8 * unit));
-+ config |= (AP_PULS_DSX1_0FT << (8 * unit));
-+ wc->hw_regs->liu_config = config;
-+
-+ param = AP4_T1_NE1_SEL | AP4_T1_CAS_ENABLE;
-+ if (lineconfig & DAHDI_CONFIG_D4) {
-+ framing = "D4";
-+ } else {
-+ framing = "ESF";
-+ param |= AP4_T1_ESF_NSF;
-+ }
-+ config = wc->hw_regs->t1_config;
-+ config &= ~(0x000000ff << (8 * unit));
-+ config |= (param << (8 * unit));
-+ wc->hw_regs->t1_config = config;
-+
-+ printk("T1 Status: 0x%08x\tT1 Config: 0x%08x\tPARAM: 0x%08x\n",
-+ wc->hw_regs->t1_status, wc->hw_regs->t1_config, param);
-+
-+ if (!polling) {
-+ __ap4_check_alarms(wc, unit);
-+ __ap4_check_sigbits(wc, unit);
-+ }
-+ printk("%s: Span %d configured for %s/%s\n", wc->variety, unit + 1, framing, line);
-+}
-+
-+static void __ap4_configure_e1(struct ap4 *wc, int unit, int lineconfig)
-+{
-+ char *crc4 = "";
-+ char *framing, *line;
-+ unsigned int e1s_cfg, config = 0;
-+ unsigned int linecode = 0;
-+
-+ wc->tspans[unit]->spantype = TYPE_E1;
-+ wc->tspans[unit]->span.channels = 31;
-+ wc->tspans[unit]->span.deflaw = DAHDI_LAW_ALAW;
-+
-+ if (loopback) {
-+ }
-+
-+ if (lineconfig & DAHDI_CONFIG_CRC4) {
-+ crc4 = "/CRC4";
-+ config |= AP_E1_CRCEN_CONFIG;
-+ }
-+
-+ if(unit < 2)
-+ linecode = AP_LIU1_LINECODE;
-+ else
-+ linecode = AP_LIU2_LINECODE;
-+ /* Configure line interface */
-+ if (lineconfig & DAHDI_CONFIG_AMI) {
-+ *(wc->membase+AP_LEDS_REG) |= linecode;
-+ line = "AMI";
-+ } else {
-+ *(wc->membase+AP_LEDS_REG) &= ~linecode;
-+ line = "HDB3";
-+ }
-+
-+ if (lineconfig & DAHDI_CONFIG_CCS) {
-+ framing = "CCS";
-+ } else {
-+ framing = "CAS";
-+ config |= (AP_E1_CASEN_CONFIG | AP_E1_PCM30_CONFIG);
-+ }
-+
-+ e1s_cfg = *(wc->membase+AP_E1_CONFIG_REG);
-+ e1s_cfg &= ~(0x000000ff<<(8*unit));
-+ e1s_cfg |= (config<<(8*unit));
-+ *(wc->membase+AP_E1_CONFIG_REG) = e1s_cfg;
-+
-+ /* Disable T1 framer */
-+ config = wc->hw_regs->t1_config;
-+ config &= ~(0x000000ff << (8 * unit));
-+ wc->hw_regs->t1_config = config;
-+
-+ /* Configure LIU Signalling */
-+ e1s_cfg = *(wc->membase+AP_T1E1_CONFIG_REG);
-+ e1s_cfg &= ~(0x000000ff<<(8*unit));
-+ e1s_cfg |= (AP_PULS_E1_120<<(8*unit));
-+ *(wc->membase+AP_T1E1_CONFIG_REG) = e1s_cfg;
-+
-+ if (!polling) {
-+ __ap4_check_alarms(wc, unit);
-+ __ap4_check_sigbits(wc, unit);
-+ }
-+ printk("%s: Span %d configured for %s/%s%s\n",
-+ wc->variety, unit + 1, framing, line, crc4);
-+}
-+
-+static int ap4_startup(struct file *file, struct dahdi_span *span)
-+{
-+ int i;
-+ int tspan;
-+ unsigned long flags;
-+ int alreadyrunning;
-+ struct ap4_span *ts = ap4_span_from_span(span);
-+ struct ap4 *wc = ts->owner;
-+
-+ printk("About to enter startup!\n");
-+ tspan = span->offset + 1;
-+ if (tspan < 0) {
-+ printk("%s: Span '%d' isn't us?\n", wc->variety, span->spanno);
-+ return -1;
-+ }
-+
-+ spin_lock_irqsave(&wc->reglock, flags);
-+
-+ alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
-+
-+ /* 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);
-+ }
-+
-+ /* Force re-evaluation fo timing source */
-+// if (timingcable)
-+ wc->syncsrc = -1;
-+
-+ if ((span->lineconfig & DAHDI_CONFIG_D4) || (span->lineconfig & DAHDI_CONFIG_ESF)) {
-+ /* is a T1 card */
-+ __ap4_configure_t1(wc, span->offset, span->lineconfig, span->txlevel);
-+ } else { /* is a E1 card */
-+ __ap4_configure_e1(wc, span->offset, span->lineconfig);
-+ }
-+
-+ /* Note clear channel status */
-+ wc->tspans[span->offset]->notclear = 0;
-+ __set_clear(wc, span->offset);
-+
-+ if (!alreadyrunning) {
-+ span->flags |= DAHDI_FLAG_RUNNING;
-+ wc->spansstarted++;
-+ /* enable interrupts */
-+
-+ if (!polling) {
-+ __ap4_check_alarms(wc, span->offset);
-+ __ap4_check_sigbits(wc, span->offset);
-+ }
-+ }
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+
-+ if (wc->tspans[0]->sync == span->spanno) printk("SPAN %d: Primary Sync Source\n",span->spanno);
-+ if (wc->numspans > 1) {
-+ if (wc->tspans[1]->sync == span->spanno) printk("SPAN %d: Secondary Sync Source\n",span->spanno);
-+ }
-+ if (wc->numspans == 4) {
-+ if (wc->tspans[2]->sync == span->spanno) printk("SPAN %d: Tertiary Sync Source\n",span->spanno);
-+ if (wc->tspans[3]->sync == span->spanno) printk("SPAN %d: Quaternary Sync Source\n",span->spanno);
-+ }
-+
-+#ifdef APEC_SUPPORT
-+ if (!apec_enable || !wc->apec_enable)
-+ wc->hw_regs->echo_ctrl = 0xe0000000;
-+ else if (!alreadyrunning && !wc->apec)
-+ if (ap4_apec_init(wc))
-+ ap4_apec_release(wc);
-+#else
-+ wc->hw_regs->echo_ctrl = 0xe0000000;
-+#endif
-+
-+ printk("Completed startup!\n");
-+ return 0;
-+}
-+
-+
-+static void ap4_receiveprep(struct ap4 *wc)
-+{
-+ volatile unsigned int *readchunk;
-+ unsigned int buffer[32];
-+ unsigned char *byte = (unsigned char *) buffer;
-+ int i, j, k;
-+
-+ readchunk = (wc->membase + (AP_DATA_BASE));
-+ for (i = 0; i < DAHDI_CHUNKSIZE; i++) {
-+ /* Prefetch Card data */
-+ for (j = 0; j < 32; ++j) {
-+ buffer[j] = readchunk[j];
-+ }
-+ for (j = 0; j < wc->numspans; j++) {
-+ /* Set first timeslot for first channel */
-+ if (wc->tspans[j]->spantype == TYPE_E1) {
-+ for (k = 0; k < 31; ++k) {
-+ /* Skip first timeslot from E1 */
-+ wc->tspans[j]->span.chans[k]->readchunk[i] =
-+ byte[4*(k+1)+j];
-+ }
-+ }
-+ else {
-+ for (k = 0; k < 24; ++k) {
-+ wc->tspans[j]->span.chans[k]->readchunk[i] =
-+ byte[4*k+j];
-+ }
-+ }
-+ }
-+ readchunk += 32;
-+ }
-+
-+ for (i = 0; i < wc->numspans; i++) {
-+ if (wc->tspans[i]->span.flags & DAHDI_FLAG_RUNNING) {
-+ for (j = 0; j < wc->tspans[i]->span.channels; j++) {
-+ /* Echo cancel double buffered data */
-+ dahdi_ec_chunk(wc->tspans[i]->span.chans[j],
-+ wc->tspans[i]->span.chans[j]->readchunk,
-+ wc->tspans[i]->ec_chunk2[j]);
-+ memcpy(wc->tspans[i]->ec_chunk2[j],wc->tspans[i]->ec_chunk1[j],
-+ DAHDI_CHUNKSIZE);
-+ memcpy(wc->tspans[i]->ec_chunk1[j],
-+ wc->tspans[i]->span.chans[j]->writechunk,
-+ DAHDI_CHUNKSIZE);
-+ }
-+ dahdi_receive(&wc->tspans[i]->span);
-+ }
-+ }
-+}
-+
-+#if (DAHDI_CHUNKSIZE != 8)
-+#error Sorry, AP400 driver does not support chunksize != 8
-+#endif
-+
-+#ifdef ENABLE_WORKQUEUES
-+static void workq_handlespan(void *data)
-+{
-+ struct ap4_span *ts = data;
-+ struct ap4 *wc = ts->owner;
-+
-+// __receive_span(ts);
-+// __transmit_span(ts);
-+ atomic_dec(&wc->worklist);
-+ atomic_read(&wc->worklist);
-+
-+}
-+#endif
-+
-+static void ap4_transmitprep(struct ap4 *wc)
-+{
-+ volatile unsigned int *writechunk;
-+ int x,y,z;
-+ unsigned int tmp;
-+
-+ for (y=0;y<wc->numspans;y++) {
-+ if (wc->tspans[y]->span.flags & DAHDI_FLAG_RUNNING)
-+ dahdi_transmit(&wc->tspans[y]->span);
-+ }
-+
-+ writechunk = (wc->membase+(AP_DATA_BASE));
-+ for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-+ // Once per chunk
-+ for (z=0;z<32;z++) {
-+ // All channels
-+ tmp = 0;
-+ for (y = 0; y < wc->numspans; ++y) {
-+ if (wc->tspans[y]->spantype == TYPE_T1 && z < 24)
-+ tmp |= (wc->tspans[y]->span.chans[z]->writechunk[x]
-+ << (8*y));
-+ else /* Span Type is E1 */
-+ if (z > 0) /* Skip first timeslot */
-+ tmp |= (wc->tspans[y]->span.chans[z-1]->writechunk[x]
-+ << (8*y));
-+ }
-+ writechunk[z] = tmp;
-+ }
-+ // Advance pointer by 4 TDM frame lengths
-+ writechunk += 32;
-+ }
-+
-+}
-+
-+static void ap4_tdm_loop(struct ap4 *wc)
-+{
-+ volatile unsigned int *buf_ptr;
-+ int x,z;
-+ unsigned int tmp;
-+
-+ buf_ptr = (wc->membase+AP_DATA_BASE);
-+
-+ for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-+ // Once per chunk
-+ for (z=0;z<32;z++) {
-+ tmp = buf_ptr[z];
-+ buf_ptr[z] = tmp;
-+ }
-+ buf_ptr += 32;
-+ }
-+}
-+
-+static void __ap4_check_sigbits(struct ap4 *wc, int span)
-+{
-+ int a,i,rxs;
-+ struct ap4_span *ts = wc->tspans[span];
-+ volatile unsigned int *readcas = (wc->membase+AP_CAS_BASE);
-+
-+// if (debug & DEBUG_RBS)
-+// printk("Checking sigbits on span %d\n", span + 1);
-+
-+ if (!(ts->span.flags & DAHDI_FLAG_RUNNING))
-+ return;
-+ // se span estiver com alarme RED ou BLUE...
-+ if( (ts->span.alarms & DAHDI_ALARM_RED) || (ts->span.alarms & DAHDI_ALARM_BLUE) ) {
-+ ts->reload_cas = 4;
-+ } else if(ts->reload_cas > 0) {
-+ // da mais um tempo para framer recuperar e enviar bits de CAS validos
-+ ts->reload_cas--;
-+ }
-+
-+ if (ts->spantype == TYPE_E1) {
-+ for (i = 0; i < 15; i++) {
-+
-+ // Se estamos em alarme ou recuperando de um entao mascara os bits para "1101" (bloqueado)
-+ if(ts->reload_cas) {
-+ a = 0xdd;
-+ } else {
-+ a = (int) ts->casbuf[i];
-+ }
-+ ts->casbuf[i] = (unsigned char) (readcas[i] >> (8*span))&0xff;
-+
-+ /* 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) {
-+ ap_debugk("CAS no canal %d mudou de 0x%02x para 0x%02x\n", i+16, 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) {
-+ ap_debugk("CAS no canal %d mudou de 0x%02x para 0x%02x\n", i, 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 < 12; i++) {
-+ a = (unsigned char) (readcas[i] >> (8*span)) & 0xcc;
-+ rxs = a & 0xc;
-+ //rxs = (a & 0xc) >> 2;
-+ if (!(ts->span.chans[2*i]->sig & DAHDI_SIG_CLEAR)) {
-+ if (ts->span.chans[2*i]->rxsig != rxs)
-+ dahdi_rbsbits(ts->span.chans[2*i], rxs);
-+ }
-+ rxs = (a >> 4) & 0xc;
-+ //rxs = ((a >> 4) & 0xc) >> 2;
-+ if (!(ts->span.chans[2*i+1]->sig & DAHDI_SIG_CLEAR)) {
-+ if (ts->span.chans[2*i+1]->rxsig != rxs)
-+ dahdi_rbsbits(ts->span.chans[2*i+1], rxs);
-+ }
-+ }
-+ } else { // ESF
-+ for (i = 0; i < 12; i++) {
-+ a = (unsigned char) (readcas[i] >> (8*span)) & 0xff;
-+ rxs = (a & 0xf);
-+ if (!(ts->span.chans[2*i+1]->sig & DAHDI_SIG_CLEAR)) {
-+ /* XXX Not really reset on every trans! XXX */
-+ if (ts->span.chans[2*i+1]->rxsig != rxs) {
-+ dahdi_rbsbits(ts->span.chans[2*i+1], rxs);
-+ }
-+ }
-+ rxs = (a >> 4) & 0xf;
-+ if (!(ts->span.chans[2*i]->sig & DAHDI_SIG_CLEAR)) {
-+ /* XXX Not really reset on every trans! XXX */
-+ if (ts->span.chans[2*i]->rxsig != rxs) {
-+ dahdi_rbsbits(ts->span.chans[2*i], rxs);
-+ }
-+ }
-+ }
-+ }
-+}
-+
-+static void __ap4_check_alarms(struct ap4 *wc, int span)
-+{
-+ unsigned char c;
-+ int alarms;
-+ int x,j;
-+ struct ap4_span *ts = wc->tspans[span];
-+ unsigned int e1_cfg;
-+
-+ if (!(ts->span.flags & DAHDI_FLAG_RUNNING))
-+ return;
-+
-+ /* Assume no alarms */
-+ alarms = DAHDI_ALARM_NONE;
-+
-+ /* And consider only carrier alarms */
-+ ts->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN);
-+
-+ 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)
-+#ifdef CONFIG_DAHDI_NET
-+ ||
-+ (ts->span.chans[x]->flags & DAHDI_FLAG_NETDEV)
-+#endif
-+ )
-+ j++;
-+ if (!j)
-+ alarms |= DAHDI_ALARM_NOTOPEN;
-+ }
-+
-+/* le status e configuracao do E1 */
-+ if (wc->tspans[span]->spantype == TYPE_E1) {
-+ c = ((*(wc->membase+AP_E1_STATUS_REG))>>(8*span));
-+ e1_cfg = ((*(wc->membase+AP_E1_CONFIG_REG))>>(8*span));
-+
-+ if ((c & AP_E1_LOS_STATUS)||(c & AP_E1_BFAE_STATUS)||(c & AP_E1_AIS_STATUS)) {
-+ if (ts->alarmcount >= alarmdebounce)
-+ alarms |= DAHDI_ALARM_RED;
-+ else
-+ ts->alarmcount++;
-+ } else
-+ ts->alarmcount = 0;
-+
-+ if ( c & AP_E1_MFAE_STATUS )
-+ alarms |= DAHDI_ALARM_BLUE;
-+
-+ if ( (!(c & AP_E1_CAS_STATUS)) && (e1_cfg & AP_E1_PCM30_CONFIG))
-+ alarms |= DAHDI_ALARM_BLUE;
-+ } else {
-+ c = ((*(wc->membase+AP_E1_STATUS_REG))>>(8*span));
-+ if (c & AP_E1_LOS_STATUS) {
-+ if (ts->alarmcount >= alarmdebounce)
-+ alarms |= DAHDI_ALARM_RED;
-+ else
-+ ts->alarmcount++;
-+ } else
-+ ts->alarmcount = 0;
-+ c = wc->hw_regs->t1_status >> (8 * span);
-+ if (!(c & AP4_T1_FRAME_SYNC))
-+ alarms |= DAHDI_ALARM_RED;
-+ }
-+
-+ if (((!ts->span.alarms) && alarms) ||
-+ (ts->span.alarms && (!alarms)))
-+ wc->checktiming = 1;
-+
-+ /* 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)) {
-+ printk("Setting yellow alarm on span %d\n", span + 1);
-+ e1_cfg = *(wc->membase+AP_E1_CONFIG_REG);
-+ e1_cfg |= (AP_E1_RAI_CONFIG<<(8*span));
-+ *(wc->membase+AP_E1_CONFIG_REG) = e1_cfg;
-+ ts->spanflags |= FLAG_SENDINGYELLOW;
-+ } else if ((!alarms) && (ts->spanflags & FLAG_SENDINGYELLOW)) {
-+ printk("Clearing yellow alarm on span %d\n", span + 1);
-+ e1_cfg = *(wc->membase+AP_E1_CONFIG_REG);
-+ e1_cfg &= ~(AP_E1_RAI_CONFIG<<(8*span));
-+ *(wc->membase+AP_E1_CONFIG_REG) = e1_cfg;
-+ ts->spanflags &= ~FLAG_SENDINGYELLOW;
-+ }
-+
-+ // Re-check the timing source when we enter/leave alarm, not withstanding yellow alarm
-+ if (c & AP_E1_RAI_STATUS)
-+ alarms |= DAHDI_ALARM_YELLOW;
-+
-+ if (ts->span.mainttimer || ts->span.maintstat)
-+ alarms |= DAHDI_ALARM_LOOPBACK;
-+
-+ ts->span.alarms = alarms;
-+ dahdi_alarm_notify(&ts->span);
-+}
-+
-+static void __ap4_do_counters(struct ap4 *wc)
-+{
-+ int span;
-+
-+ for (span=0;span<wc->numspans;span++) {
-+ struct ap4_span *ts = wc->tspans[span];
-+ int docheck=0;
-+ if (ts->loopupcnt || ts->loopdowncnt)
-+ docheck++;
-+ if (ts->alarmtimer) {
-+ if (!--ts->alarmtimer) {
-+ docheck++;
-+ ts->span.alarms &= ~(DAHDI_ALARM_RECOVER);
-+ }
-+ }
-+ if (docheck) {
-+ if (!polling)
-+ __ap4_check_alarms(wc, span);
-+ dahdi_alarm_notify(&ts->span);
-+ }
-+ }
-+}
-+
-+static inline void __handle_leds(struct ap4 *wc)
-+{
-+ int x, span_status;
-+ #define MAX_BLINKTIMER 0x14
-+
-+ for (x=0;x<wc->numspans;x++) {
-+ struct ap4_span *ts = wc->tspans[x];
-+ /* le status do E1 (para avaliar LOS) */
-+ span_status = ((*(wc->membase+AP_E1_STATUS_REG))>>(8*x));
-+ if (ts->span.flags & DAHDI_FLAG_RUNNING) {
-+ if(span_status&AP_E1_LOS_STATUS) {
-+ if (wc->blinktimer[x] >= (altab[wc->alarmpos[x]] /*>> 1*/)) {
-+ __ap4_set_led(wc, x, AP_ON);
-+ }
-+ if (wc->blinktimer[x] >= (MAX_BLINKTIMER-1)) {
-+ __ap4_set_led(wc, x, AP_OFF);
-+ }
-+ wc->blinktimer[x] += 1;
-+ } else if (ts->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) {
-+ if (wc->blinktimer[x] >= (altab[wc->alarmpos[x]] /*>> 1*/)) {
-+ __ap4_set_led(wc, x, AP_ON);
-+ }
-+ if (wc->blinktimer[x] >= (MAX_BLINKTIMER-2)) {
-+ __ap4_set_led(wc, x, AP_OFF);
-+ }
-+ wc->blinktimer[x] += 3;
-+ } /*else if (ts->span.alarms & DAHDI_ALARM_YELLOW) {
-+ // Yellow Alarm
-+ __ap4_set_led(wc, x, AP_ON);
-+ } else if (ts->span.mainttimer || ts->span.maintstat) {
-+
-+ if (wc->blinktimer == (altab[wc->alarmpos] >> 1)) {
-+ __ap4_set_led(wc, x, AP_GREEN);
-+ }
-+ if (wc->blinktimer == 0xf) {
-+ __ap4_set_led(wc, x, AP_OFF);
-+ }
-+
-+ } */else {
-+ /* No Alarm */
-+ __ap4_set_led(wc, x, AP_ON);
-+ }
-+ } else
-+ __ap4_set_led(wc, x, AP_OFF);
-+
-+ if (wc->blinktimer[x] > MAX_BLINKTIMER) {
-+ wc->blinktimer[x] = 0;
-+ wc->alarmpos[x]++;
-+ if (wc->alarmpos[x] >= (sizeof(altab) / sizeof(altab[0])))
-+ wc->alarmpos[x] = 0;
-+ }
-+
-+ }
-+}
-+
-+
-+static irqreturn_t ap4_interrupt(int irq, void *dev_id)
-+{
-+ struct ap4 *wc = dev_id;
-+ unsigned long flags;
-+ int x;
-+ static unsigned int val, cfg;
-+ unsigned int cnt_irq_misses;
-+ static unsigned int cnt_tmp;
-+ int ret = 0;
-+
-+ /* retorna se interrupcao nao foi habilitada ou nao esta ativa */
-+ cfg = *(wc->membase + AP_INT_CONTROL_REG);
-+ if((cfg & AP_INT_CTL_ENABLE) == 0 || (cfg & AP_INT_CTL_ACTIVE) == 0) {
-+ ret = 0;
-+ goto out;
-+ }
-+ /* se chegamos aqui eh porque a interrupcao esta habilitada
-+ * e esta ativa, ou seja, foi gerada pelo nosso cartao.
-+ * Agora damos o ack da interrupcao */
-+ val = *(wc->membase + AP_CLEAR_IRQ_REG);
-+
-+ /* conta interrupcoes perdidas */
-+ if (wc->flag_1st_irq > 0) {
-+ // nao considera as primeiras passagens pela rotina
-+ cnt_irq_misses = (*(wc->membase+AP_CNT_IRQ_REG));
-+ // so considera int. para o cartao
-+ if(cnt_irq_misses) {
-+ wc->flag_1st_irq--;
-+ *(wc->membase+AP_CNT_IRQ_REG)=0;
-+ }
-+ // zera erro de CRC
-+ cnt_tmp = (*(wc->membase + AP_CNT_CRC_REG));
-+ } else {
-+ // neste registro da FPGA temos o numero de interrupcoes que aconteceram
-+ // desde o ultimo reset do contador de interrupcoes. O normal eh ler 1.
-+ cnt_irq_misses = (*(wc->membase+AP_CNT_IRQ_REG));
-+ // Se for zero significa que a interrupcao nao foi gerada pelo nosso cartao
-+ if(cnt_irq_misses == 0) {
-+ if(debug) printk("Interrupcao gerada mas nao pela FPGA?!\n");
-+ ret = 0;
-+ goto out;
-+ }
-+ // reseta o contador
-+ *(wc->membase+AP_CNT_IRQ_REG)=0;
-+ for(x=0;x<(wc->numspans);x++)
-+ wc->ddev->irqmisses += (cnt_irq_misses-1);
-+ }
-+
-+ if (!wc->spansstarted) {
-+ /* Not prepped yet! */
-+ ret = 0;
-+ goto out;
-+ }
-+
-+ wc->intcount++;
-+
-+#ifdef ENABLE_WORKQUEUES
-+ int cpus = num_online_cpus();
-+ atomic_set(&wc->worklist, wc->numspans);
-+ if (wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)
-+ ap4_queue_work(wc->workq, &wc->tspans[0]->swork, 0);
-+ else
-+ atomic_dec(&wc->worklist);
-+ if (wc->numspans > 1) {
-+ if (wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)
-+ ap4_queue_work(wc->workq, &wc->tspans[1]->swork, 1 % cpus);
-+ else
-+ atomic_dec(&wc->worklist);
-+ }
-+ if (wc->numspans == 4) {
-+ if (wc->tspans[2]->span.flags & DAHDI_FLAG_RUNNING)
-+ ap4_queue_work(wc->workq, &wc->tspans[2]->swork, 2 % cpus);
-+ else
-+ atomic_dec(&wc->worklist);
-+ if (wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING)
-+ ap4_queue_work(wc->workq, &wc->tspans[3]->swork, 3 % cpus);
-+ else
-+ atomic_dec(&wc->worklist);
-+ }
-+#else
-+ if (tdm_loop == 1)
-+ ap4_tdm_loop(wc);
-+ else {
-+ ap4_receiveprep(wc);
-+ ap4_transmitprep(wc);
-+ }
-+#endif
-+
-+ // Estatisticas a cada 128ms
-+ if(!(wc->intcount&0x7f)){
-+ clock_source = wc->hw_regs->clock_source;
-+ cnt_tmp = (*(wc->membase + AP_CNT_CV_REG));
-+ for(x=0;x<(wc->numspans);x++)
-+ wc->tspans[x]->span.count.bpv += (cnt_tmp>>(8*x))&0xff;
-+ cnt_tmp = (*(wc->membase + AP_CNT_CRC_REG));
-+ for(x=0;x<(wc->numspans);x++)
-+ wc->tspans[x]->span.count.crc4 += (cnt_tmp>>(8*x))&0xff;
-+ cnt_tmp = (*(wc->membase + AP_CNT_SLIP_REG));
-+ for(x=0;x<(wc->numspans);x++) {
-+ if (((cnt_tmp>>(8*x))&0xff) && (!(wc->tspans[x]->span.alarms & DAHDI_ALARM_RED)) ){
-+ wc->tspans[x]->slipcount++;
-+ if(debug) printk("Slip detected on span %d: slipcount = %d\n", x+1, wc->tspans[x]->slipcount);
-+ }
-+ }
-+ }
-+
-+ spin_lock_irqsave(&wc->reglock, flags);
-+
-+ __handle_leds(wc);
-+
-+ __ap4_do_counters(wc);
-+
-+ //x = wc->intcount & 15;
-+ x = wc->intcount & 7;
-+ switch(x) {
-+ case 0:
-+ case 1:
-+ case 2:
-+ case 3:
-+ __ap4_check_alarms(wc, x);
-+ break;
-+ case 4:
-+ case 5:
-+ case 6:
-+ case 7:
-+ __ap4_check_sigbits(wc, x - 4);
-+ break;
-+ }
-+
-+ if (wc->checktiming > 0)
-+ __ap4_set_timing_source_auto(wc);
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+ /* IRQ was treated */
-+ ret = 1;
-+out:
-+#ifdef AP400_HDLC
-+ /* Call AP400_HDLC_CARD IRQ handler before leave */
-+ ret |= ap400_intr_handler(irq, wc->hdlc_card);
-+#endif
-+
-+ return IRQ_RETVAL(ret);
-+}
-+
-+
-+static int __devinit ap4_launch(struct ap4 *wc)
-+{
-+ int x;
-+ unsigned long flags;
-+
-+ if (wc->tspans[0]->span.flags & DAHDI_FLAG_REGISTERED)
-+ return 0;
-+ printk("%s: Launching card: %d\n", wc->variety, wc->order);
-+
-+ /* Setup serial parameters and system interface */
-+ for (x=0;x<4;x++) {
-+ //ap4_serial_setup(wc, x);
-+ wc->globalconfig = 1;
-+ }
-+
-+ for (x=0; x<wc->numspans; x++)
-+ list_add_tail(&wc->tspans[x]->span.device_node,
-+ &wc->ddev->spans);
-+ if (dahdi_register_device(wc->ddev, &wc->dev->dev)) {
-+ printk(KERN_ERR "Unable to register span %s\n", wc->tspans[0]->span.name);
-+ return -1; /* FIXME: proper error handling */
-+ }
-+ wc->checktiming = 1;
-+ spin_lock_irqsave(&wc->reglock, flags);
-+// __ap4_set_timing_source(wc,4);
-+ spin_unlock_irqrestore(&wc->reglock, flags);
-+#ifdef ENABLE_TASKLETS
-+ tasklet_init(&wc->ap4_tlet, ap4_tasklet, (unsigned long)wc);
-+#endif
-+ return 0;
-+}
-+
-+
-+static int ap4xx_liu_reset(struct ap4 *wc)
-+{
-+ unsigned int jiffies_hold = jiffies;
-+ *(wc->membase+AP_LEDS_REG) |= AP_LIU_RESET_BIT;
-+ while(jiffies<=(jiffies_hold+2));
-+ *(wc->membase+AP_LEDS_REG) &= ~AP_LIU_RESET_BIT;
-+ return 0;
-+}
-+
-+
-+static int ap4xx_bus_test(struct ap4 *wc)
-+{
-+ int tst_result = 0;
-+ unsigned int val;
-+
-+ *(wc->membase+AP_E1_CONFIG_REG) = 0xAAAAAAAA;
-+ *wc->membase = 0; // flush
-+ val = *(wc->membase+AP_E1_CONFIG_REG);
-+ if(val != 0xAAAAAAAA) {
-+ printk("Escrito 0xAAAAAAAA, lido 0x%08X!\n", val);
-+ tst_result++;
-+ }
-+ *(wc->membase+AP_E1_CONFIG_REG) = 0x55555555;
-+ *wc->membase = 0; // flush
-+ val = *(wc->membase+AP_E1_CONFIG_REG);
-+ if(val != 0x55555555) {
-+ printk("Escrito 0x55555555, lido 0x%08X!\n", val);
-+ tst_result++;
-+ }
-+ *(wc->membase+AP_E1_CONFIG_REG) = 0xFFFFFFFF;
-+ *wc->membase = 0; // flush
-+ val = *(wc->membase+AP_E1_CONFIG_REG);
-+ if(val != 0xFFFFFFFF) {
-+ printk("Escrito 0xFFFFFFFF, lido 0x%08X!\n", val);
-+ tst_result++;
-+ }
-+ *(wc->membase+AP_E1_CONFIG_REG) = 0x00000000;
-+ *wc->membase = 0xFFFFFFFF; // flush
-+ val = *(wc->membase+AP_E1_CONFIG_REG);
-+ if(val != 0x00000000) {
-+ printk("Escrito 0x00000000, lido 0x%08X!\n", val);
-+ tst_result++;
-+ }
-+ return tst_result;
-+}
-+
-+#ifdef TIMER_DEBUG
-+void ap4xx_opt_timeout(unsigned long arg)
-+{
-+ struct pci_dev *dev = (struct pci_dev *)arg;
-+ struct ap4 *wc = pci_get_drvdata(dev);
-+
-+// ap_debugk("wc->tspans[0]->span.chans[1].readchunk[1] = 0x%02x\n", wc->tspans[0]->span.chans[0].readchunk[1]);
-+// ap_debugk("e1s_cfg = 0x%08x\n", *(wc->membase+AP_E1_CONFIG_REG));
-+// ap_debugk("e1_status = 0x%08x\n", *(wc->membase + AP_E1_STATUS_REG));
-+// ap_debugk("clk_cfg = 0x%08x\n", *(wc->membase+0x07));
-+// ap_debugk("e1_data = 0x%08x\n", *(wc->membase + (AP_DATA_BASE + 1)));
-+// ap_debugk("cas_data = 0x%08x\n", *(wc->membase + AP_CAS_BASE));
-+
-+ // dispara timer novamente
-+ init_timer(&ap4xx_opt_timer);
-+ ap4xx_opt_timer.function = ap4xx_opt_timeout;
-+ ap4xx_opt_timer.data = arg;
-+ ap4xx_opt_timer.expires = jiffies + (delay/4);
-+ add_timer(&ap4xx_opt_timer);
-+
-+}
-+#endif
-+
-+static inline int ap4_card_detect (struct ap4 *wc) {
-+ int i;
-+ if ((wc->hw_regs->card_id != AP4XX_CARD_ID) &&
-+ (wc->hw_regs->card_id != APE4XX_CARD_ID)) {
-+ printk("AP400: Unknown card ID(0x%08X)! Aborting...\n", wc->hw_regs->card_id);
-+ return -EPERM;
-+ }
-+ // Test bus integrity
-+ for (i=0; i < 1000; i++) {
-+ if (ap4xx_bus_test(wc)) {
-+ printk("AP400: Bus integrity test failed! Aborting...\n");
-+ return -EIO;
-+ }
-+ }
-+ printk("AP400: Bus integrity OK!\n");
-+
-+ wc->fpgaver = wc->hw_regs->fpga_ver;
-+ wc->numspans = wc->hw_regs->span_num;
-+ wc->hwid = ((*(wc->membase+AP_HWCONFIG_REG))&AP_HWID_MASK)>>4;
-+
-+ if ((wc->hwid == AP_HWID_1E1_RJ && wc->numspans != 1) ||
-+ (wc->hwid == AP_HWID_2E1_RJ && wc->numspans != 2) ||
-+ (wc->hwid == AP_HWID_4E1_RJ && wc->numspans != 4)) {
-+ printk("AP400: Incompatible Hardware ID(0x%02x)! Aborting...\n", wc->hwid);
-+ return -EIO;
-+ }
-+
-+ if (wc->hw_regs->card_id == AP4XX_CARD_ID)
-+ switch (wc->numspans) {
-+ case 1:
-+ wc->dt = (struct devtype *) &ap401;
-+ break;
-+ case 2:
-+ wc->dt = (struct devtype *) &ap402;
-+ break;
-+ case 4:
-+ wc->dt = (struct devtype *) &ap404;
-+ break;
-+ default:
-+ printk("AP400: Unsupported spans number(%d)! Aborting...\n",
-+ wc->numspans);
-+ return -EPERM;
-+ }
-+ else
-+ switch (wc->numspans) {
-+ case 1:
-+ wc->dt = (struct devtype *) &ape401;
-+ break;
-+ case 2:
-+ wc->dt = (struct devtype *) &ape402;
-+ break;
-+ case 4:
-+ wc->dt = (struct devtype *) &ape404;
-+ break;
-+ default:
-+ printk("APE400: Unsupported spans number(%d)! Aborting...\n",
-+ wc->numspans);
-+ return -EPERM;
-+ }
-+
-+ wc->variety = wc->dt->desc;
-+ printk("Found a %s (firmware version %d.%d) at base address %08lx, remapped to %p\n",
-+ wc->variety, wc->fpgaver >> 8, wc->fpgaver & 0xFF,
-+ wc->memaddr, wc->membase);
-+
-+ return 0;
-+}
-+
-+static void __devexit ap4_remove_one(struct pci_dev *pdev);
-+
-+static int __devinit ap4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-+{
-+ int res;
-+ struct ap4 *wc;
-+ int x,f;
-+ int basesize;
-+ static int initd_ifaces=0;
-+ // Initialize pointer struct
-+ if(!initd_ifaces){
-+ memset((void *)cards,0,(sizeof(struct ap4 *))*MAX_AP4_CARDS);
-+ initd_ifaces=1;
-+ }
-+
-+ if ((res = pci_enable_device(pdev)) != 0) {
-+ goto out;
-+ }
-+ // Allocate card struct
-+ wc = kmalloc(sizeof(struct ap4), GFP_KERNEL);
-+ if (wc == NULL) {
-+ res = -ENOMEM;
-+ goto out;
-+ }
-+
-+ memset(wc, 0x0, sizeof(struct ap4));
-+ spin_lock_init(&wc->reglock);
-+
-+ basesize = DAHDI_MAX_CHUNKSIZE * 32 * 2 * 4;
-+
-+ // Request PCI regions
-+ if ((res = pci_request_regions(pdev, "ap400")) != 0) {
-+ printk("AP400: Unable to request regions!\n");
-+ goto out;
-+ }
-+
-+ // Remap PCI address
-+ wc->memaddr = pci_resource_start(pdev, 2);
-+ wc->memlen = pci_resource_len(pdev, 2);
-+ wc->membase = ioremap(wc->memaddr, wc->memlen);
-+ if(wc->membase == NULL) {
-+ printk("AP400: ioremap failed!\n");
-+ res = -EIO;
-+ goto out;
-+ }
-+ wc->hw_regs = (struct ap4_regs *) wc->membase;
-+
-+ // Detect Card model
-+ if ((res = ap4_card_detect(wc)) != 0)
-+ goto out;
-+
-+ ap4xx_liu_reset(wc);
-+
-+ // This rids of the Double missed interrupt message after loading
-+ wc->last0 = 1;
-+
-+ wc->dev = pdev;
-+
-+ // 32 channels, Double-buffer, Read/Write, 4 spans
-+ wc->writechunk = kmalloc(basesize * 2, GFP_KERNEL);
-+ if (!wc->writechunk) {
-+ printk("%s: Unable to allocate memory!\n", wc->variety);
-+ res = -ENOMEM;
-+ goto out;
-+ }
-+
-+ // Read is after the whole write piece (in words)
-+ wc->readchunk = wc->writechunk + basesize / 4;
-+
-+
-+ // Initialize Write/Buffers to all blank data
-+ memset((void *) wc->writechunk, 0x00, basesize);
-+ memset((void *) wc->readchunk, 0xff, basesize);
-+
-+ /* Keep track of which device we are */
-+ pci_set_drvdata(pdev, wc);
-+
-+ /* inicializa contador de interrupcao */
-+ wc->intcount = 0;
-+
-+ for(x = 0; x < MAX_AP4_CARDS; x++) {
-+ if (!cards[x]) break;
-+ }
-+
-+ if (x >= MAX_AP4_CARDS) {
-+ printk("No cards[] slot available!!\n");
-+ res = -ENOMEM;
-+ goto out;
-+ }
-+
-+ wc->num = x;
-+ cards[x] = wc;
-+
-+ /* Allocate pieces we need here, consider 31 channels for E1*/
-+ for (x=0;x<4;x++) {
-+ wc->tspans[x] = kmalloc(sizeof(struct ap4_span), GFP_KERNEL);
-+ if (wc->tspans[x]) {
-+ memset(wc->tspans[x], 0, sizeof(struct ap4_span));
-+ wc->tspans[x]->spantype = TYPE_E1;
-+ } else {
-+ res = -ENOMEM;
-+ goto out;
-+ }
-+ for (f = 0; f < 31; f++) {
-+ if (!(wc->tspans[x]->chans[f] = kmalloc(sizeof(*wc->tspans[x]->chans[f]), GFP_KERNEL))) {
-+ res = -ENOMEM;
-+ goto out;
-+ }
-+ memset(wc->tspans[x]->chans[f], 0, sizeof(*wc->tspans[x]->chans[f]));
-+ }
-+#ifdef ENABLE_WORKQUEUES
-+ INIT_WORK(&wc->tspans[x]->swork, workq_handlespan, wc->tspans[x]);
-+#endif
-+ wc->tspans[x]->spanflags |= wc->dt->flags;
-+ }
-+
-+ if (request_irq(pdev->irq, ap4_interrupt, IRQF_DISABLED | IRQF_SHARED, "ap400", wc))
-+ {
-+ printk("%s: Unable to request IRQ %d\n", wc->variety, pdev->irq);
-+ res = -EIO;
-+ goto out;
-+ }
-+
-+ wc->ddev = dahdi_create_device();
-+ wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d",
-+ wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
-+ if (!wc->ddev->location)
-+ return -ENOMEM; /* FIXME: proper error handling */
-+ wc->ddev->manufacturer = "Aligera";
-+ wc->ddev->devicetype = wc->variety;
-+ wc->ddev->irqmisses = 0;
-+ init_spans(wc);
-+
-+ /* Launch cards as appropriate */
-+ x = 0;
-+ for(;;) {
-+ /* Find a card to activate */
-+ f = 0;
-+ for (x=0;cards[x];x++) {
-+ if (cards[x]->order <= highestorder) {
-+ ap4_launch(cards[x]);
-+ if (cards[x]->order == highestorder)
-+ f = 1;
-+ }
-+ }
-+ /* If we found at least one, increment the highest order and search again, otherwise stop */
-+ if (f)
-+ highestorder++;
-+ else
-+ break;
-+ }
-+
-+#ifdef APEC_SUPPORT
-+ if (wc->fpgaver >= 0x0400)
-+ wc->apec_enable = 1;
-+#endif
-+
-+#ifdef TIMER_DEBUG
-+ // dispara timer de debug
-+ init_timer(&ap4xx_opt_timer);
-+ ap4xx_opt_timer.function = ap4xx_opt_timeout;
-+ ap4xx_opt_timer.data = (unsigned long) pdev;
-+ ap4xx_opt_timer.expires = jiffies + 100;
-+ add_timer(&ap4xx_opt_timer);
-+#endif
-+
-+ /* Initialize HDLC_CARD */
-+#ifdef AP400_HDLC
-+ u8 __iomem *base_addr[3];
-+ unsigned int bar_size[3];
-+ int i;
-+ base_addr[2] = (void *) wc->membase;
-+ bar_size[2] = wc->memlen;
-+ for (i = 0; i < 2; i++) {
-+ bar_size[i] = (u32) pci_resource_len(pdev, i);
-+ base_addr[i] = ioremap(pci_resource_start(pdev, i),
-+ bar_size[i]);
-+ if (base_addr[i] == NULL) {
-+ printk(KERN_ERR "Memory map failed\n");
-+ res = -ENODEV;
-+ goto out;
-+ }
-+ }
-+ ap400_card_init(&wc->hdlc_card, base_addr, bar_size);
-+ ap400_intr_enable(wc->hdlc_card);
-+#endif
-+
-+ res = 0;
-+out:
-+ if (res != 0) {
-+ ap4_remove_one(pdev);
-+ }
-+ return res;
-+}
-+
-+static void __devexit ap4_remove_one(struct pci_dev *pdev)
-+{
-+ struct ap4 *wc = pci_get_drvdata(pdev);
-+ int x;
-+
-+ if (wc) {
-+ ap_debugk("desabilita interrupcao!\n");
-+ // desabilita interrupcao
-+ *(wc->membase + AP_INT_CONTROL_REG) &= ~AP_INT_CTL_ENABLE;
-+
-+#ifdef APEC_SUPPORT
-+ // Stop echo cancellation module
-+ ap4_apec_release(wc);
-+#endif
-+ /* Unregister spans */
-+ dahdi_unregister_device(wc->ddev);
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+#ifdef ENABLE_WORKQUEUES
-+ if (wc->workq) {
-+ flush_workqueue(wc->workq);
-+ destroy_workqueue(wc->workq);
-+ }
-+#endif
-+
-+#ifdef TIMER_DEBUG
-+ del_timer(&ap4xx_opt_timer);
-+#endif
-+
-+ wc->hw_regs = NULL;
-+ if(wc->membase)
-+ iounmap((void *)wc->membase);
-+
-+ /* Immediately free resources */
-+ kfree((void *) wc->writechunk);
-+
-+#ifdef AP400_HDLC
-+ /* Remove HDLC Card */
-+ ap400_card_remove(wc->hdlc_card);
-+ if (wc->hdlc_card->cfg_base_addr)
-+ iounmap(wc->hdlc_card->cfg_base_addr);
-+ if (wc->hdlc_card->buf_base_addr)
-+ iounmap(wc->hdlc_card->buf_base_addr);
-+ kfree(wc->hdlc_card);
-+#endif
-+ free_irq(pdev->irq, wc);
-+
-+ cards[wc->num] = NULL;
-+ for (x=0;x<wc->numspans;x++) {
-+ if (wc->tspans[x])
-+ kfree(wc->tspans[x]);
-+ }
-+ kfree(wc);
-+ }
-+ pci_release_regions(pdev);
-+ pci_disable_device(pdev);
-+ pci_set_drvdata(pdev, NULL);
-+ printk(KERN_INFO "AP400 driver removed\n");
-+}
-+
-+
-+static struct pci_device_id ap4_pci_tbl[] __devinitdata =
-+{
-+ { PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_AP4XX), },
-+ { 0, }
-+};
-+
-+
-+static struct pci_driver ap4_driver = {
-+ .name = "Unified ap4xx driver",
-+ .probe = ap4_init_one,
-+#ifdef LINUX26
-+ .remove = __devexit_p(ap4_remove_one),
-+#else
-+ .remove = ap4_remove_one,
-+#endif
-+ .id_table = ap4_pci_tbl,
-+};
-+
-+static int __init ap4_init(void)
-+{
-+ int res;
-+ printk("Unified AP4XX PCI Card Driver\n");
-+ res = pci_register_driver(&ap4_driver);
-+ if (res) {
-+ return -ENODEV;
-+ }
-+ return 0;
-+}
-+
-+static void __exit ap4_cleanup(void)
-+{
-+ printk("Unified AP4XX PCI Card Driver Cleanup\n");
-+ pci_unregister_driver(&ap4_driver);
-+}
-+
-+
-+MODULE_AUTHOR("Aligera (aligera@aligera.com.br)");
-+MODULE_DESCRIPTION("Unified AP4XX PCI Card Driver");
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+module_param(debug, int, 0600);
-+module_param(loopback, int, 0600);
-+module_param(noburst, int, 0600);
-+module_param(debugslips, int, 0600);
-+module_param(polling, int, 0600);
-+module_param(timingcable, int, 0600);
-+module_param(t1e1override, int, 0600);
-+module_param(alarmdebounce, int, 0600);
-+module_param(j1mode, int, 0600);
-+
-+MODULE_DEVICE_TABLE(pci, ap4_pci_tbl);
-+
-+module_init(ap4_init);
-+module_exit(ap4_cleanup);
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/ap400/ap400.h dahdi-extra-dahdi-linux/drivers/dahdi/ap400/ap400.h
---- dahdi-linux-2.7.0/drivers/dahdi/ap400/ap400.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/ap400/ap400.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,107 @@
-+/*
-+ * AP4XX T1/E1 PCI Driver
-+ *
-+ * Written by Ronaldo Valiati <aligera@aligera.com.br>
-+ *
-+ * Based on previous works, designs, and archetectures conceived and
-+ * written by Jim Dixon <jim@lambdatel.com> and Mark Spencer <markster@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 -uNr dahdi-linux-2.7.0/drivers/dahdi/ap400/apec.c dahdi-extra-dahdi-linux/drivers/dahdi/ap400/apec.c
---- dahdi-linux-2.7.0/drivers/dahdi/ap400/apec.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/ap400/apec.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,400 @@
-+/*
-+ * AP400 Echo Cancelation Hardware support
-+ *
-+ * Written by Wagner Gegler <aligera@aligera.com.br>
-+ *
-+ * Based on previous work written by Mark Spencer <markster@digium.com>
-+ *
-+ * Copyright (C) 2005-2006 Digium, Inc.
-+ *
-+ * Mark Spencer <markster@digium.com>
-+ *
-+ * 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/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/string.h>
-+#include <linux/time.h>
-+#include <linux/version.h>
-+#include <linux/delay.h>
-+
-+#include "apec.h"
-+#include "oct6100api/oct6100_api.h"
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
-+#include <linux/config.h>
-+#else
-+#include <linux/autoconf.h>
-+#endif
-+
-+/* API for Octasic access */
-+UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
-+{
-+ /* Why couldn't they just take a timeval like everyone else? */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
-+ struct timeval tv;
-+#else
-+ struct timespec64 tv;
-+#endif
-+ unsigned long long total_usecs;
-+ unsigned int mask = ~0;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
-+ do_gettimeofday(&tv);
-+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
-+ (((unsigned long long)(tv.tv_usec)));
-+#else
-+ ktime_get_real_ts64(&tv);
-+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
-+ (((unsigned long long)(tv.tv_nsec))) / 1000;
-+#endif
-+ 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("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_write(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_write(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_write(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_read(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_read(f_pBurstParams->pProcessContext, f_pBurstParams->ulReadAddress + (x << 1));
-+ }
-+ return cOCT6100_ERR_OK;
-+}
-+
-+#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 apec_s {
-+ 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 void apec_setecmode(struct apec_s *apec, int channel, int mode)
-+{
-+ tOCT6100_CHANNEL_MODIFY *modify;
-+ UINT32 ulResult;
-+
-+ if (apec->ecmode[channel] == mode)
-+ return;
-+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC);
-+ if (!modify) {
-+ printk("APEC: Unable to allocate memory for setec!\n");
-+ return;
-+ }
-+ Oct6100ChannelModifyDef(modify);
-+ modify->ulEchoOperationMode = mode;
-+ modify->ulChannelHndl = apec->aulEchoChanHndl[channel];
-+ ulResult = Oct6100ChannelModify(apec->pApiInstance, modify);
-+ if (ulResult != GENERIC_OK) {
-+ printk("Failed to apply echo can changes on channel %d!\n", channel);
-+ } else {
-+#ifdef OCTASIC_DEBUG
-+ printk("Echo can on channel %d set to %d\n", channel, mode);
-+#endif
-+ apec->ecmode[channel] = mode;
-+ }
-+ kfree(modify);
-+}
-+
-+void apec_setec(struct apec_s *apec, int channel, int eclen)
-+{
-+ if (eclen) {
-+ apec->chanflags[channel] |= FLAG_ECHO;
-+ apec_setecmode(apec, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
-+ apec_setecmode(apec, channel, cOCT6100_ECHO_OP_MODE_NORMAL);
-+ } else {
-+ apec->chanflags[channel] &= ~FLAG_ECHO;
-+ if (apec->chanflags[channel] & (FLAG_DTMF | FLAG_MUTE)) {
-+ apec_setecmode(apec, channel, cOCT6100_ECHO_OP_MODE_HT_RESET);
-+ apec_setecmode(apec, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE);
-+ } else
-+ apec_setecmode(apec, channel, cOCT6100_ECHO_OP_MODE_DIGITAL);
-+ }
-+ printk("APEC: Setting EC on channel %d to %d\n", channel, eclen);
-+}
-+
-+int apec_checkirq(struct apec_s *apec)
-+{
-+ tOCT6100_INTERRUPT_FLAGS InterruptFlags;
-+
-+ Oct6100InterruptServiceRoutineDef(&InterruptFlags);
-+ Oct6100InterruptServiceRoutine(apec->pApiInstance, &InterruptFlags);
-+
-+ return InterruptFlags.fToneEventsPending ? 1 : 0;
-+}
-+
-+unsigned int apec_capacity_get(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("Failed to get chip capacity, code %08x!\n", ulResult);
-+ return 0;
-+ }
-+ return CapacityPins.ulCapacityValue;
-+}
-+
-+struct apec_s *apec_init(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 apec_s *apec;
-+ int x, law;
-+#ifdef CONFIG_4KSTACKS
-+ unsigned long flags;
-+#endif
-+
-+ if (!(apec = kmalloc(sizeof(struct apec_s), GFP_KERNEL)))
-+ return NULL;
-+
-+ memset(apec, 0, sizeof(struct apec_s));
-+
-+ if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
-+ kfree(apec);
-+ return NULL;
-+ }
-+
-+ memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN));
-+
-+ if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) {
-+ kfree(apec);
-+ kfree(ChipOpen);
-+ return NULL;
-+ }
-+
-+ memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN));
-+
-+ for (x=0;x<128;x++)
-+ apec->ecmode[x] = -1;
-+
-+ apec->numchans = numspans * 32;
-+ printk("APEC: echo cancellation for %d channels\n", apec->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 = apec->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("Failed to get instance size, code %08x!\n", ulResult);
-+ kfree(apec);
-+ return NULL;
-+ }
-+
-+
-+ apec->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize);
-+ if (!apec->pApiInstance) {
-+ printk("Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize);
-+ kfree(apec);
-+ 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(apec->pApiInstance, ChipOpen);
-+ if (ulResult != cOCT6100_ERR_OK) {
-+ printk("Failed to open chip, code %08x!\n", ulResult);
-+#ifdef CONFIG_4KSTACKS
-+ local_irq_restore(flags);
-+#endif
-+ kfree(apec);
-+ kfree(ChipOpen);
-+ kfree(ChannelOpen);
-+ return NULL;
-+ }
-+ for (x=0; x < 128; x++) {
-+ /* execute this loop always on 4 span cards but
-+ * on 2 span cards only execute for the channels related to our spans */
-+ if ((x & 0x3) < 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 = &apec->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(apec->pApiInstance, ChannelOpen);
-+ if (ulResult != GENERIC_OK) {
-+ printk("Failed to open channel %d!\n", x);
-+ }
-+ }
-+ }
-+
-+#ifdef CONFIG_4KSTACKS
-+ local_irq_restore(flags);
-+#endif
-+ kfree(ChipOpen);
-+ kfree(ChannelOpen);
-+ return apec;
-+}
-+
-+void apec_release(struct apec_s *apec)
-+{
-+ UINT32 ulResult;
-+ tOCT6100_CHIP_CLOSE ChipClose;
-+
-+ Oct6100ChipCloseDef(&ChipClose);
-+ ulResult = Oct6100ChipClose(apec->pApiInstance, &ChipClose);
-+ if (ulResult != cOCT6100_ERR_OK) {
-+ printk("Failed to close chip, code %08x!\n", ulResult);
-+ }
-+ vfree(apec->pApiInstance);
-+ kfree(apec);
-+ printk(KERN_INFO "APEC: Releasing...\n");
-+}
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/ap400/apec.h dahdi-extra-dahdi-linux/drivers/dahdi/ap400/apec.h
---- dahdi-linux-2.7.0/drivers/dahdi/ap400/apec.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/ap400/apec.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,48 @@
-+/*
-+ * AP400 Echo Cancelation Hardware support
-+ *
-+ * Written by Wagner Gegler <aligera@aligera.com.br>
-+ *
-+ * Based on previous work written by Mark Spencer <markster@digium.com>
-+ *
-+ * Copyright (C) 2005-2006 Digium, Inc.
-+ *
-+ * Mark Spencer <markster@digium.com>
-+ *
-+ * All Rights Reserved
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#ifndef _APEC_H_
-+#define _APEC_H_
-+
-+#include <linux/firmware.h>
-+
-+struct apec_s;
-+
-+/* From AP400 */
-+unsigned int oct_read(void *card, unsigned int addr);
-+void oct_write(void *card, unsigned int addr, unsigned int data);
-+
-+/* From APEC */
-+struct apec_s *apec_init(void *wc, int *isalaw, int numspans, const struct firmware *firmware);
-+unsigned int apec_capacity_get(void *wc);
-+void apec_setec(struct apec_s *instance, int channel, int eclen);
-+int apec_checkirq(struct apec_s *apec);
-+void apec_release(struct apec_s *instance);
-+
-+#endif /*_APEC_H_*/
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/ap400/Kbuild dahdi-extra-dahdi-linux/drivers/dahdi/ap400/Kbuild
---- dahdi-linux-2.7.0/drivers/dahdi/ap400/Kbuild 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/ap400/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/dahdi/Kbuild dahdi-extra-dahdi-linux/drivers/dahdi/Kbuild
---- dahdi-linux-2.7.0/drivers/dahdi/Kbuild 2013-06-07 20:29:39.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -39,6 +39,14 @@
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_KB1) += dahdi_echocan_kb1.o
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ECHOCAN_MG2) += dahdi_echocan_mg2.o
-
-+ifdef CONFIG_PCI
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_AP400) += ap400/
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200) += opvxa1200/
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115) += opvxd115/
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCOPENPCI) += wcopenpci.o
-+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ZAPHFC) += zaphfc/
-+endif
-+
- obj-m += $(DAHDI_MODULES_EXTRA)
-
- # If you want to build OSLEC, include the code in the standard location:
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/Kconfig dahdi-extra-dahdi-linux/drivers/dahdi/Kconfig
---- dahdi-linux-2.7.0/drivers/dahdi/Kconfig 2013-06-07 20:29:39.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/Kconfig 2013-06-04 15:18:43.000000000 +0100
-@@ -292,3 +292,89 @@
- If unsure, say Y.
-
- source "drivers/dahdi/xpp/Kconfig"
-+
-+config DAHDI_AP4XX
-+ tristate "Aligera AP4XX PCI Card Driver"
-+ depends on DAHDI && PCI
-+ default DAHDI
-+ ---help---
-+ This driver provides support for the Aligera AP400 quad-span
-+ E1/T1 DAHDI cards:
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called ap4xx.
-+
-+ 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_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_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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/base.c dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/base.c
---- dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/base.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/base.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,3070 @@
-+/*
-+ * OpenVox A1200P FXS/FXO Interface Driver for DAHDI Telephony interface
-+ *
-+ * Written by MiaoLin<miaolin@openvox.cn>
-+ *
-+ * Copyright (C) 2005-2010 OpenVox Communication Co. Ltd,
-+ *
-+ * 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.
-+ *
-+ */
-+
-+/* Rev histroy
-+ *
-+ * Rev 0.10 initial version
-+ * Rev 0.11
-+ * fixed the led light on/off bug.
-+ * modify some wctdm print to opvxa1200
-+ * support firmware version 1.2, faster i/o operation, and better LED control.
-+ *
-+ * Rev 0.12 patched to support new pci id 0x8519
-+ * Rev 0.13 patched to remove the warning during compile under kernel 2.6.22
-+ * Rev 0.14 patched to remove the bug for ZAP_IRQ_SHARED , 3/9/2007
-+ * Rev 0.15 patched to support new pci ID 0X9532 by james.zhu, 23/10/2007
-+ * Rev 0.16 support new pci id 0x9559 by Miao Lin 21/3/2008
-+ * Rev 0.17
-+ * patched a few bugs,
-+ * add hwgain support.
-+ * fixed A800P version check
-+ * Rev 1.4.9.2
-+ * Only generate 8 channels for A800P
-+ * Version number synced to zaptel distribution.
-+ * Rev 1.4.9.2.a
-+ * Fixed freeregion.
-+ *
-+ * Rev 1.4.9.2.b
-+ * Add cid before first ring support.
-+ * New Paremeters:
-+ * cidbeforering : set to 1 will cause the card enable cidbeforering function. default 0
-+ * cidbuflen : length of cid buffer, in msec, default 3000 msec.
-+ * cidtimeout : time out of a ring, default 6000msec
-+ * User must set cidstart=polarity in zapata.conf to use with this feature
-+ * cidsignalling = signalling format send before 1st ring. most likely dtmf.
-+ *
-+ * Rev 1.4.9.2.c
-+ * add driver parameter cidtimeout.
-+ *
-+ * Rev 1.4.9.2.d
-+ * add debug stuff to test fxs power alarm
-+ *
-+ * Rev 1.4.11
-+ * Support enhanced full scale tx/rx for FXO required by europe standard (Register 30, acim) (module parm fxofullscale)
-+ *
-+ * Rev 1.4.12 2008/10/17
-+ * Fixed bug cause FXS module report fake power alarm.
-+ * Power alarm debug stuff removed.
-+ *
-+ * Rev 2.0 DAHDI 2008/10/17
-+ *
-+ * Rev 2.0.1 add new pci id 0x9599
-+ * Re 2.0.2 12/01/2009
-+ add fixedtimepolarity: set time(ms) when send polarity after 1st ring happen.
-+ * Sometimes the dtmf cid is sent just after first ring off, and the system do not have
-+ * enough time to start detect 1st dtmf.
-+ * 0 means send polarity at the end of 1st ring.
-+ * x means send ploarity after x ms of 1st ring begin.
-+ *
-+ * Rev 2.0.3 12/01/2009
-+ * Add touch_softlockup_watchdog() in wctdm_hardware_init, to avoid cpu softlockup system message for FXS.
-+ *
-+ *
-+ * Rev 1.4.12.4 17/04/2009 James.zhu
-+ * Changed wctdm_voicedaa_check_hook() to detect FXO battery and solved the problem with dial(dahdi/go/XXXXXXXXXX)
-+ * add alarm detection for FXO
-+ *
-+ * Rev 1.4.12.5 01/10/2009 james.zhu
-+ * Add jiffies for 5 second in wctdm_hardware_init
-+ *
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <linux/moduleparam.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
-+#include <linux/nmi.h>
-+#else
-+#include <linux/sched.h>
-+#endif
-+#include "proslic.h"
-+
-+/* MiaoLin debug start */
-+#include <linux/string.h>
-+#include <asm/uaccess.h> /* get_fs(), set_fs(), KERNEL_DS */
-+#include <linux/file.h> /* fput() */
-+/* MiaoLin debug end */
-+
-+
-+/*
-+ * Define for audio vs. register based ring detection
-+ *
-+ */
-+/* #define AUDIO_RINGCHECK */
-+
-+/*
-+ Experimental max loop current limit for the proslic
-+ Loop current limit is from 20 mA to 41 mA in steps of 3
-+ (according to datasheet)
-+ So set the value below to:
-+ 0x00 : 20mA (default)
-+ 0x01 : 23mA
-+ 0x02 : 26mA
-+ 0x03 : 29mA
-+ 0x04 : 32mA
-+ 0x05 : 35mA
-+ 0x06 : 37mA
-+ 0x07 : 41mA
-+*/
-+static int loopcurrent = 20;
-+
-+static int reversepolarity = 0;
-+
-+static alpha indirect_regs[] =
-+{
-+{0,255,"DTMF_ROW_0_PEAK",0x55C2},
-+{1,255,"DTMF_ROW_1_PEAK",0x51E6},
-+{2,255,"DTMF_ROW2_PEAK",0x4B85},
-+{3,255,"DTMF_ROW3_PEAK",0x4937},
-+{4,255,"DTMF_COL1_PEAK",0x3333},
-+{5,255,"DTMF_FWD_TWIST",0x0202},
-+{6,255,"DTMF_RVS_TWIST",0x0202},
-+{7,255,"DTMF_ROW_RATIO_TRES",0x0198},
-+{8,255,"DTMF_COL_RATIO_TRES",0x0198},
-+{9,255,"DTMF_ROW_2ND_ARM",0x0611},
-+{10,255,"DTMF_COL_2ND_ARM",0x0202},
-+{11,255,"DTMF_PWR_MIN_TRES",0x00E5},
-+{12,255,"DTMF_OT_LIM_TRES",0x0A1C},
-+{13,0,"OSC1_COEF",0x7B30},
-+{14,1,"OSC1X",0x0063},
-+{15,2,"OSC1Y",0x0000},
-+{16,3,"OSC2_COEF",0x7870},
-+{17,4,"OSC2X",0x007D},
-+{18,5,"OSC2Y",0x0000},
-+{19,6,"RING_V_OFF",0x0000},
-+{20,7,"RING_OSC",0x7EF0},
-+{21,8,"RING_X",0x0160},
-+{22,9,"RING_Y",0x0000},
-+{23,255,"PULSE_ENVEL",0x2000},
-+{24,255,"PULSE_X",0x2000},
-+{25,255,"PULSE_Y",0x0000},
-+//{26,13,"RECV_DIGITAL_GAIN",0x4000}, // playback volume set lower
-+{26,13,"RECV_DIGITAL_GAIN",0x2000}, // playback volume set lower
-+{27,14,"XMIT_DIGITAL_GAIN",0x4000},
-+//{27,14,"XMIT_DIGITAL_GAIN",0x2000},
-+{28,15,"LOOP_CLOSE_TRES",0x1000},
-+{29,16,"RING_TRIP_TRES",0x3600},
-+{30,17,"COMMON_MIN_TRES",0x1000},
-+{31,18,"COMMON_MAX_TRES",0x0200},
-+{32,19,"PWR_ALARM_Q1Q2",0x07C0},
-+{33,20,"PWR_ALARM_Q3Q4",0x2600},
-+{34,21,"PWR_ALARM_Q5Q6",0x1B80},
-+{35,22,"LOOP_CLOSURE_FILTER",0x8000},
-+{36,23,"RING_TRIP_FILTER",0x0320},
-+{37,24,"TERM_LP_POLE_Q1Q2",0x008C},
-+{38,25,"TERM_LP_POLE_Q3Q4",0x0100},
-+{39,26,"TERM_LP_POLE_Q5Q6",0x0010},
-+{40,27,"CM_BIAS_RINGING",0x0C00},
-+{41,64,"DCDC_MIN_V",0x0C00},
-+{42,255,"DCDC_XTRA",0x1000},
-+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000},
-+};
-+
-+
-+#include <dahdi/kernel.h>
-+#include <dahdi/wctdm_user.h>
-+
-+#include "fxo_modes.h"
-+
-+#define NUM_FXO_REGS 60
-+
-+#define WC_MAX_IFACES 128
-+
-+#define WC_OFFSET 4 /* Offset between transmit and receive, in bytes. */
-+#define WC_SYNCFLAG 0xca1ef1ac
-+
-+#define WC_CNTL 0x00
-+#define WC_OPER 0x01
-+#define WC_AUXC 0x02
-+#define WC_AUXD 0x03
-+#define WC_MASK0 0x04
-+#define WC_MASK1 0x05
-+#define WC_INTSTAT 0x06
-+#define WC_AUXR 0x07
-+
-+#define WC_DMAWS 0x08
-+#define WC_DMAWI 0x0c
-+#define WC_DMAWE 0x10
-+#define WC_DMARS 0x18
-+#define WC_DMARI 0x1c
-+#define WC_DMARE 0x20
-+
-+#define WC_AUXFUNC 0x2b
-+#define WC_SERCTL 0x2d
-+#define WC_FSCDELAY 0x2f
-+
-+#define WC_REGBASE 0xc0
-+
-+#define WC_VER 0x0
-+#define WC_CS 0x1
-+#define WC_SPICTRL 0x2
-+#define WC_SPIDATA 0x3
-+
-+#define BIT_SPI_BYHW (1 << 0)
-+#define BIT_SPI_BUSY (1 << 1) // 0=can read/write spi, 1=spi working.
-+#define BIT_SPI_START (1 << 2)
-+
-+
-+#define BIT_LED_CLK (1 << 0) // MiaoLin add to control the led.
-+#define BIT_LED_DATA (1 << 1) // MiaoLin add to control the led.
-+
-+#define BIT_CS (1 << 2)
-+#define BIT_SCLK (1 << 3)
-+#define BIT_SDI (1 << 4)
-+#define BIT_SDO (1 << 5)
-+
-+#define FLAG_EMPTY 0
-+#define FLAG_WRITE 1
-+#define FLAG_READ 2
-+#define DEFAULT_RING_DEBOUNCE 64 /* Ringer Debounce (64 ms) */
-+#define POLARITY_DEBOUNCE 64 /* Polarity debounce (64 ms) */
-+#define OHT_TIMER 6000 /* How long after RING to retain OHT */
-+
-+#define FLAG_3215 (1 << 0)
-+#define FLAG_A800 (1 << 7)
-+
-+#define MAX_NUM_CARDS 12
-+#define NUM_CARDS 12
-+#define NUM_FLAG 4 /* number of flag channels. */
-+
-+
-+enum cid_hook_state {
-+ CID_STATE_IDLE = 0,
-+ CID_STATE_RING_ON,
-+ CID_STATE_RING_OFF,
-+ CID_STATE_WAIT_RING_FINISH
-+};
-+
-+/* if you want to record the last 8 sec voice before the driver unload, uncomment it and rebuild. */
-+/* #define TEST_LOG_INCOME_VOICE */
-+#define voc_buffer_size (8000*8)
-+
-+
-+#define MAX_ALARMS 10
-+
-+#define MOD_TYPE_FXS 0
-+#define MOD_TYPE_FXO 1
-+
-+#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */
-+#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */
-+#define PEGCOUNT 5 /* 5 cycles of pegging means RING */
-+
-+#define NUM_CAL_REGS 12
-+
-+struct calregs {
-+ unsigned char vals[NUM_CAL_REGS];
-+};
-+
-+enum proslic_power_warn {
-+ PROSLIC_POWER_UNKNOWN = 0,
-+ PROSLIC_POWER_ON,
-+ PROSLIC_POWER_WARNED,
-+};
-+
-+enum battery_state {
-+ BATTERY_UNKNOWN = 0,
-+ BATTERY_PRESENT,
-+ BATTERY_LOST,
-+};
-+struct wctdm {
-+ struct pci_dev *dev;
-+ char *variety;
-+ struct dahdi_span span;
-+ struct dahdi_device *ddev;
-+ unsigned char ios;
-+ int usecount;
-+ unsigned int intcount;
-+ int dead;
-+ int pos;
-+ int flags[MAX_NUM_CARDS];
-+ int freeregion;
-+ int alt;
-+ int curcard;
-+ int cardflag; /* Bit-map of present cards */
-+ enum proslic_power_warn proslic_power;
-+ spinlock_t lock;
-+
-+ union {
-+ struct fxo {
-+#ifdef AUDIO_RINGCHECK
-+ unsigned int pegtimer;
-+ int pegcount;
-+ int peg;
-+ int ring;
-+#else
-+ int wasringing;
-+ int lastrdtx;
-+#endif
-+ int ringdebounce;
-+ int offhook;
-+ unsigned int battdebounce;
-+ unsigned int battalarm;
-+ enum battery_state battery;
-+ int lastpol;
-+ int polarity;
-+ int polaritydebounce;
-+ } fxo;
-+ struct fxs {
-+ int oldrxhook;
-+ int debouncehook;
-+ int lastrxhook;
-+ int debounce;
-+ int ohttimer;
-+ int idletxhookstate; /* IDLE changing hook state */
-+ int lasttxhook;
-+ int palarms;
-+ struct calregs calregs;
-+ } fxs;
-+ } mod[MAX_NUM_CARDS];
-+
-+ /* Receive hook state and debouncing */
-+ int modtype[MAX_NUM_CARDS];
-+ unsigned char reg0shadow[MAX_NUM_CARDS];
-+ unsigned char reg1shadow[MAX_NUM_CARDS];
-+
-+ unsigned long ioaddr;
-+ unsigned long mem_region; /* 32 bit Region allocated to tiger320 */
-+ unsigned long mem_len; /* Length of 32 bit region */
-+ volatile unsigned long mem32; /* Virtual representation of 32 bit memory area */
-+
-+ dma_addr_t readdma;
-+ dma_addr_t writedma;
-+ volatile unsigned char *writechunk; /* Double-word aligned write memory */
-+ volatile unsigned char *readchunk; /* Double-word aligned read memory */
-+ /*struct dahdi_chan chans[MAX_NUM_CARDS];*/
-+ struct dahdi_chan _chans[NUM_CARDS];
-+ struct dahdi_chan *chans[NUM_CARDS];
-+
-+
-+#ifdef TEST_LOG_INCOME_VOICE
-+ char * voc_buf[MAX_NUM_CARDS + NUM_FLAG];
-+ int voc_ptr[MAX_NUM_CARDS + NUM_FLAG];
-+#endif
-+ int lastchan;
-+ unsigned short ledstate;
-+ unsigned char fwversion;
-+ int max_cards;
-+ char *card_name;
-+
-+ char *cid_history_buf[MAX_NUM_CARDS];
-+ int cid_history_ptr[MAX_NUM_CARDS];
-+ int cid_history_clone_cnt[MAX_NUM_CARDS];
-+ enum cid_hook_state cid_state[MAX_NUM_CARDS];
-+ int cid_ring_on_time[MAX_NUM_CARDS];
-+};
-+
-+static char* A1200P_Name = "A1200P";
-+static char* A800P_Name = "A800P";
-+
-+struct wctdm_desc {
-+ char *name;
-+ int flags;
-+};
-+
-+static struct wctdm_desc wctdme = { "OpenVox A1200P/A800P", 0 };
-+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };
-+
-+static struct wctdm *ifaces[WC_MAX_IFACES];
-+
-+static void wctdm_release(struct wctdm *wc);
-+
-+static unsigned int battdebounce;
-+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;
-+static int timingonly = 0;
-+static int lowpower = 0;
-+static int boostringer = 0;
-+static int fastringer = 0;
-+static int _opermode = 0;
-+static char *opermode = "FCC";
-+static int fxshonormode = 0;
-+static int alawoverride = 0;
-+static int fastpickup = 0;
-+static int fxotxgain = 0;
-+static int fxorxgain = 0;
-+static int fxstxgain = 0;
-+static int fxsrxgain = 0;
-+/* special h/w control command */
-+static int spibyhw = 1;
-+static int usememio = 1;
-+static int cidbeforering = 0;
-+static int cidbuflen = 3000; /* in msec, default 3000 */
-+static int cidtimeout = 6*1000; /* in msec, default 6000 */
-+static int fxofullscale = 0; /* fxo full scale tx/rx, register 30, acim */
-+static int fixedtimepolarity=0; /* time delay in ms when send polarity after rise edge of 1st ring.*/
-+
-+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane);
-+
-+static void wctdm_set_led(struct wctdm* wc, int card, int onoff)
-+{
-+ int i;
-+ unsigned char c;
-+
-+ wc->ledstate &= ~(0x01<<card);
-+ wc->ledstate |= (onoff<<card);
-+ c = (inb(wc->ioaddr + WC_AUXD)&~BIT_LED_CLK)|BIT_LED_DATA;
-+ outb( c, wc->ioaddr + WC_AUXD);
-+ for(i=MAX_NUM_CARDS-1; i>=0; i--)
-+ {
-+ if(wc->ledstate & (0x0001<<i))
-+ if(wc->fwversion == 0x11)
-+ c &= ~BIT_LED_DATA;
-+ else
-+ c |= BIT_LED_DATA;
-+ else
-+ if(wc->fwversion == 0x11)
-+ c |= BIT_LED_DATA;
-+ else
-+ c &= ~BIT_LED_DATA;
-+
-+ outb( c, wc->ioaddr + WC_AUXD);
-+ outb( c|BIT_LED_CLK, wc->ioaddr + WC_AUXD);
-+ outb( (c&~BIT_LED_CLK)|BIT_LED_DATA, wc->ioaddr + WC_AUXD);
-+ }
-+}
-+
-+
-+static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char ints)
-+{
-+ int x, y, chan_offset, pos;
-+ volatile unsigned char *txbuf;
-+
-+ if (ints & /*0x01*/ 0x04)
-+ /* Write is at interrupt address. Start writing from normal offset */
-+ txbuf = wc->writechunk;
-+ else
-+ txbuf = wc->writechunk + DAHDI_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG);
-+
-+ /* Calculate Transmission */
-+ dahdi_transmit(&wc->span);
-+
-+ if(wc->lastchan == -1) // not in sync.
-+ return;
-+
-+ chan_offset = (wc->lastchan*4 + 4 ) % (MAX_NUM_CARDS+NUM_FLAG);
-+
-+ for (y=0;y<DAHDI_CHUNKSIZE;y++) {
-+#ifdef __BIG_ENDIAN
-+ // operation pending...
-+#else
-+ for (x=0;x<(MAX_NUM_CARDS+NUM_FLAG);x++) {
-+ pos = y * (MAX_NUM_CARDS+NUM_FLAG) + ((x + chan_offset + MAX_NUM_CARDS+NUM_FLAG - WC_OFFSET)&0x0f);
-+ if(x<wc->max_cards/*MAX_NUM_CARDS*/)
-+ txbuf[pos] = wc->chans[x]->writechunk[y];
-+ else
-+ txbuf[pos] = 0;
-+ }
-+#endif
-+ }
-+}
-+
-+
-+#ifdef AUDIO_RINGCHECK
-+static inline void ring_check(struct wctdm *wc, int card)
-+{
-+ int x;
-+ short sample;
-+ if (wc->modtype[card] != MOD_TYPE_FXO)
-+ return;
-+ wc->mod[card].fxo.pegtimer += DAHDI_CHUNKSIZE;
-+ for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-+ /* Look for pegging to indicate ringing */
-+ sample = DAHDI_XLAW(wc->chans[card].readchunk[x], (&(wc->chans[card])));
-+ if ((sample > 10000) && (wc->mod[card].fxo.peg != 1)) {
-+ if (debug > 1) printk(KERN_DEBUG "High peg!\n");
-+ if ((wc->mod[card].fxo.pegtimer < PEGTIME) && (wc->mod[card].fxo.pegtimer > MINPEGTIME))
-+ wc->mod[card].fxo.pegcount++;
-+ wc->mod[card].fxo.pegtimer = 0;
-+ wc->mod[card].fxo.peg = 1;
-+ } else if ((sample < -10000) && (wc->mod[card].fxo.peg != -1)) {
-+ if (debug > 1) printk(KERN_DEBUG "Low peg!\n");
-+ if ((wc->mod[card].fxo.pegtimer < (PEGTIME >> 2)) && (wc->mod[card].fxo.pegtimer > (MINPEGTIME >> 2)))
-+ wc->mod[card].fxo.pegcount++;
-+ wc->mod[card].fxo.pegtimer = 0;
-+ wc->mod[card].fxo.peg = -1;
-+ }
-+ }
-+ if (wc->mod[card].fxo.pegtimer > PEGTIME) {
-+ /* Reset pegcount if our timer expires */
-+ wc->mod[card].fxo.pegcount = 0;
-+ }
-+ /* Decrement debouncer if appropriate */
-+ if (wc->mod[card].fxo.ringdebounce)
-+ wc->mod[card].fxo.ringdebounce--;
-+ if (!wc->mod[card].fxo.offhook && !wc->mod[card].fxo.ringdebounce) {
-+ if (!wc->mod[card].fxo.ring && (wc->mod[card].fxo.pegcount > PEGCOUNT)) {
-+ /* It's ringing */
-+ if (debug)
-+ printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ if (!wc->mod[card].fxo.offhook)
-+ dahdi_hooksig(&wc->chans[card], DAHDI_RXSIG_RING);
-+ wc->mod[card].fxo.ring = 1;
-+ }
-+ if (wc->mod[card].fxo.ring && !wc->mod[card].fxo.pegcount) {
-+ /* No more ring */
-+ if (debug)
-+ printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ dahdi_hooksig(&wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ wc->mod[card].fxo.ring = 0;
-+ }
-+ }
-+}
-+#endif
-+
-+
-+static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char ints)
-+{
-+ volatile unsigned char *rxbuf;
-+ int x, y, chan_offset;
-+
-+
-+ if (ints & 0x08/*0x04*/)
-+ /* Read is at interrupt address. Valid data is available at normal offset */
-+ rxbuf = wc->readchunk;
-+ else
-+ rxbuf = wc->readchunk + DAHDI_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG);
-+
-+ for(x=0; x<4; x++)
-+ if( *(int*)(rxbuf+x*4) == WC_SYNCFLAG)
-+ break;
-+ if(x==4)
-+ {
-+ printk("buffer sync misseed!\n");
-+ wc->lastchan = -1;
-+ return;
-+ }
-+ else if(wc->lastchan != x)
-+ {
-+ printk("buffer re-sync occur from %d to %d\n", wc->lastchan, x);
-+ wc->lastchan = x;
-+ }
-+ chan_offset = (wc->lastchan*4 + 4 ) % (MAX_NUM_CARDS+NUM_FLAG);
-+
-+ for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-+#ifdef __BIG_ENDIAN
-+ // operation pending...
-+#else
-+ for (y=0;y<wc->max_cards/*MAX_NUM_CARDS*/;y++) {
-+ if (wc->cardflag & (1 << y))
-+ wc->chans[y]->readchunk[x] = rxbuf[(MAX_NUM_CARDS+NUM_FLAG) * x + ((y + chan_offset ) & 0x0f)];
-+#ifdef TEST_LOG_INCOME_VOICE
-+ wc->voc_buf[y][wc->voc_ptr[y]] = rxbuf[(MAX_NUM_CARDS+NUM_FLAG) * x + ((y + chan_offset) & 0x0f)];
-+ wc->voc_ptr[y]++;
-+ if(wc->voc_ptr[y] >= voc_buffer_size)
-+ wc->voc_ptr[y] = 0;
-+#endif
-+ }
-+#endif
-+ }
-+
-+ if(cidbeforering)
-+ {
-+ for(x=0; x<wc->max_cards; x++)
-+ {
-+ if (wc->modtype[wc->chans[x]->chanpos - 1] == MOD_TYPE_FXO)
-+ if(wc->mod[wc->chans[x]->chanpos - 1].fxo.offhook == 0)
-+ {
-+ /*unsigned int *p_readchunk, *p_cid_history;
-+
-+ p_readchunk = (unsigned int*)wc->chans[x].readchunk;
-+ p_cid_history = (unsigned int*)(wc->cid_history_buf[x] + wc->cid_history_ptr[x]);*/
-+
-+ if(wc->cid_state[x] == CID_STATE_IDLE) /* we need copy data to the cid voice buffer */
-+ {
-+ memcpy(wc->cid_history_buf[x] + wc->cid_history_ptr[x], wc->chans[x]->readchunk, DAHDI_CHUNKSIZE);
-+ wc->cid_history_ptr[x] = (wc->cid_history_ptr[x] + DAHDI_CHUNKSIZE)%(cidbuflen * DAHDI_MAX_CHUNKSIZE);
-+ }
-+ else if (wc->cid_state[x] == CID_STATE_RING_ON)
-+ wc->cid_history_clone_cnt[x] = cidbuflen;
-+ else if (wc->cid_state[x] == CID_STATE_RING_OFF)
-+ {
-+ if(wc->cid_history_clone_cnt[x])
-+ {
-+ memcpy(wc->chans[x]->readchunk, wc->cid_history_buf[x] + wc->cid_history_ptr[x], DAHDI_MAX_CHUNKSIZE);
-+ wc->cid_history_clone_cnt[x]--;
-+ wc->cid_history_ptr[x] = (wc->cid_history_ptr[x] + DAHDI_MAX_CHUNKSIZE)%(cidbuflen * DAHDI_MAX_CHUNKSIZE);
-+ }
-+ else
-+ {
-+ wc->cid_state[x] = CID_STATE_WAIT_RING_FINISH;
-+ wc->cid_history_clone_cnt[x] = cidtimeout; /* wait 6 sec, if no ring, return to idle */
-+ }
-+ }
-+ else if(wc->cid_state[x] == CID_STATE_WAIT_RING_FINISH)
-+ {
-+ if(wc->cid_history_clone_cnt[x] > 0)
-+ wc->cid_history_clone_cnt[x]--;
-+ else
-+ {
-+ wc->cid_state[x] = CID_STATE_IDLE;
-+ wc->cid_history_ptr[x] = 0;
-+ wc->cid_history_clone_cnt[x] = 0;
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+#ifdef AUDIO_RINGCHECK
-+ for (x=0;x<wc->max_cards;x++)
-+ ring_check(wc, x);
-+#endif
-+ /* XXX We're wasting 8 taps. We should get closer :( */
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) {
-+ if (wc->cardflag & (1 << x))
-+ dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk);
-+ }
-+ dahdi_receive(&wc->span);
-+}
-+
-+static void wctdm_stop_dma(struct wctdm *wc);
-+static void wctdm_reset_tdm(struct wctdm *wc);
-+static void wctdm_restart_dma(struct wctdm *wc);
-+
-+
-+static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg);
-+static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val);
-+
-+
-+static inline void __write_8bits(struct wctdm *wc, unsigned char bits)
-+{
-+ if(spibyhw == 0)
-+ {
-+ int x;
-+ /* Drop chip select */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ wc->ios &= ~BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ for (x=0;x<8;x++) {
-+ /* Send out each bit, MSB first, drop SCLK as we do so */
-+ if (bits & 0x80)
-+ wc->ios |= BIT_SDI;
-+ else
-+ wc->ios &= ~BIT_SDI;
-+ wc->ios &= ~BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Now raise SCLK high again and repeat */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ bits <<= 1;
-+ }
-+ /* Finally raise CS back high again */
-+ wc->ios |= BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ }
-+ else
-+ {
-+ __wctdm_setcreg(wc, WC_SPIDATA, bits);
-+ __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW | BIT_SPI_START);
-+ while ((__wctdm_getcreg(wc, WC_SPICTRL) & BIT_SPI_BUSY) != 0);
-+ __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW);
-+ }
-+}
-+
-+
-+static inline void __reset_spi(struct wctdm *wc)
-+{
-+ __wctdm_setcreg(wc, WC_SPICTRL, 0);
-+
-+ /* Drop chip select and clock once and raise and clock once */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ wc->ios &= ~BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ wc->ios |= BIT_SDI;
-+ wc->ios &= ~BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Now raise SCLK high again and repeat */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Finally raise CS back high again */
-+ wc->ios |= BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Clock again */
-+ wc->ios &= ~BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Now raise SCLK high again and repeat */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+
-+ __wctdm_setcreg(wc, WC_SPICTRL, spibyhw);
-+
-+}
-+
-+static inline unsigned char __read_8bits(struct wctdm *wc)
-+{
-+ unsigned char res=0, c;
-+ int x;
-+ if(spibyhw == 0)
-+ {
-+ wc->ios &= ~BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Drop chip select */
-+ wc->ios &= ~BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ for (x=0;x<8;x++) {
-+ res <<= 1;
-+ /* Get SCLK */
-+ wc->ios &= ~BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ /* Read back the value */
-+ c = inb(wc->ioaddr + WC_AUXR);
-+ if (c & BIT_SDO)
-+ res |= 1;
-+ /* Now raise SCLK high again */
-+ wc->ios |= BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ }
-+ /* Finally raise CS back high again */
-+ wc->ios |= BIT_CS;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ wc->ios &= ~BIT_SCLK;
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+ }
-+ else
-+ {
-+ __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW | BIT_SPI_START);
-+ while ((__wctdm_getcreg(wc, WC_SPICTRL) & BIT_SPI_BUSY) != 0);
-+ res = __wctdm_getcreg(wc, WC_SPIDATA);
-+ __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW);
-+ }
-+
-+ /* And return our result */
-+ return res;
-+}
-+
-+static void __wctdm_setcreg_mem(struct wctdm *wc, unsigned char reg, unsigned char val)
-+{
-+ unsigned int *p = (unsigned int*)(wc->mem32 + WC_REGBASE + ((reg & 0xf) << 2));
-+ *p = val;
-+}
-+
-+static unsigned char __wctdm_getcreg_mem(struct wctdm *wc, unsigned char reg)
-+{
-+ unsigned int *p = (unsigned int*)(wc->mem32 + WC_REGBASE + ((reg & 0xf) << 2));
-+ return (*p)&0x00ff;
-+}
-+
-+
-+static void __wctdm_setcreg(struct wctdm *wc, unsigned char reg, unsigned char val)
-+{
-+ if(usememio)
-+ __wctdm_setcreg_mem(wc, reg, val);
-+ else
-+ outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2));
-+}
-+
-+static unsigned char __wctdm_getcreg(struct wctdm *wc, unsigned char reg)
-+{
-+ if(usememio)
-+ return __wctdm_getcreg_mem(wc, reg);
-+ else
-+ return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2));
-+}
-+
-+static inline void __wctdm_setcard(struct wctdm *wc, int card)
-+{
-+ if (wc->curcard != card) {
-+ __wctdm_setcreg(wc, WC_CS, card);
-+ wc->curcard = card;
-+ //printk("Select card %d\n", card);
-+ }
-+}
-+
-+static void __wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value)
-+{
-+ __wctdm_setcard(wc, card);
-+ if (wc->modtype[card] == MOD_TYPE_FXO) {
-+ __write_8bits(wc, 0x20);
-+ __write_8bits(wc, reg & 0x7f);
-+ } else {
-+ __write_8bits(wc, reg & 0x7f);
-+ }
-+ __write_8bits(wc, value);
-+}
-+
-+static void wctdm_setreg(struct wctdm *wc, int card, unsigned char reg, unsigned char value)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&wc->lock, flags);
-+ __wctdm_setreg(wc, card, reg, value);
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+}
-+
-+static unsigned char __wctdm_getreg(struct wctdm *wc, int card, unsigned char reg)
-+{
-+ __wctdm_setcard(wc, card);
-+ if (wc->modtype[card] == MOD_TYPE_FXO) {
-+ __write_8bits(wc, 0x60);
-+ __write_8bits(wc, reg & 0x7f);
-+ } else {
-+ __write_8bits(wc, reg | 0x80);
-+ }
-+ return __read_8bits(wc);
-+}
-+
-+static inline void reset_spi(struct wctdm *wc, int card)
-+{
-+ unsigned long flags;
-+ spin_lock_irqsave(&wc->lock, flags);
-+ __wctdm_setcard(wc, card);
-+ __reset_spi(wc);
-+ __reset_spi(wc);
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+}
-+
-+static unsigned char wctdm_getreg(struct wctdm *wc, int card, unsigned char reg)
-+{
-+ unsigned long flags;
-+ unsigned char res;
-+ spin_lock_irqsave(&wc->lock, flags);
-+ res = __wctdm_getreg(wc, card, reg);
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return res;
-+}
-+
-+static int __wait_access(struct wctdm *wc, int card)
-+{
-+ unsigned char data = 0;
-+ long origjiffies;
-+ int count = 0;
-+
-+ #define MAX 6000 /* attempts */
-+
-+
-+ origjiffies = jiffies;
-+ /* Wait for indirect access */
-+ while (count++ < MAX)
-+ {
-+ data = __wctdm_getreg(wc, card, I_STATUS);
-+
-+ if (!data)
-+ return 0;
-+
-+ }
-+
-+ if(count > (MAX-1)) printk(KERN_NOTICE " ##### Loop error (%02x) #####\n", data);
-+
-+ return 0;
-+}
-+
-+static unsigned char translate_3215(unsigned char address)
-+{
-+ int x;
-+ for (x=0;x<sizeof(indirect_regs)/sizeof(indirect_regs[0]);x++) {
-+ if (indirect_regs[x].address == address) {
-+ address = indirect_regs[x].altaddr;
-+ break;
-+ }
-+ }
-+ return address;
-+}
-+
-+static int wctdm_proslic_setreg_indirect(struct wctdm *wc, int card, unsigned char address, unsigned short data)
-+{
-+ unsigned long flags;
-+ int res = -1;
-+ /* Translate 3215 addresses */
-+ if (wc->flags[card] & FLAG_3215) {
-+ address = translate_3215(address);
-+ if (address == 255)
-+ return 0;
-+ }
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if(!__wait_access(wc, card)) {
-+ __wctdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF));
-+ __wctdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8));
-+ __wctdm_setreg(wc, card, IAA,address);
-+ res = 0;
-+ };
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return res;
-+}
-+
-+static int wctdm_proslic_getreg_indirect(struct wctdm *wc, int card, unsigned char address)
-+{
-+ unsigned long flags;
-+ int res = -1;
-+ char *p=NULL;
-+ /* Translate 3215 addresses */
-+ if (wc->flags[card] & FLAG_3215) {
-+ address = translate_3215(address);
-+ if (address == 255)
-+ return 0;
-+ }
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (!__wait_access(wc, card)) {
-+ __wctdm_setreg(wc, card, IAA, address);
-+ if (!__wait_access(wc, card)) {
-+ unsigned char data1, data2;
-+ data1 = __wctdm_getreg(wc, card, IDA_LO);
-+ data2 = __wctdm_getreg(wc, card, IDA_HI);
-+ res = data1 | (data2 << 8);
-+ } else
-+ p = "Failed to wait inside\n";
-+ } else
-+ p = "failed to wait\n";
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ if (p)
-+ printk(KERN_NOTICE "%s", p);
-+ return res;
-+}
-+
-+static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card)
-+{
-+ unsigned char i;
-+
-+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
-+ {
-+ if(wctdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial))
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
-+{
-+ int passed = 1;
-+ unsigned short i, initial;
-+ int j;
-+
-+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++)
-+ {
-+ if((j = wctdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) {
-+ printk(KERN_NOTICE "Failed to read indirect register %d\n", i);
-+ return -1;
-+ }
-+ initial= indirect_regs[i].initial;
-+
-+ if ( j != initial && (!(wc->flags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255)))
-+ {
-+ printk(KERN_NOTICE "!!!!!!! %s iREG %X = %X should be %X\n",
-+ indirect_regs[i].name,indirect_regs[i].address,j,initial );
-+ passed = 0;
-+ }
-+ }
-+
-+ if (passed) {
-+ if (debug)
-+ printk(KERN_DEBUG "Init Indirect Registers completed successfully.\n");
-+ } else {
-+ printk(KERN_NOTICE " !!!!! Init Indirect Registers UNSUCCESSFULLY.\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
-+{
-+ int res;
-+ /* Check loopback */
-+ res = wc->reg1shadow[card];
-+
-+ if (!res && (res != wc->mod[card].fxs.lasttxhook)) // read real state from register By wx
-+ res=wctdm_getreg(wc, card, 64);
-+
-+ if (!res && (res != wc->mod[card].fxs.lasttxhook)) {
-+ res = wctdm_getreg(wc, card, 8);
-+ if (res) {
-+ printk(KERN_NOTICE "Ouch, part reset, quickly restoring reality (%d)\n", card);
-+ wctdm_init_proslic(wc, card, 1, 0, 1);
-+ } else {
-+ if (wc->mod[card].fxs.palarms++ < MAX_ALARMS) {
-+ printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1);
-+ if (wc->mod[card].fxs.lasttxhook == 4)
-+ wc->mod[card].fxs.lasttxhook = 1;
-+ wctdm_setreg(wc, card, 64, wc->mod[card].fxs.lasttxhook);
-+ } else {
-+ if (wc->mod[card].fxs.palarms == MAX_ALARMS)
-+ printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1);
-+ }
-+ }
-+ }
-+}
-+static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
-+{
-+#define MS_PER_CHECK_HOOK 16
-+
-+#ifndef AUDIO_RINGCHECK
-+ unsigned char res;
-+#endif
-+ signed char b;
-+ int errors = 0;
-+ struct fxo *fxo = &wc->mod[card].fxo;
-+
-+ /* Try to track issues that plague slot one FXO's */
-+ b = wc->reg0shadow[card];
-+ if ((b & 0x2) || !(b & 0x8)) {
-+ /* Not good -- don't look at anything else */
-+ if (debug)
-+ printk(KERN_DEBUG "Error (%02x) on card %d!\n", b, card + 1);
-+ errors++;
-+ }
-+ b &= 0x9b;
-+ if (fxo->offhook) {
-+ if (b != 0x9)
-+ wctdm_setreg(wc, card, 5, 0x9);
-+ } else {
-+ if (b != 0x8)
-+ wctdm_setreg(wc, card, 5, 0x8);
-+ }
-+ if (errors)
-+ return;
-+ if (!fxo->offhook) {
-+ if(fixedtimepolarity) {
-+ if ( wc->cid_state[card] == CID_STATE_RING_ON && wc->cid_ring_on_time[card]>0)
-+ {
-+ if(wc->cid_ring_on_time[card]>=fixedtimepolarity )
-+ {
-+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY);
-+ wc->cid_ring_on_time[card] = -1; /* the polarity already sent */
-+ }
-+ else
-+ wc->cid_ring_on_time[card] += 16;
-+ }
-+}
-+ if (fwringdetect) {
-+ res = wc->reg0shadow[card] & 0x60;
-+ if (fxo->ringdebounce) {
-+ --fxo->ringdebounce;
-+ if (res && (res != fxo->lastrdtx) &&
-+ (fxo->battery == BATTERY_PRESENT)) {
-+ if (!fxo->wasringing) {
-+ fxo->wasringing = 1;
-+ if (debug)
-+ printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ if(cidbeforering)
-+ {
-+ if(wc->cid_state[card] == CID_STATE_IDLE)
-+ {
-+ wc->cid_state[card] = CID_STATE_RING_ON;
-+ wc->cid_ring_on_time[card] = 16; /* check every 16ms */
-+ }
-+ else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING);
-+ }
-+ else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING);
-+ }
-+ fxo->lastrdtx = res;
-+ fxo->ringdebounce = 10;
-+ } else if (!res) {
-+ if ((fxo->ringdebounce == 0) && fxo->wasringing) {
-+ fxo->wasringing = 0;
-+ if (debug)
-+ printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ if(cidbeforering)
-+ {
-+ if(wc->cid_state[card] == CID_STATE_RING_ON)
-+ {
-+ if(fixedtimepolarity==0)
-+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY);
-+ wc->cid_state[card] = CID_STATE_RING_OFF;
-+ }
-+ else
-+ {
-+ if(wc->cid_state[card] == CID_STATE_WAIT_RING_FINISH)
-+ wc->cid_history_clone_cnt[card] = cidtimeout;
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ }
-+ }
-+ else
-+
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ }
-+ }
-+ } else if (res && (fxo->battery == BATTERY_PRESENT)) {
-+ fxo->lastrdtx = res;
-+ fxo->ringdebounce = 10;
-+ }
-+ } else {
-+ res = wc->reg0shadow[card];
-+ if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) {
-+ fxo->ringdebounce += (DAHDI_CHUNKSIZE * 16);
-+ if (fxo->ringdebounce >= DAHDI_CHUNKSIZE * ringdebounce) {
-+ if (!fxo->wasringing) {
-+ fxo->wasringing = 1;
-+ if(cidbeforering)
-+ {
-+ if(wc->cid_state[card] == CID_STATE_IDLE)
-+ {
-+ wc->cid_state[card] = CID_STATE_RING_ON;
-+ wc->cid_ring_on_time[card] = 16; /* check every 16ms */
-+ }
-+ else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING);
-+ }
-+ else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING);
-+ if (debug)
-+ printk(KERN_DEBUG "RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ }
-+ fxo->ringdebounce = DAHDI_CHUNKSIZE * ringdebounce;
-+ }
-+ } else {
-+ fxo->ringdebounce -= DAHDI_CHUNKSIZE * 4;
-+ if (fxo->ringdebounce <= 0) {
-+ if (fxo->wasringing) {
-+ fxo->wasringing = 0;
-+ if(cidbeforering)
-+ {
-+ if(wc->cid_state[card] == CID_STATE_RING_ON)
-+ {
-+ if(fixedtimepolarity==0)
-+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY);
-+ wc->cid_state[card] = CID_STATE_RING_OFF;
-+ }
-+ else
-+ {
-+ if(wc->cid_state[card] == CID_STATE_WAIT_RING_FINISH)
-+ wc->cid_history_clone_cnt[card] = cidtimeout;
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ }
-+ }
-+ else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ if (debug)
-+ printk(KERN_DEBUG "NO RING on %d/%d!\n", wc->span.spanno, card + 1);
-+ }
-+ fxo->ringdebounce = 0;
-+ }
-+ }
-+ }
-+ }
-+
-+ b = wc->reg1shadow[card];
-+ if (abs(b) < battthresh) {
-+ /* possible existing states:
-+ battery lost, no debounce timer
-+ battery lost, debounce timer (going to battery present)
-+ battery present or unknown, no debounce timer
-+ battery present or unknown, debounce timer (going to battery lost)
-+ */
-+
-+ if (fxo->battery == BATTERY_LOST) {
-+ if (fxo->battdebounce) {
-+ /* we were going to BATTERY_PRESENT, but battery was lost again,
-+ so clear the debounce timer */
-+ fxo->battdebounce = 0;
-+ }
-+ } else {
-+ if (fxo->battdebounce) {
-+ /* going to BATTERY_LOST, see if we are there yet */
-+ if (--fxo->battdebounce == 0) {
-+ fxo->battery = BATTERY_LOST;
-+ if (debug)
-+ printk(KERN_DEBUG "NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
-+#ifdef JAPAN
-+ if (!wc->ohdebounce && wc->offhook) {
-+ dahdi_hooksig(&wc->chans[card], DAHDI_RXSIG_ONHOOK);
-+ if (debug)
-+ printk(KERN_DEBUG "Signalled On Hook\n");
-+#ifdef ZERO_BATT_RING
-+ wc->onhook++;
-+#endif
-+ }
-+#else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK);
-+ /* set the alarm timer, taking into account that part of its time
-+ period has already passed while debouncing occurred */
-+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
-+#endif
-+ }
-+ } else {
-+ /* start the debounce timer to verify that battery has been lost */
-+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
-+ }
-+ }
-+ } else {
-+ /* possible existing states:
-+ battery lost or unknown, no debounce timer
-+ battery lost or unknown, debounce timer (going to battery present)
-+ battery present, no debounce timer
-+ battery present, debounce timer (going to battery lost)
-+ */
-+
-+ if (fxo->battery == BATTERY_PRESENT) {
-+ if (fxo->battdebounce) {
-+ /* we were going to BATTERY_LOST, but battery appeared again,
-+ so clear the debounce timer */
-+ fxo->battdebounce = 0;
-+ }
-+ } else {
-+ if (fxo->battdebounce) {
-+ /* going to BATTERY_PRESENT, see if we are there yet */
-+ if (--fxo->battdebounce == 0) {
-+ fxo->battery = BATTERY_PRESENT;
-+ if (debug)
-+ printk(KERN_DEBUG "BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
-+ (b < 0) ? "-" : "+");
-+#ifdef ZERO_BATT_RING
-+ if (wc->onhook) {
-+ wc->onhook = 0;
-+ dahdi_hooksig(&wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ if (debug)
-+ printk(KERN_DEBUG "Signalled Off Hook\n");
-+ }
-+#else
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+#endif
-+ /* set the alarm timer, taking into account that part of its time
-+ period has already passed while debouncing occurred */
-+ fxo->battalarm = (battalarm - battdebounce) / MS_PER_CHECK_HOOK;
-+ }
-+ } else {
-+ /* start the debounce timer to verify that battery has appeared */
-+ fxo->battdebounce = battdebounce / MS_PER_CHECK_HOOK;
-+ }
-+ }
-+ }
-+
-+ if (fxo->lastpol >= 0) {
-+ if (b < 0) {
-+ fxo->lastpol = -1;
-+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
-+ }
-+ }
-+ if (fxo->lastpol <= 0) {
-+ if (b > 0) {
-+ fxo->lastpol = 1;
-+ fxo->polaritydebounce = POLARITY_DEBOUNCE / MS_PER_CHECK_HOOK;
-+ }
-+ }
-+
-+ if (fxo->battalarm) {
-+ if (--fxo->battalarm == 0) {
-+ /* the alarm timer has expired, so update the battery alarm state
-+ for this channel */
-+ dahdi_alarm_channel(wc->chans[card], fxo->battery == BATTERY_LOST ? DAHDI_ALARM_RED : DAHDI_ALARM_NONE);
-+ }
-+ }
-+
-+ if (fxo->polaritydebounce) {
-+ if (--fxo->polaritydebounce == 0) {
-+ if (fxo->lastpol != fxo->polarity) {
-+ if (debug)
-+ printk(KERN_DEBUG "%lu Polarity reversed (%d -> %d)\n", jiffies,
-+ fxo->polarity,
-+ fxo->lastpol);
-+ if (fxo->polarity)
-+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY);
-+ fxo->polarity = fxo->lastpol;
-+ }
-+ }
-+ }
-+#undef MS_PER_CHECK_HOOK
-+}
-+
-+static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
-+{
-+ char res;
-+ int hook;
-+
-+ /* For some reason we have to debounce the
-+ hook detector. */
-+
-+ res = wc->reg0shadow[card];
-+ hook = (res & 1);
-+ if (hook != wc->mod[card].fxs.lastrxhook) {
-+ /* Reset the debounce (must be multiple of 4ms) */
-+ 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
-+ } else {
-+ if (wc->mod[card].fxs.debounce > 0) {
-+ wc->mod[card].fxs.debounce-= 16 * DAHDI_CHUNKSIZE;
-+#if 0
-+ printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, wc->mod[card].fxs.debounce);
-+#endif
-+ if (!wc->mod[card].fxs.debounce) {
-+#if 0
-+ printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook);
-+#endif
-+ wc->mod[card].fxs.debouncehook = hook;
-+ }
-+ if (!wc->mod[card].fxs.oldrxhook && wc->mod[card].fxs.debouncehook) {
-+ /* Off hook */
-+#if 1
-+ if (debug)
-+#endif
-+ printk(KERN_DEBUG "opvxa1200: Card %d Going off hook\n", card);
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK);
-+ if (robust)
-+ wctdm_init_proslic(wc, card, 1, 0, 1);
-+ wc->mod[card].fxs.oldrxhook = 1;
-+
-+ } else if (wc->mod[card].fxs.oldrxhook && !wc->mod[card].fxs.debouncehook) {
-+ /* On hook */
-+#if 1
-+ if (debug)
-+#endif
-+ printk(KERN_DEBUG "opvxa1200: Card %d Going on hook\n", card);
-+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK);
-+ wc->mod[card].fxs.oldrxhook = 0;
-+ }
-+ }
-+ }
-+ wc->mod[card].fxs.lastrxhook = hook;
-+}
-+
-+static irqreturn_t wctdm_interrupt(int irq, void *dev_id)
-+{
-+ struct wctdm *wc = dev_id;
-+ unsigned char ints;
-+ int x, y, z;
-+ int mode;
-+
-+ ints = inb(wc->ioaddr + WC_INTSTAT);
-+
-+ if (!ints)
-+ return IRQ_NONE;
-+
-+ outb(ints, wc->ioaddr + WC_INTSTAT);
-+
-+ if (ints & 0x10) {
-+ /* Stop DMA, wait for watchdog */
-+ printk(KERN_INFO "TDM PCI Master abort\n");
-+ wctdm_stop_dma(wc);
-+ return IRQ_RETVAL(1);
-+ }
-+
-+ if (ints & 0x20) {
-+ printk(KERN_INFO "PCI Target abort\n");
-+ return IRQ_RETVAL(1);
-+ }
-+
-+ for (x=0;x<wc->max_cards/*4*3*/;x++) {
-+ if (wc->cardflag & (1 << x) &&
-+ (wc->modtype[x] == MOD_TYPE_FXS)) {
-+ if (wc->mod[x].fxs.lasttxhook == 0x4) {
-+ /* RINGing, prepare for OHT */
-+ wc->mod[x].fxs.ohttimer = OHT_TIMER << 3;
-+ if (reversepolarity)
-+ wc->mod[x].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
-+ else
-+ wc->mod[x].fxs.idletxhookstate = 0x2;
-+ } else {
-+ if (wc->mod[x].fxs.ohttimer) {
-+ wc->mod[x].fxs.ohttimer-= DAHDI_CHUNKSIZE;
-+ if (!wc->mod[x].fxs.ohttimer) {
-+ if (reversepolarity)
-+ wc->mod[x].fxs.idletxhookstate = 0x5; /* Switch to active */
-+ else
-+ wc->mod[x].fxs.idletxhookstate = 0x1;
-+ if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) {
-+ /* Apply the change if appropriate */
-+ if (reversepolarity)
-+ wc->mod[x].fxs.lasttxhook = 0x5;
-+ else
-+ wc->mod[x].fxs.lasttxhook = 0x1;
-+ wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook);
-+ }
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ if (ints & 0x0f) {
-+ wc->intcount++;
-+ z = wc->intcount & 0x3;
-+ mode = wc->intcount & 0xc;
-+ for(y=0; y<wc->max_cards/4/*3*/; y++)
-+ {
-+ x = z + y*4;
-+ if (wc->cardflag & (1 << x ) )
-+ {
-+ switch(mode)
-+ {
-+ case 0:
-+ /* Rest */
-+ break;
-+ case 4:
-+ /* Read first shadow reg */
-+ if (wc->modtype[x] == MOD_TYPE_FXS)
-+ wc->reg0shadow[x] = wctdm_getreg(wc, x, 68);
-+ else if (wc->modtype[x] == MOD_TYPE_FXO)
-+ wc->reg0shadow[x] = wctdm_getreg(wc, x, 5);
-+ break;
-+ case 8:
-+ /* Read second shadow reg */
-+ if (wc->modtype[x] == MOD_TYPE_FXS)
-+ wc->reg1shadow[x] = wctdm_getreg(wc, x, 64);
-+ else if (wc->modtype[x] == MOD_TYPE_FXO)
-+ wc->reg1shadow[x] = wctdm_getreg(wc, x, 29);
-+ break;
-+ case 12:
-+ /* Perform processing */
-+ if (wc->modtype[x] == MOD_TYPE_FXS) {
-+ wctdm_proslic_check_hook(wc, x);
-+ if (!(wc->intcount & 0xf0))
-+ wctdm_proslic_recheck_sanity(wc, x);
-+ } else if (wc->modtype[x] == MOD_TYPE_FXO) {
-+ wctdm_voicedaa_check_hook(wc, x);
-+ }
-+ break;
-+ }
-+ }
-+ }
-+ if (!(wc->intcount % 10000)) {
-+ /* Accept an alarm once per 10 seconds */
-+ for (x=0;x<wc->max_cards/*4*3*/;x++)
-+ if (wc->modtype[x] == MOD_TYPE_FXS) {
-+ if (wc->mod[x].fxs.palarms)
-+ wc->mod[x].fxs.palarms--;
-+ }
-+ }
-+ wctdm_receiveprep(wc, ints);
-+ wctdm_transmitprep(wc, ints);
-+ }
-+
-+ return IRQ_RETVAL(1);
-+
-+}
-+
-+static int wctdm_voicedaa_insane(struct wctdm *wc, int card)
-+{
-+ int blah;
-+ blah = wctdm_getreg(wc, card, 2);
-+ if (blah != 0x3)
-+ return -2;
-+ blah = wctdm_getreg(wc, card, 11);
-+ if (debug)
-+ printk(KERN_DEBUG "VoiceDAA System: %02x\n", blah & 0xf);
-+ return 0;
-+}
-+
-+static int wctdm_proslic_insane(struct wctdm *wc, int card)
-+{
-+ int blah,insane_report;
-+ insane_report=0;
-+
-+ blah = wctdm_getreg(wc, card, 0);
-+ if (debug)
-+ printk(KERN_DEBUG "ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf));
-+
-+#if 0
-+ if ((blah & 0x30) >> 4) {
-+ printk(KERN_DEBUG "ProSLIC on module %d is not a 3210.\n", card);
-+ return -1;
-+ }
-+#endif
-+ if (((blah & 0xf) == 0) || ((blah & 0xf) == 0xf)) {
-+ /* SLIC not loaded */
-+ return -1;
-+ }
-+ if ((blah & 0xf) < 2) {
-+ printk(KERN_NOTICE "ProSLIC 3210 version %d is too old\n", blah & 0xf);
-+ return -1;
-+ }
-+ if (wctdm_getreg(wc, card, 1) & 0x80)
-+ /* ProSLIC 3215, not a 3210 */
-+ wc->flags[card] |= FLAG_3215;
-+
-+ blah = wctdm_getreg(wc, card, 8);
-+ if (blah != 0x2) {
-+ printk(KERN_NOTICE "ProSLIC on module %d insane (1) %d should be 2\n", card, blah);
-+ return -1;
-+ } else if ( insane_report)
-+ printk(KERN_NOTICE "ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah);
-+
-+ blah = wctdm_getreg(wc, card, 64);
-+ if (blah != 0x0) {
-+ printk(KERN_NOTICE "ProSLIC on module %d insane (2)\n", card);
-+ return -1;
-+ } else if ( insane_report)
-+ printk(KERN_NOTICE "ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah);
-+
-+ blah = wctdm_getreg(wc, card, 11);
-+ if (blah != 0x33) {
-+ printk(KERN_NOTICE "ProSLIC on module %d insane (3)\n", card);
-+ return -1;
-+ } else if ( insane_report)
-+ printk(KERN_NOTICE "ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah);
-+
-+ /* Just be sure it's setup right. */
-+ wctdm_setreg(wc, card, 30, 0);
-+
-+ if (debug)
-+ printk(KERN_DEBUG "ProSLIC on module %d seems sane.\n", card);
-+ return 0;
-+}
-+
-+static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card)
-+{
-+ unsigned long origjiffies;
-+ unsigned char vbat;
-+
-+ /* Turn off linefeed */
-+ wctdm_setreg(wc, card, 64, 0);
-+
-+ /* Power down */
-+ wctdm_setreg(wc, card, 14, 0x10);
-+
-+ /* Wait for one second */
-+ origjiffies = jiffies;
-+
-+ while((vbat = wctdm_getreg(wc, card, 82)) > 0x6) {
-+ if ((jiffies - origjiffies) >= (HZ/2))
-+ break;
-+ }
-+
-+ if (vbat < 0x06) {
-+ printk(KERN_NOTICE "Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", card,
-+ 376 * vbat / 1000, vbat, (int)((jiffies - origjiffies) * 1000 / HZ));
-+ return -1;
-+ } else if (debug) {
-+ printk(KERN_NOTICE "Post-leakage voltage: %d volts\n", 376 * vbat / 1000);
-+ }
-+ return 0;
-+}
-+
-+static int wctdm_powerup_proslic(struct wctdm *wc, int card, int fast)
-+{
-+ unsigned char vbat;
-+ unsigned long origjiffies;
-+ int lim;
-+
-+ /* Set period of DC-DC converter to 1/64 khz */
-+ wctdm_setreg(wc, card, 92, 0xff /* was 0xff */);
-+
-+ /* Wait for VBat to powerup */
-+ origjiffies = jiffies;
-+
-+ /* Disable powerdown */
-+ wctdm_setreg(wc, card, 14, 0);
-+
-+ /* If fast, don't bother checking anymore */
-+ if (fast)
-+ return 0;
-+
-+ while((vbat = wctdm_getreg(wc, card, 82)) < 0xc0) {
-+ /* Wait no more than 500ms */
-+ if ((jiffies - origjiffies) > HZ/2) {
-+ break;
-+ }
-+ }
-+
-+ if (vbat < 0xc0) {
-+ if (wc->proslic_power == PROSLIC_POWER_UNKNOWN)
-+ printk(KERN_NOTICE "ProSLIC on module %d failed to powerup within %d ms (%d mV only)\n\n -- DID YOU REMEMBER TO PLUG IN THE HD POWER CABLE TO THE A1200P??\n",
-+ card, (int)(((jiffies - origjiffies) * 1000 / HZ)),
-+ vbat * 375);
-+ wc->proslic_power = PROSLIC_POWER_WARNED;
-+ return -1;
-+ } else if (debug) {
-+ printk(KERN_DEBUG "ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
-+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
-+ }
-+ wc->proslic_power = PROSLIC_POWER_ON;
-+
-+ /* Proslic max allowed loop current, reg 71 LOOP_I_LIMIT */
-+ /* If out of range, just set it to the default value */
-+ lim = (loopcurrent - 20) / 3;
-+ if ( loopcurrent > 41 ) {
-+ lim = 0;
-+ if (debug)
-+ printk(KERN_DEBUG "Loop current out of range! Setting to default 20mA!\n");
-+ }
-+ else if (debug)
-+ printk(KERN_DEBUG "Loop current set to %dmA!\n",(lim*3)+20);
-+ wctdm_setreg(wc,card,LOOP_I_LIMIT,lim);
-+
-+ /* Engage DC-DC converter */
-+ wctdm_setreg(wc, card, 93, 0x19 /* was 0x19 */);
-+#if 0
-+ origjiffies = jiffies;
-+ while(0x80 & wctdm_getreg(wc, card, 93)) {
-+ if ((jiffies - origjiffies) > 2 * HZ) {
-+ printk(KERN_DEBUG "Timeout waiting for DC-DC calibration on module %d\n", card);
-+ return -1;
-+ }
-+ }
-+
-+#if 0
-+ /* Wait a full two seconds */
-+ while((jiffies - origjiffies) < 2 * HZ);
-+
-+ /* Just check to be sure */
-+ vbat = wctdm_getreg(wc, card, 82);
-+ printk(KERN_DEBUG "ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n",
-+ card, vbat * 376 / 1000, vbat, (int)(((jiffies - origjiffies) * 1000 / HZ)));
-+#endif
-+#endif
-+ return 0;
-+
-+}
-+
-+static int wctdm_proslic_manual_calibrate(struct wctdm *wc, int card){
-+ unsigned long origjiffies;
-+ unsigned char i;
-+
-+ wctdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21
-+ wctdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21
-+ wctdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21
-+ wctdm_setreg(wc, card, 64, 0);//(0)
-+
-+ wctdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration.
-+ wctdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM
-+
-+ origjiffies=jiffies;
-+ while( wctdm_getreg(wc,card,96)!=0 ){
-+ if((jiffies-origjiffies)>80)
-+ return -1;
-+ }
-+//Initialized DR 98 and 99 to get consistant results.
-+// 98 and 99 are the results registers and the search should have same intial conditions.
-+
-+/*******************************The following is the manual gain mismatch calibration****************************/
-+/*******************************This is also available as a function *******************************************/
-+ // Delay 10ms
-+ origjiffies=jiffies;
-+ while((jiffies-origjiffies)<1);
-+ wctdm_proslic_setreg_indirect(wc, card, 88,0);
-+ wctdm_proslic_setreg_indirect(wc,card,89,0);
-+ wctdm_proslic_setreg_indirect(wc,card,90,0);
-+ wctdm_proslic_setreg_indirect(wc,card,91,0);
-+ wctdm_proslic_setreg_indirect(wc,card,92,0);
-+ wctdm_proslic_setreg_indirect(wc,card,93,0);
-+
-+ wctdm_setreg(wc, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time
-+ wctdm_setreg(wc, card, 99,0x10);
-+
-+ for ( i=0x1f; i>0; i--)
-+ {
-+ wctdm_setreg(wc, card, 98,i);
-+ origjiffies=jiffies;
-+ while((jiffies-origjiffies)<4);
-+ if((wctdm_getreg(wc,card,88)) == 0)
-+ break;
-+ } // for
-+
-+ for ( i=0x1f; i>0; i--)
-+ {
-+ wctdm_setreg(wc, card, 99,i);
-+ origjiffies=jiffies;
-+ while((jiffies-origjiffies)<4);
-+ if((wctdm_getreg(wc,card,89)) == 0)
-+ break;
-+ }//for
-+
-+/*******************************The preceding is the manual gain mismatch calibration****************************/
-+/**********************************The following is the longitudinal Balance Cal***********************************/
-+ wctdm_setreg(wc,card,64,1);
-+ while((jiffies-origjiffies)<10); // Sleep 100?
-+
-+ wctdm_setreg(wc, card, 64, 0);
-+ wctdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal
-+ wctdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration
-+ wctdm_setreg(wc, card, 96,0x40);
-+
-+ wctdm_getreg(wc,card,96); /* Read Reg 96 just cause */
-+
-+ wctdm_setreg(wc, card, 21, 0xFF);
-+ wctdm_setreg(wc, card, 22, 0xFF);
-+ wctdm_setreg(wc, card, 23, 0xFF);
-+
-+ /**The preceding is the longitudinal Balance Cal***/
-+ return(0);
-+
-+}
-+#if 1
-+static int wctdm_proslic_calibrate(struct wctdm *wc, int card)
-+{
-+ unsigned long origjiffies;
-+ int x;
-+ /* Perform all calibrations */
-+ wctdm_setreg(wc, card, 97, 0x1f);
-+
-+ /* Begin, no speedup */
-+ wctdm_setreg(wc, card, 96, 0x5f);
-+
-+ /* Wait for it to finish */
-+ origjiffies = jiffies;
-+ while(wctdm_getreg(wc, card, 96)) {
-+ if ((jiffies - origjiffies) > 2 * HZ) {
-+ printk(KERN_NOTICE "Timeout waiting for calibration of module %d\n", card);
-+ return -1;
-+ }
-+ }
-+
-+ if (debug) {
-+ /* Print calibration parameters */
-+ printk(KERN_DEBUG "Calibration Vector Regs 98 - 107: \n");
-+ for (x=98;x<108;x++) {
-+ printk(KERN_DEBUG "%d: %02x\n", x, wctdm_getreg(wc, card, x));
-+ }
-+ }
-+ return 0;
-+}
-+#endif
-+
-+static void wait_just_a_bit(int foo)
-+{
-+ long newjiffies;
-+ newjiffies = jiffies + foo;
-+ while(jiffies < newjiffies);
-+}
-+
-+/*********************************************************************
-+ * Set the hwgain on the analog modules
-+ *
-+ * card = the card position for this module (0-23)
-+ * gain = gain in dB x10 (e.g. -3.5dB would be gain=-35)
-+ * tx = (0 for rx; 1 for tx)
-+ *
-+ *******************************************************************/
-+static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx)
-+{
-+ if (!(wc->modtype[card] == MOD_TYPE_FXO)) {
-+ printk(KERN_NOTICE "Cannot adjust gain. Unsupported module type!\n");
-+ return -1;
-+ }
-+ if (tx) {
-+ if (debug)
-+ printk(KERN_DEBUG "setting FXO tx gain for card=%d to %d\n", card, gain);
-+ if (gain >= -150 && gain <= 0) {
-+ wctdm_setreg(wc, card, 38, 16 + (gain/-10));
-+ wctdm_setreg(wc, card, 40, 16 + (-gain%10));
-+ } else if (gain <= 120 && gain > 0) {
-+ wctdm_setreg(wc, card, 38, gain/10);
-+ wctdm_setreg(wc, card, 40, (gain%10));
-+ } else {
-+ printk(KERN_INFO "FXO tx gain is out of range (%d)\n", gain);
-+ return -1;
-+ }
-+ } else { /* rx */
-+ if (debug)
-+ printk(KERN_DEBUG "setting FXO rx gain for card=%d to %d\n", card, gain);
-+ if (gain >= -150 && gain <= 0) {
-+ wctdm_setreg(wc, card, 39, 16+ (gain/-10));
-+ wctdm_setreg(wc, card, 41, 16 + (-gain%10));
-+ } else if (gain <= 120 && gain > 0) {
-+ wctdm_setreg(wc, card, 39, gain/10);
-+ wctdm_setreg(wc, card, 41, (gain%10));
-+ } else {
-+ printk(KERN_INFO "FXO rx gain is out of range (%d)\n", gain);
-+ return -1;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, int sane)
-+{
-+ unsigned char reg16=0, reg26=0, reg30=0, reg31=0;
-+ long newjiffies;
-+ wc->modtype[card] = MOD_TYPE_FXO;
-+ /* Sanity check the ProSLIC */
-+ reset_spi(wc, card);
-+ if (!sane && wctdm_voicedaa_insane(wc, card))
-+ return -2;
-+
-+ /* Software reset */
-+ wctdm_setreg(wc, card, 1, 0x80);
-+
-+ /* Wait just a bit */
-+ wait_just_a_bit(HZ/10);
-+
-+ /* Enable PCM, ulaw */
-+ if (alawoverride)
-+ wctdm_setreg(wc, card, 33, 0x20);
-+ else
-+ wctdm_setreg(wc, card, 33, 0x28);
-+
-+ /* Set On-hook speed, Ringer impedence, and ringer threshold */
-+ reg16 |= (fxo_modes[_opermode].ohs << 6);
-+ reg16 |= (fxo_modes[_opermode].rz << 1);
-+ reg16 |= (fxo_modes[_opermode].rt);
-+ wctdm_setreg(wc, card, 16, reg16);
-+
-+ if(fwringdetect) {
-+ /* Enable ring detector full-wave rectifier mode */
-+ wctdm_setreg(wc, card, 18, 2);
-+ wctdm_setreg(wc, card, 24, 0);
-+ } else {
-+ /* Set to the device defaults */
-+ wctdm_setreg(wc, card, 18, 0);
-+ wctdm_setreg(wc, card, 24, 0x19);
-+ }
-+
-+ /* Set DC Termination:
-+ Tip/Ring voltage adjust, minimum operational current, current limitation */
-+ reg26 |= (fxo_modes[_opermode].dcv << 6);
-+ reg26 |= (fxo_modes[_opermode].mini << 4);
-+ reg26 |= (fxo_modes[_opermode].ilim << 1);
-+ wctdm_setreg(wc, card, 26, reg26);
-+
-+ /* Set AC Impedence */
-+ reg30 = (fxofullscale==1) ? (fxo_modes[_opermode].acim|0x10) : (fxo_modes[_opermode].acim);
-+ wctdm_setreg(wc, card, 30, reg30);
-+
-+ /* Misc. DAA parameters */
-+ if (fastpickup)
-+ reg31 = 0xb3;
-+ else
-+ reg31 = 0xa3;
-+
-+ reg31 |= (fxo_modes[_opermode].ohs2 << 3);
-+ wctdm_setreg(wc, card, 31, reg31);
-+
-+ /* Set Transmit/Receive timeslot */
-+ //printk("set card %d to %d\n", card, (3-(card%4)) * 8 + (card/4) * 64);
-+ wctdm_setreg(wc, card, 34, (3-(card%4)) * 8 + (card/4) * 64);
-+ wctdm_setreg(wc, card, 35, 0x00);
-+ wctdm_setreg(wc, card, 36, (3-(card%4)) * 8 + (card/4) * 64);
-+ wctdm_setreg(wc, card, 37, 0x00);
-+
-+ /* Enable ISO-Cap */
-+ wctdm_setreg(wc, card, 6, 0x00);
-+
-+ if (fastpickup)
-+ wctdm_setreg(wc, card, 17, wctdm_getreg(wc, card, 17) | 0x20);
-+
-+ /* Wait 1000ms for ISO-cap to come up */
-+ newjiffies = jiffies;
-+ newjiffies += 2 * HZ;
-+ while((jiffies < newjiffies) && !(wctdm_getreg(wc, card, 11) & 0xf0))
-+ wait_just_a_bit(HZ/10);
-+
-+ if (!(wctdm_getreg(wc, card, 11) & 0xf0)) {
-+ printk(KERN_NOTICE "VoiceDAA did not bring up ISO link properly!\n");
-+ return -1;
-+ }
-+ if (debug)
-+ printk(KERN_DEBUG "ISO-Cap is now up, line side: %02x rev %02x\n",
-+ wctdm_getreg(wc, card, 11) >> 4,
-+ (wctdm_getreg(wc, card, 13) >> 2) & 0xf);
-+ /* Enable on-hook line monitor */
-+ wctdm_setreg(wc, card, 5, 0x08);
-+
-+ /* Take values for fxotxgain and fxorxgain and apply them to module */
-+ wctdm_set_hwgain(wc, card, fxotxgain, 1);
-+ wctdm_set_hwgain(wc, card, fxorxgain, 0);
-+
-+ /* NZ -- crank the tx gain up by 7 dB */
-+ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) {
-+ printk(KERN_INFO "Adjusting gain\n");
-+ wctdm_set_hwgain(wc, card, 7, 1);
-+ }
-+
-+ if(debug)
-+ printk(KERN_DEBUG "DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16)?-(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16)? -(wctdm_getreg(wc, card, 40) - 16):wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16)? -(wctdm_getreg(wc, card, 39) - 16) : wctdm_getreg(wc, card, 39),(wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16):wctdm_getreg(wc, card, 41));
-+
-+ return 0;
-+
-+}
-+
-+static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, int sane)
-+{
-+
-+ unsigned short tmp[5];
-+ unsigned char r19, r9;
-+ int x;
-+ int fxsmode=0;
-+
-+ /* Sanity check the ProSLIC */
-+ if (!sane && wctdm_proslic_insane(wc, card))
-+ return -2;
-+
-+ /* By default, don't send on hook */
-+ if (reversepolarity)
-+ wc->mod[card].fxs.idletxhookstate = 5;
-+ else
-+ wc->mod[card].fxs.idletxhookstate = 1;
-+
-+ if (sane) {
-+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */
-+ wctdm_setreg(wc, card, 14, 0x10);
-+ }
-+
-+ if (wctdm_proslic_init_indirect_regs(wc, card)) {
-+ printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card);
-+ return -1;
-+ }
-+
-+ /* Clear scratch pad area */
-+ wctdm_proslic_setreg_indirect(wc, card, 97,0);
-+
-+ /* Clear digital loopback */
-+ wctdm_setreg(wc, card, 8, 0);
-+
-+ /* Revision C optimization */
-+ wctdm_setreg(wc, card, 108, 0xeb);
-+
-+ /* Disable automatic VBat switching for safety to prevent
-+ Q7 from accidently turning on and burning out. */
-+ wctdm_setreg(wc, card, 67, 0x07); /* Note, if pulse dialing has problems at high REN loads
-+ change this to 0x17 */
-+
-+ /* Turn off Q7 */
-+ wctdm_setreg(wc, card, 66, 1);
-+
-+ /* Flush ProSLIC digital filters by setting to clear, while
-+ saving old values */
-+ for (x=0;x<5;x++) {
-+ tmp[x] = wctdm_proslic_getreg_indirect(wc, card, x + 35);
-+ wctdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000);
-+ }
-+
-+ /* Power up the DC-DC converter */
-+ if (wctdm_powerup_proslic(wc, card, fast)) {
-+ printk(KERN_NOTICE "Unable to do INITIAL ProSLIC powerup on module %d\n", card);
-+ return -1;
-+ }
-+
-+ if (!fast) {
-+
-+ /* Check for power leaks */
-+ if (wctdm_proslic_powerleak_test(wc, card)) {
-+ printk(KERN_NOTICE "ProSLIC module %d failed leakage test. Check for short circuit\n", card);
-+ }
-+ /* Power up again */
-+ if (wctdm_powerup_proslic(wc, card, fast)) {
-+ printk(KERN_NOTICE "Unable to do FINAL ProSLIC powerup on module %d\n", card);
-+ return -1;
-+ }
-+#ifndef NO_CALIBRATION
-+ /* Perform calibration */
-+ if(manual) {
-+ if (wctdm_proslic_manual_calibrate(wc, card)) {
-+ //printk(KERN_NOTICE "Proslic failed on Manual Calibration\n");
-+ if (wctdm_proslic_manual_calibrate(wc, card)) {
-+ printk(KERN_NOTICE "Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n");
-+ return -1;
-+ }
-+ printk(KERN_NOTICE "Proslic Passed Manual Calibration on Second Attempt\n");
-+ }
-+ }
-+ else {
-+ if(wctdm_proslic_calibrate(wc, card)) {
-+ //printk(KERN_NOTICE "ProSlic died on Auto Calibration.\n");
-+ if (wctdm_proslic_calibrate(wc, card)) {
-+ printk(KERN_NOTICE "Proslic Failed on Second Attempt to Auto Calibrate\n");
-+ return -1;
-+ }
-+ printk(KERN_NOTICE "Proslic Passed Auto Calibration on Second Attempt\n");
-+ }
-+ }
-+ /* Perform DC-DC calibration */
-+ wctdm_setreg(wc, card, 93, 0x99);
-+ r19 = wctdm_getreg(wc, card, 107);
-+ if ((r19 < 0x2) || (r19 > 0xd)) {
-+ printk(KERN_NOTICE "DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19);
-+ wctdm_setreg(wc, card, 107, 0x8);
-+ }
-+
-+ /* Save calibration vectors */
-+ for (x=0;x<NUM_CAL_REGS;x++)
-+ wc->mod[card].fxs.calregs.vals[x] = wctdm_getreg(wc, card, 96 + x);
-+#endif
-+
-+ } else {
-+ /* Restore calibration registers */
-+ for (x=0;x<NUM_CAL_REGS;x++)
-+ wctdm_setreg(wc, card, 96 + x, wc->mod[card].fxs.calregs.vals[x]);
-+ }
-+ /* Calibration complete, restore original values */
-+ for (x=0;x<5;x++) {
-+ wctdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]);
-+ }
-+
-+ if (wctdm_proslic_verify_indirect_regs(wc, card)) {
-+ printk(KERN_INFO "Indirect Registers failed verification.\n");
-+ return -1;
-+ }
-+
-+
-+#if 0
-+ /* Disable Auto Power Alarm Detect and other "features" */
-+ wctdm_setreg(wc, card, 67, 0x0e);
-+ blah = wctdm_getreg(wc, card, 67);
-+#endif
-+
-+#if 0
-+ if (wctdm_proslic_setreg_indirect(wc, card, 97, 0x0)) { // Stanley: for the bad recording fix
-+ printk(KERN_INFO "ProSlic IndirectReg Died.\n");
-+ return -1;
-+ }
-+#endif
-+
-+ if (alawoverride)
-+ wctdm_setreg(wc, card, 1, 0x20);
-+ else
-+ wctdm_setreg(wc, card, 1, 0x28);
-+ // U-Law 8-bit interface
-+ wctdm_setreg(wc, card, 2, (3-(card%4)) * 8 + (card/4) * 64); // Tx Start count low byte 0
-+ wctdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0
-+ wctdm_setreg(wc, card, 4, (3-(card%4)) * 8 + (card/4) * 64); // Rx Start count low byte 0
-+ wctdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0
-+ wctdm_setreg(wc, card, 18, 0xff); // clear all interrupt
-+ wctdm_setreg(wc, card, 19, 0xff);
-+ wctdm_setreg(wc, card, 20, 0xff);
-+ wctdm_setreg(wc, card, 73, 0x04);
-+ if (fxshonormode) {
-+ fxsmode = acim2tiss[fxo_modes[_opermode].acim];
-+ wctdm_setreg(wc, card, 10, 0x08 | fxsmode);
-+ if (fxo_modes[_opermode].ring_osc)
-+ wctdm_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc);
-+ if (fxo_modes[_opermode].ring_x)
-+ wctdm_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x);
-+ }
-+ if (lowpower)
-+ wctdm_setreg(wc, card, 72, 0x10);
-+
-+#if 0
-+ wctdm_setreg(wc, card, 21, 0x00); // enable interrupt
-+ wctdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt
-+ wctdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt
-+#endif
-+
-+#if 0
-+ /* Enable loopback */
-+ wctdm_setreg(wc, card, 8, 0x2);
-+ wctdm_setreg(wc, card, 14, 0x0);
-+ wctdm_setreg(wc, card, 64, 0x0);
-+ wctdm_setreg(wc, card, 1, 0x08);
-+#endif
-+
-+ if (fastringer) {
-+ /* Speed up Ringer */
-+ wctdm_proslic_setreg_indirect(wc, card, 20, 0x7e6d);
-+ wctdm_proslic_setreg_indirect(wc, card, 21, 0x01b9);
-+ /* Beef up Ringing voltage to 89V */
-+ if (boostringer) {
-+ wctdm_setreg(wc, card, 74, 0x3f);
-+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x247))
-+ return -1;
-+ printk(KERN_INFO "Boosting fast ringer on slot %d (89V peak)\n", card + 1);
-+ } else if (lowpower) {
-+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x14b))
-+ return -1;
-+ printk(KERN_INFO "Reducing fast ring power on slot %d (50V peak)\n", card + 1);
-+ } else
-+ printk(KERN_INFO "Speeding up ringer on slot %d (25Hz)\n", card + 1);
-+ } else {
-+ /* Beef up Ringing voltage to 89V */
-+ if (boostringer) {
-+ wctdm_setreg(wc, card, 74, 0x3f);
-+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x1d1))
-+ return -1;
-+ printk(KERN_INFO "Boosting ringer on slot %d (89V peak)\n", card + 1);
-+ } else if (lowpower) {
-+ if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x108))
-+ return -1;
-+ printk(KERN_INFO "Reducing ring power on slot %d (50V peak)\n", card + 1);
-+ }
-+ }
-+
-+ if(fxstxgain || fxsrxgain) {
-+ r9 = wctdm_getreg(wc, card, 9);
-+ switch (fxstxgain) {
-+
-+ case 35:
-+ r9+=8;
-+ break;
-+ case -35:
-+ r9+=4;
-+ break;
-+ case 0:
-+ break;
-+ }
-+
-+ switch (fxsrxgain) {
-+
-+ case 35:
-+ r9+=2;
-+ break;
-+ case -35:
-+ r9+=1;
-+ break;
-+ case 0:
-+ break;
-+ }
-+ wctdm_setreg(wc,card,9,r9);
-+ }
-+
-+ if(debug)
-+ printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
-+
-+ wctdm_setreg(wc, card, 64, 0x01);
-+ return 0;
-+}
-+
-+
-+static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data)
-+{
-+ struct wctdm_stats stats;
-+ struct wctdm_regs regs;
-+ struct wctdm_regop regop;
-+ struct wctdm_echo_coefs echoregs;
-+ struct dahdi_hwgain hwgain;
-+ struct wctdm *wc = chan->pvt;
-+ int x;
-+ switch (cmd) {
-+ case DAHDI_ONHOOKTRANSFER:
-+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
-+ return -EINVAL;
-+ if (get_user(x, (__user int *)data))
-+ return -EFAULT;
-+ wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3;
-+ if (reversepolarity)
-+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
-+ else
-+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x2;
-+ if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) {
-+ /* Apply the change if appropriate */
-+ if (reversepolarity)
-+ wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6;
-+ else
-+ wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2;
-+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
-+ }
-+ break;
-+ case DAHDI_SETPOLARITY:
-+ if (get_user(x, (__user int *)data))
-+ return -EFAULT;
-+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
-+ return -EINVAL;
-+ /* Can't change polarity while ringing or when open */
-+ if ((wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) ||
-+ (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00))
-+ return -EINVAL;
-+
-+ if ((x && !reversepolarity) || (!x && reversepolarity))
-+ wc->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04;
-+ else
-+ wc->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04;
-+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook);
-+ break;
-+ case WCTDM_GET_STATS:
-+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
-+ stats.tipvolt = wctdm_getreg(wc, chan->chanpos - 1, 80) * -376;
-+ stats.ringvolt = wctdm_getreg(wc, chan->chanpos - 1, 81) * -376;
-+ stats.batvolt = wctdm_getreg(wc, chan->chanpos - 1, 82) * -376;
-+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
-+ stats.tipvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
-+ stats.ringvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
-+ stats.batvolt = (signed char)wctdm_getreg(wc, chan->chanpos - 1, 29) * 1000;
-+ } else
-+ return -EINVAL;
-+ if (copy_to_user((__user void *)data, &stats, sizeof(stats)))
-+ return -EFAULT;
-+ break;
-+ case WCTDM_GET_REGS:
-+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
-+ for (x=0;x<NUM_INDIRECT_REGS;x++)
-+ regs.indirect[x] = wctdm_proslic_getreg_indirect(wc, chan->chanpos -1, x);
-+ for (x=0;x<NUM_REGS;x++)
-+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
-+ } else {
-+ memset(&regs, 0, sizeof(regs));
-+ for (x=0;x<NUM_FXO_REGS;x++)
-+ regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
-+ }
-+ if (copy_to_user((__user void *)data, &regs, sizeof(regs)))
-+ return -EFAULT;
-+ break;
-+ case WCTDM_SET_REG:
-+ if (copy_from_user(&regop, (__user void *)data, sizeof(regop)))
-+ return -EFAULT;
-+ if (regop.indirect) {
-+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS)
-+ return -EINVAL;
-+ printk(KERN_INFO "Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos);
-+ wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val);
-+ } else {
-+ regop.val &= 0xff;
-+ printk(KERN_INFO "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos);
-+ wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val);
-+ }
-+ break;
-+ case WCTDM_SET_ECHOTUNE:
-+ printk(KERN_INFO "-- Setting echo registers: \n");
-+ if (copy_from_user(&echoregs, (__user void *)data, sizeof(echoregs)))
-+ return -EFAULT;
-+
-+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
-+ /* Set the ACIM register */
-+ wctdm_setreg(wc, chan->chanpos - 1, 30, (fxofullscale==1) ? (echoregs.acim|0x10) : echoregs.acim);
-+
-+ /* Set the digital echo canceller registers */
-+ wctdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1);
-+ wctdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2);
-+ wctdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3);
-+ wctdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4);
-+ wctdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5);
-+ wctdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6);
-+ wctdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7);
-+ wctdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8);
-+
-+ printk(KERN_INFO "-- Set echo registers successfully\n");
-+
-+ break;
-+ } else {
-+ return -EINVAL;
-+
-+ }
-+ break;
-+ case DAHDI_SET_HWGAIN:
-+ if (copy_from_user(&hwgain, (__user void *) data, sizeof(hwgain)))
-+ return -EFAULT;
-+
-+ wctdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx);
-+
-+ if (debug)
-+ printk(KERN_DEBUG "Setting hwgain on channel %d to %d for %s direction\n",
-+ chan->chanpos-1, hwgain.newgain, hwgain.tx ? "tx" : "rx");
-+ break;
-+ default:
-+ return -ENOTTY;
-+ }
-+ return 0;
-+
-+}
-+
-+static int wctdm_open(struct dahdi_chan *chan)
-+{
-+ struct wctdm *wc = chan->pvt;
-+ if (!(wc->cardflag & (1 << (chan->chanpos - 1))))
-+ return -ENODEV;
-+ if (wc->dead)
-+ return -ENODEV;
-+ wc->usecount++;
-+
-+ /*MOD_INC_USE_COUNT; */
-+ try_module_get(THIS_MODULE);
-+ return 0;
-+}
-+
-+static inline struct wctdm *wctdm_from_span(struct dahdi_span *span)
-+{
-+ return container_of(span, struct wctdm, span);
-+}
-+
-+static int wctdm_watchdog(struct dahdi_span *span, int event)
-+{
-+ printk(KERN_INFO "opvxa1200: Restarting DMA\n");
-+ wctdm_restart_dma(wctdm_from_span(span));
-+ return 0;
-+}
-+
-+static int wctdm_close(struct dahdi_chan *chan)
-+{
-+ struct wctdm *wc = chan->pvt;
-+ wc->usecount--;
-+
-+ /*MOD_DEC_USE_COUNT;*/
-+ module_put(THIS_MODULE);
-+
-+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) {
-+ if (reversepolarity)
-+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 5;
-+ else
-+ wc->mod[chan->chanpos - 1].fxs.idletxhookstate = 1;
-+ }
-+ /* If we're dead, release us now */
-+ if (!wc->usecount && wc->dead)
-+ wctdm_release(wc);
-+ return 0;
-+}
-+
-+static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
-+{
-+ struct wctdm *wc = chan->pvt;
-+ int reg=0;
-+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
-+ /* XXX Enable hooksig for FXO XXX */
-+ switch(txsig) {
-+ case DAHDI_TXSIG_START:
-+ case DAHDI_TXSIG_OFFHOOK:
-+ wc->mod[chan->chanpos - 1].fxo.offhook = 1;
-+ wctdm_setreg(wc, chan->chanpos - 1, 5, 0x9);
-+ if(cidbeforering)
-+ {
-+ wc->cid_state[chan->chanpos - 1] = CID_STATE_IDLE;
-+ wc->cid_history_clone_cnt[chan->chanpos - 1] = 0;
-+ wc->cid_history_ptr[chan->chanpos - 1] = 0;
-+ memset(wc->cid_history_buf[chan->chanpos - 1], DAHDI_LIN2X(0, chan), cidbuflen * DAHDI_MAX_CHUNKSIZE);
-+ }
-+ break;
-+ case DAHDI_TXSIG_ONHOOK:
-+ wc->mod[chan->chanpos - 1].fxo.offhook = 0;
-+ wctdm_setreg(wc, chan->chanpos - 1, 5, 0x8);
-+ break;
-+ default:
-+ printk(KERN_NOTICE "wcfxo: Can't set tx state to %d\n", txsig);
-+ }
-+ } else {
-+ switch(txsig) {
-+ case DAHDI_TXSIG_ONHOOK:
-+ switch(chan->sig) {
-+ case DAHDI_SIG_EM:
-+ case DAHDI_SIG_FXOKS:
-+ case DAHDI_SIG_FXOLS:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
-+ break;
-+ case DAHDI_SIG_FXOGS:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 3;
-+ break;
-+ }
-+ break;
-+ case DAHDI_TXSIG_OFFHOOK:
-+ switch(chan->sig) {
-+ case DAHDI_SIG_EM:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 5;
-+ break;
-+ default:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate;
-+ break;
-+ }
-+ break;
-+ case DAHDI_TXSIG_START:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 4;
-+ break;
-+ case DAHDI_TXSIG_KEWL:
-+ wc->mod[chan->chanpos-1].fxs.lasttxhook = 0;
-+ break;
-+ default:
-+ printk(KERN_NOTICE "opvxa1200: Can't set tx state to %d\n", txsig);
-+ }
-+ if (debug)
-+ printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, reg);
-+
-+#if 1
-+ wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook);
-+#endif
-+ }
-+ 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,
-+};
-+#endif
-+
-+static int wctdm_initialize(struct wctdm *wc)
-+{
-+ int x;
-+
-+ /* Dahdi stuff */
-+ sprintf(wc->span.name, "OPVXA1200/%d", wc->pos);
-+ snprintf(wc->span.desc, sizeof(wc->span.desc)-1, "%s Board %d", wc->variety, wc->pos + 1);
-+ wc->ddev->location = kasprintf(GFP_KERNEL,
-+ "PCI Bus %02d Slot %02d",
-+ wc->dev->bus->number,
-+ PCI_SLOT(wc->dev->devfn) + 1);
-+ if (!wc->ddev->location) {
-+ dahdi_free_device(wc->ddev);
-+ wc->ddev = NULL;
-+ return -ENOMEM;
-+ }
-+ wc->ddev->manufacturer = "OpenVox";
-+ wc->ddev->devicetype = wc->variety;
-+ if (alawoverride) {
-+ printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n");
-+ wc->span.deflaw = DAHDI_LAW_ALAW;
-+ } else
-+ wc->span.deflaw = DAHDI_LAW_MULAW;
-+
-+ x = __wctdm_getcreg(wc, WC_VER);
-+ wc->fwversion = x;
-+ if( x & FLAG_A800)
-+ {
-+ wc->card_name = A800P_Name;
-+ wc->max_cards = 8;
-+ }
-+ else
-+ {
-+ wc->card_name = A1200P_Name;
-+ wc->max_cards = 12;
-+ }
-+
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) {
-+ sprintf(wc->chans[x]->name, "OPVXA1200/%d/%d", wc->pos, x);
-+ wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR;
-+ wc->chans[x]->sigcap |= DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR;
-+ 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.flags = DAHDI_FLAG_RBS;
-+ wc->span.ops = &wctdm_span_ops;
-+
-+ list_add_tail(&wc->span.device_node, &wc->ddev->spans);
-+ if (dahdi_register_device(wc->ddev, &wc->dev->dev)) {
-+ printk(KERN_NOTICE "Unable to register device %s with DAHDI\n",
-+ wc->span.name);
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+ wc->ddev = NULL;
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static void wctdm_post_initialize(struct wctdm *wc)
-+{
-+ int x;
-+
-+ /* Finalize signalling */
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) {
-+ if (wc->cardflag & (1 << x)) {
-+ if (wc->modtype[x] == MOD_TYPE_FXO)
-+ wc->chans[x]->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF | DAHDI_SIG_CLEAR;
-+ else
-+ wc->chans[x]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM | DAHDI_SIG_CLEAR;
-+ } else if (!(wc->chans[x]->sigcap & DAHDI_SIG_BROKEN)) {
-+ wc->chans[x]->sigcap = 0;
-+ }
-+ }
-+}
-+
-+static int wctdm_hardware_init(struct wctdm *wc)
-+{
-+ /* Hardware stuff */
-+ unsigned char ver;
-+ unsigned char x,y;
-+ int failed;
-+ long origjiffies; //ml.
-+
-+ /* Signal Reset */
-+ printk("before raise reset\n");
-+ outb(0x01, wc->ioaddr + WC_CNTL);
-+
-+ /* Wait for 5 second */
-+
-+ origjiffies = jiffies;
-+
-+ while(1)
-+ {
-+ if ((jiffies - origjiffies) >= (HZ*5))
-+ break;;
-+ }
-+
-+ /* printk(KERN_INFO "after raise reset\n");*/
-+
-+ /* Check OpenVox chip */
-+ x=inb(wc->ioaddr + WC_CNTL);
-+ ver = __wctdm_getcreg(wc, WC_VER);
-+ wc->fwversion = ver;
-+ /*if( ver & FLAG_A800)
-+ {
-+ wc->card_name = A800P_Name;
-+ wc->max_cards = 8;
-+ }
-+ else
-+ {
-+ wc->card_name = A1200P_Name;
-+ wc->max_cards = 12;
-+ }*/
-+ printk(KERN_NOTICE "OpenVox %s version: %01x.%01x\n", wc->card_name, (ver&(~FLAG_A800))>>4, ver&0x0f);
-+
-+ failed = 0;
-+ if (ver != 0x00) {
-+ for (x=0;x<16;x++) {
-+ /* Test registers */
-+ __wctdm_setcreg(wc, WC_CS, x);
-+ y = __wctdm_getcreg(wc, WC_CS) & 0x0f;
-+ if (x != y) {
-+ printk(KERN_INFO "%02x != %02x\n", x, y);
-+ failed++;
-+ }
-+ }
-+
-+ if (!failed) {
-+ printk(KERN_INFO "OpenVox %s passed register test\n", wc->card_name);
-+ } else {
-+ printk(KERN_NOTICE "OpenVox %s failed register test\n", wc->card_name);
-+ return -1;
-+ }
-+ } else {
-+ printk(KERN_INFO "No OpenVox chip %02x\n", ver);
-+ }
-+
-+ if (spibyhw)
-+ __wctdm_setcreg(wc, WC_SPICTRL, BIT_SPI_BYHW); // spi controled by hw MiaoLin;
-+ else
-+ __wctdm_setcreg(wc, WC_SPICTRL, 0);
-+
-+ /* Reset PCI Interface chip and registers (and serial) */
-+ outb(0x06, wc->ioaddr + WC_CNTL);
-+ /* Setup our proper outputs for when we switch for our "serial" port */
-+ wc->ios = BIT_CS | BIT_SCLK | BIT_SDI;
-+
-+ outb(wc->ios, wc->ioaddr + WC_AUXD);
-+
-+ /* Set all to outputs except AUX 5, which is an input */
-+ outb(0xdf, wc->ioaddr + WC_AUXC);
-+
-+ /* Select alternate function for AUX0 */ /* Useless in OpenVox by MiaoLin. */
-+ /* outb(0x4, wc->ioaddr + WC_AUXFUNC); */
-+
-+ /* Wait 1/4 of a sec */
-+ wait_just_a_bit(HZ/4);
-+
-+ /* Back to normal, with automatic DMA wrap around */
-+ outb(0x30 | 0x01, wc->ioaddr + WC_CNTL);
-+ wc->ledstate = 0;
-+ wctdm_set_led(wc, 0, 0);
-+
-+ /* Make sure serial port and DMA are out of reset */
-+ outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL);
-+
-+ /* Configure serial port for MSB->LSB operation */
-+ outb(0xc1, wc->ioaddr + WC_SERCTL);
-+
-+ /* Delay FSC by 0 so it's properly aligned */
-+ outb(0x01, wc->ioaddr + WC_FSCDELAY); /* Modify to 1 by MiaoLin */
-+
-+ /* Setup DMA Addresses */
-+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */
-+ outl(wc->writedma + DAHDI_CHUNKSIZE * 4 * 4 - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */
-+ outl(wc->writedma + DAHDI_CHUNKSIZE * 8 * 4 - 4, wc->ioaddr + WC_DMAWE); /* End */
-+
-+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */
-+ outl(wc->readdma + DAHDI_CHUNKSIZE * 4 * 4 - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */
-+ outl(wc->readdma + DAHDI_CHUNKSIZE * 8 * 4 - 4, wc->ioaddr + WC_DMARE); /* End */
-+
-+ /* Clear interrupts */
-+ outb(0xff, wc->ioaddr + WC_INTSTAT);
-+
-+ /* Wait 1/4 of a second more */
-+ wait_just_a_bit(HZ/4);
-+
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) {
-+ int sane=0,ret=0,readi=0;
-+#if 1
-+ touch_softlockup_watchdog(); // avoid showing CPU softlock message
-+ /* Init with Auto Calibration */
-+ if (!(ret=wctdm_init_proslic(wc, x, 0, 0, sane))) {
-+ wc->cardflag |= (1 << x);
-+ if (debug) {
-+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
-+ printk("Proslic module %d loop current is %dmA\n",x,
-+ ((readi*3)+20));
-+ }
-+ printk(KERN_INFO "Module %d: Installed -- AUTO FXS/DPO\n",x);
-+ wctdm_set_led(wc, (unsigned int)x, 1);
-+ } else {
-+ if(ret!=-2) {
-+ sane=1;
-+
-+ printk(KERN_INFO "Init ProSlic with Manual Calibration \n");
-+ /* Init with Manual Calibration */
-+ if (!wctdm_init_proslic(wc, x, 0, 1, sane)) {
-+ wc->cardflag |= (1 << x);
-+ if (debug) {
-+ readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
-+ printk("Proslic module %d loop current is %dmA\n",x,
-+ ((readi*3)+20));
-+ }
-+ printk(KERN_INFO "Module %d: Installed -- MANUAL FXS\n",x);
-+ } else {
-+ printk(KERN_NOTICE "Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC");
-+ wc->chans[x]->sigcap = __DAHDI_SIG_FXO | DAHDI_SIG_BROKEN;
-+ }
-+ } else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) {
-+ wc->cardflag |= (1 << x);
-+ printk(KERN_INFO "Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name);
-+ wctdm_set_led(wc, (unsigned int)x, 1);
-+ } else
-+ printk(KERN_NOTICE "Module %d: Not installed\n", x);
-+ }
-+#endif
-+ }
-+
-+ /* Return error if nothing initialized okay. */
-+ if (!wc->cardflag && !timingonly)
-+ return -1;
-+ /*__wctdm_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1); */ /* removed by MiaoLin */
-+ return 0;
-+}
-+
-+static void wctdm_enable_interrupts(struct wctdm *wc)
-+{
-+ /* Clear interrupts */
-+ outb(0xff, wc->ioaddr + WC_INTSTAT);
-+
-+ /* Enable interrupts (we care about all of them) */
-+ outb(0x3c, wc->ioaddr + WC_MASK0);
-+ /* No external interrupts */
-+ outb(0x00, wc->ioaddr + WC_MASK1);
-+}
-+
-+static void wctdm_restart_dma(struct wctdm *wc)
-+{
-+ /* Reset Master and TDM */
-+ outb(0x01, wc->ioaddr + WC_CNTL);
-+ outb(0x01, wc->ioaddr + WC_OPER);
-+}
-+
-+static void wctdm_start_dma(struct wctdm *wc)
-+{
-+ /* Reset Master and TDM */
-+ outb(0x0f, wc->ioaddr + WC_CNTL);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ outb(0x01, wc->ioaddr + WC_CNTL);
-+ outb(0x01, wc->ioaddr + WC_OPER);
-+}
-+
-+static void wctdm_stop_dma(struct wctdm *wc)
-+{
-+ outb(0x00, wc->ioaddr + WC_OPER);
-+}
-+
-+static void wctdm_reset_tdm(struct wctdm *wc)
-+{
-+ /* Reset TDM */
-+ outb(0x0f, wc->ioaddr + WC_CNTL);
-+}
-+
-+static void wctdm_disable_interrupts(struct wctdm *wc)
-+{
-+ outb(0x00, wc->ioaddr + WC_MASK0);
-+ outb(0x00, wc->ioaddr + WC_MASK1);
-+}
-+
-+static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-+{
-+ int res;
-+ struct wctdm *wc;
-+ struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data;
-+ int x;
-+ int y;
-+
-+ static int initd_ifaces=0;
-+
-+ if(initd_ifaces){
-+ memset((void *)ifaces,0,(sizeof(struct wctdm *))*WC_MAX_IFACES);
-+ initd_ifaces=1;
-+ }
-+ for (x=0;x<WC_MAX_IFACES;x++)
-+ if (!ifaces[x]) break;
-+ if (x >= WC_MAX_IFACES) {
-+ printk(KERN_NOTICE "Too many interfaces\n");
-+ return -EIO;
-+ }
-+
-+ if (pci_enable_device(pdev)) {
-+ res = -EIO;
-+ } else {
-+ wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL);
-+ if (wc) {
-+ int cardcount = 0;
-+
-+ wc->lastchan = -1; /* first channel offset = -1; */
-+ wc->ledstate = 0;
-+
-+ ifaces[x] = wc;
-+ memset(wc, 0, sizeof(struct wctdm));
-+ for (x=0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); ++x) {
-+ wc->chans[x] = &wc->_chans[x];
-+ }
-+
-+ spin_lock_init(&wc->lock);
-+ wc->curcard = -1;
-+ wc->ioaddr = pci_resource_start(pdev, 0);
-+ wc->mem_region = pci_resource_start(pdev, 1);
-+ wc->mem_len = pci_resource_len(pdev, 1);
-+ wc->mem32 = (unsigned long)ioremap(wc->mem_region, wc->mem_len);
-+ wc->dev = pdev;
-+ wc->pos = x;
-+ wc->variety = d->name;
-+ for (y=0;y<MAX_NUM_CARDS;y++)
-+ wc->flags[y] = d->flags;
-+ /* Keep track of whether we need to free the region */
-+ if (request_region(wc->ioaddr, 0xff, "opvxa1200"))
-+ wc->freeregion = 1;
-+ else
-+ wc->freeregion = 0;
-+
-+ if (request_mem_region(wc->mem_region, wc->mem_len, "opvxa1200"))
-+ wc->freeregion |= 0x02;
-+
-+ /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses
-+ 8 bits. */
-+ wc->writechunk = pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2 * 2, &wc->writedma);
-+ if (!wc->writechunk) {
-+ printk(KERN_NOTICE "opvxa1200: Unable to allocate DMA-able memory\n");
-+ if (wc->freeregion & 0x01)
-+ release_region(wc->ioaddr, 0xff);
-+ if (wc->freeregion & 0x02)
-+ {
-+ release_mem_region(wc->mem_region, wc->mem_len);
-+ iounmap((void *)wc->mem32);
-+ }
-+ return -ENOMEM;
-+ }
-+
-+ wc->readchunk = wc->writechunk + DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2; /* in bytes */
-+ wc->readdma = wc->writedma + DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2; /* in bytes */
-+
-+ if (wctdm_initialize(wc)) {
-+ printk(KERN_NOTICE "opvxa1200: Unable to intialize FXS\n");
-+ /* Set Reset Low */
-+ x=inb(wc->ioaddr + WC_CNTL);
-+ outb((~0x1)&x, wc->ioaddr + WC_CNTL);
-+ /* Free Resources */
-+ free_irq(pdev->irq, wc);
-+ if (wc->freeregion & 0x01)
-+ release_region(wc->ioaddr, 0xff);
-+ if (wc->freeregion & 0x02)
-+ {
-+ release_mem_region(wc->mem_region, wc->mem_len);
-+ iounmap((void *)wc->mem32);
-+ }
-+ }
-+
-+ /* Enable bus mastering */
-+ pci_set_master(pdev);
-+
-+ /* Keep track of which device we are */
-+ pci_set_drvdata(pdev, wc);
-+
-+
-+ if (request_irq(pdev->irq, wctdm_interrupt, IRQF_SHARED, "opvxa1200", wc)) {
-+ printk(KERN_NOTICE "opvxa1200: Unable to request IRQ %d\n", pdev->irq);
-+ if (wc->freeregion & 0x01)
-+ release_region(wc->ioaddr, 0xff);
-+ if (wc->freeregion & 0x02)
-+ {
-+ release_mem_region(wc->mem_region, wc->mem_len);
-+ iounmap((void *)wc->mem32);
-+ }
-+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma);
-+ pci_set_drvdata(pdev, NULL);
-+ kfree(wc);
-+ return -EIO;
-+ }
-+
-+ if (wctdm_hardware_init(wc)) {
-+ unsigned char w;
-+
-+ /* Set Reset Low */
-+ w=inb(wc->ioaddr + WC_CNTL);
-+ outb((~0x1)&w, wc->ioaddr + WC_CNTL);
-+ /* Free Resources */
-+ free_irq(pdev->irq, wc);
-+ if (wc->freeregion & 0x01)
-+ release_region(wc->ioaddr, 0xff);
-+ if (wc->freeregion & 0x02)
-+ {
-+ release_mem_region(wc->mem_region, wc->mem_len);
-+ iounmap((void *)wc->mem32);
-+ }
-+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma);
-+ pci_set_drvdata(pdev, NULL);
-+ dahdi_unregister_device(wc->ddev);
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+ kfree(wc);
-+ return -EIO;
-+
-+ }
-+
-+#ifdef TEST_LOG_INCOME_VOICE
-+ for(x=0; x<MAX_NUM_CARDS+NUM_FLAG; x++)
-+ {
-+ wc->voc_buf[x] = kmalloc(voc_buffer_size, GFP_KERNEL);
-+ wc->voc_ptr[x] = 0;
-+ }
-+#endif
-+
-+ if(cidbeforering)
-+ {
-+ int len = cidbuflen * DAHDI_MAX_CHUNKSIZE;
-+ if(debug)
-+ printk("cidbeforering support enabled, length is %d msec\n", cidbuflen);
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++)
-+ {
-+ wc->cid_history_buf[x] = kmalloc(len, GFP_KERNEL);
-+ wc->cid_history_ptr[x] = 0;
-+ wc->cid_history_clone_cnt[x] = 0;
-+ wc->cid_state[x] = CID_STATE_IDLE;
-+ }
-+ }
-+
-+ wctdm_post_initialize(wc);
-+
-+ /* Enable interrupts */
-+ wctdm_enable_interrupts(wc);
-+ /* Initialize Write/Buffers to all blank data */
-+ memset((void *)wc->writechunk,0, DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2 * 2);
-+
-+ /* Start DMA */
-+ wctdm_start_dma(wc);
-+
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++) {
-+ if (wc->cardflag & (1 << x))
-+ cardcount++;
-+ }
-+
-+ printk(KERN_INFO "Found an OpenVox %s: Version %x.%x (%d modules)\n", wc->card_name, (wc->fwversion&(~FLAG_A800))>>4, wc->fwversion&0x0f, cardcount);
-+ if(debug)
-+ printk(KERN_DEBUG "OpenVox %s debug On\n", wc->card_name);
-+
-+ res = 0;
-+ } else
-+ res = -ENOMEM;
-+ }
-+ return res;
-+}
-+
-+static void wctdm_release(struct wctdm *wc)
-+{
-+#ifdef TEST_LOG_INCOME_VOICE
-+ struct file * f = NULL;
-+ mm_segment_t orig_fs;
-+ int i;
-+ char fname[20];
-+#endif
-+
-+ dahdi_unregister_device(wc->ddev);
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+ if (wc->freeregion & 0x01)
-+ release_region(wc->ioaddr, 0xff);
-+ if (wc->freeregion & 0x02)
-+ {
-+ release_mem_region(wc->mem_region, wc->mem_len);
-+ iounmap((void *)wc->mem32);
-+ }
-+
-+#ifdef TEST_LOG_INCOME_VOICE
-+ for(i=0; i<MAX_NUM_CARDS + NUM_FLAG; i++)
-+ {
-+ sprintf(fname, "//usr//%d.pcm", i);
-+ f = filp_open(fname, O_RDWR|O_CREAT, 00);
-+
-+ if (!f || !f->f_op || !f->f_op->read)
-+ {
-+ printk("WARNING: File (read) object is a null pointer!!!\n");
-+ continue;
-+ }
-+
-+ f->f_pos = 0;
-+
-+ orig_fs = get_fs();
-+ set_fs(KERNEL_DS);
-+
-+ if(wc->voc_buf[i])
-+ {
-+ f->f_op->write(f, wc->voc_buf[i], voc_buffer_size, &f->f_pos);
-+ kfree(wc->voc_buf[i]);
-+ }
-+
-+ set_fs(orig_fs);
-+ fput(f);
-+ }
-+#endif
-+
-+ if(cidbeforering)
-+ {
-+ int x;
-+ for (x = 0; x < wc->max_cards/*MAX_NUM_CARDS*/; x++)
-+ kfree(wc->cid_history_buf[x]);
-+ }
-+
-+ kfree(wc);
-+ printk(KERN_INFO "Free an OpenVox A1200 card\n");
-+}
-+
-+static void __devexit wctdm_remove_one(struct pci_dev *pdev)
-+{
-+ struct wctdm *wc = pci_get_drvdata(pdev);
-+ if (wc) {
-+
-+ /* Stop any DMA */
-+ wctdm_stop_dma(wc);
-+ wctdm_reset_tdm(wc);
-+
-+ /* In case hardware is still there */
-+ wctdm_disable_interrupts(wc);
-+
-+ /* Immediately free resources */
-+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS+NUM_FLAG) * 2 * 2, (void *)wc->writechunk, wc->writedma);
-+ free_irq(pdev->irq, wc);
-+
-+ /* Reset PCI chip and registers */
-+ if(wc->fwversion > 0x11)
-+ outb(0x0e, wc->ioaddr + WC_CNTL);
-+ else
-+ {
-+ wc->ledstate = 0;
-+ wctdm_set_led(wc,0,0); // power off all leds.
-+ }
-+
-+ /* Release span, possibly delayed */
-+ if (!wc->usecount)
-+ wctdm_release(wc);
-+ else
-+ wc->dead = 1;
-+ }
-+}
-+
-+static struct pci_device_id wctdm_pci_tbl[] = {
-+ { 0xe159, 0x0001, 0x9100, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x9519, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x95D9, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x9500, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x9532, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x8519, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x9559, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0xe159, 0x0001, 0x9599, PCI_ANY_ID, 0, 0, (unsigned long) &wctdme },
-+ { 0 }
-+};
-+
-+MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl);
-+
-+static struct pci_driver wctdm_driver = {
-+ .name = "opvxa1200",
-+ .probe = wctdm_init_one,
-+ .remove = __devexit_p(wctdm_remove_one),
-+ .suspend = NULL,
-+ .resume = NULL,
-+ .id_table = wctdm_pci_tbl,
-+};
-+
-+static int __init wctdm_init(void)
-+{
-+ int res;
-+ int x;
-+ for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
-+ if (!strcmp(fxo_modes[x].name, opermode))
-+ break;
-+ }
-+ if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
-+ _opermode = x;
-+ } else {
-+ printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode);
-+ for (x=0;x<sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
-+ printk(KERN_INFO " %s\n", fxo_modes[x].name);
-+ printk(KERN_INFO "Note this option is CASE SENSITIVE!\n");
-+ return -ENODEV;
-+ }
-+ if (!strcmp(fxo_modes[_opermode].name, "AUSTRALIA")) {
-+ boostringer=1;
-+ fxshonormode=1;
-+}
-+ if (battdebounce == 0) {
-+ battdebounce = fxo_modes[_opermode].battdebounce;
-+ }
-+ if (battalarm == 0) {
-+ battalarm = fxo_modes[_opermode].battalarm;
-+ }
-+ if (battthresh == 0) {
-+ battthresh = fxo_modes[_opermode].battthresh;
-+ }
-+
-+ res = pci_register_driver(&wctdm_driver);
-+ if (res)
-+ return -ENODEV;
-+ return 0;
-+}
-+
-+static void __exit wctdm_cleanup(void)
-+{
-+ pci_unregister_driver(&wctdm_driver);
-+}
-+
-+module_param(debug, int, 0600);
-+module_param(loopcurrent, int, 0600);
-+module_param(reversepolarity, int, 0600);
-+module_param(robust, int, 0600);
-+module_param(opermode, charp, 0600);
-+module_param(timingonly, int, 0600);
-+module_param(lowpower, int, 0600);
-+module_param(boostringer, int, 0600);
-+module_param(fastringer, int, 0600);
-+module_param(fxshonormode, int, 0600);
-+module_param(battdebounce, uint, 0600);
-+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);
-+module_param(fxotxgain, int, 0600);
-+module_param(fxorxgain, int, 0600);
-+module_param(fxstxgain, int, 0600);
-+module_param(fxsrxgain, int, 0600);
-+module_param(spibyhw, int, 0600);
-+module_param(usememio, int, 0600);
-+module_param(cidbeforering, int, 0600);
-+module_param(cidbuflen, int, 0600);
-+module_param(cidtimeout, int, 0600);
-+module_param(fxofullscale, int, 0600);
-+module_param(fixedtimepolarity, int, 0600);
-+
-+MODULE_DESCRIPTION("OpenVox A1200 Driver");
-+MODULE_AUTHOR("MiaoLin <miaolin@openvox.com.cn>");
-+MODULE_LICENSE("GPL v2");
-+
-+module_init(wctdm_init);
-+module_exit(wctdm_cleanup);
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/Kbuild dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/Kbuild
---- dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/Kbuild 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -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
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/Makefile dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/Makefile
---- dahdi-linux-2.7.0/drivers/dahdi/opvxa1200/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxa1200/Makefile 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/base.c dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/base.c
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/base.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/base.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,4916 @@
-+/*
-+ * OpenVox D115P/D115E PCI/PCI-E Driver version 0.1 01/07/2011
-+ *
-+ * Written by Mark Spencer <markster@digium.com>
-+ * Modify from wct4xxp module by mark.liu@openvox.cn
-+
-+ * Based on previous works, designs, and archetectures conceived and
-+ * written by Jim Dixon <jim@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)
-+
-+#ifndef IRQF_DISABLED
-+#ifdef SA_INTERRUPT
-+#define IRQF_DISABLED SA_INTERRUPT
-+#else
-+#define IRQF_DISABLED 0x0
-+#endif
-+#endif
-+
-+#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_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 */
-+ struct dahdi_device *ddev; /* Pointer to DAHDI 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 = {
-+ .echocan_free = echocan_free,
-+};
-+
-+static const struct dahdi_echocan_ops vpm450m_ec_ops = {
-+ .echocan_free = echocan_free,
-+};
-+#endif
-+
-+static void __set_clear(struct t4 *wc, int span);
-+static int t4_startup(struct file *file, 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, "echo canceller does not support "
-+ "parameters; failing request\n");
-+ 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:
-+ 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;
-+#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 file *file, 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(file, span);
-+
-+ if (debug)
-+ dev_info(&wc->dev->dev, "Done with spanconfig!\n");
-+ return 0;
-+}
-+
-+static int t4_chanconfig(struct file *file, 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)
-+{
-+ struct dahdi_device *ddev = wc->ddev;
-+ const char *devicetype_old = ddev->devicetype;
-+ char *extra_str = "";
-+
-+ if (wc->vpm == T4_VPM_PRESENT)
-+ extra_str = (!wc->vpm450m) ? " (VPM400M)" : " (VPMOCT032)",
-+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s%s",
-+ wc->variety, extra_str);
-+
-+ /* On the off chance that we were able to allocate it previously. */
-+ if (!wc->ddev->devicetype)
-+ wc->ddev->devicetype = devicetype_old;
-+ else
-+ kfree(devicetype_old);
-+}
-+
-+/* 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;
-+
-+ wc->ddev->manufacturer = "OpenVox";
-+ if (order_index[wc->order] == 1)
-+ wc->ddev->location = kasprintf(GFP_KERNEL,
-+ "Board ID Switch %d", wc->order);
-+ else
-+ wc->ddev->location = kasprintf(GFP_KERNEL,
-+ "PCI Bus %02d Slot %02d",
-+ wc->dev->bus->number,
-+ PCI_SLOT(wc->dev->devfn) + 1);
-+ if (!wc->ddev->location)
-+ return; /* FIXME: Error handling */
-+
-+ 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);
-+ switch (ts->spantype) {
-+ case TYPE_T1:
-+ ts->span.spantype = SPANTYPE_DIGITAL_T1;
-+ break;
-+ case TYPE_E1:
-+ ts->span.spantype = SPANTYPE_DIGITAL_E1;
-+ break;
-+ case TYPE_J1:
-+ ts->span.spantype = SPANTYPE_DIGITAL_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
-+
-+ /* 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);
-+
-+ 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 file *file, 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->ddev->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)
-+#ifdef CONFIG_DAHDI_NET
-+ ||
-+ (ts->span.chans[x]->flags & DAHDI_FLAG_NETDEV)
-+#endif
-+ )
-+ 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.count.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.count.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
-+static irqreturn_t t4_interrupt(int irq, void *dev_id)
-+{
-+ 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
-+}
-+
-+static irqreturn_t t4_interrupt_gen2(int irq, void *dev_id)
-+{
-+ 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->ddev->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);
-+
-+ for (x = 0; x < wc->numspans; ++x) {
-+ list_add_tail(&wc->tspans[x]->span.device_node,
-+ &wc->ddev->spans);
-+ }
-+ if (dahdi_register_device(wc->ddev, &wc->dev->dev)) {
-+ 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, IRQF_SHARED | IRQF_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, IRQF_SHARED | IRQF_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);
-+ int basesize;
-+
-+ 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;
-+
-+ dahdi_unregister_device(wc->ddev);
-+ kfree(wc->ddev->location);
-+ kfree(wc->ddev->devicetype);
-+ dahdi_free_device(wc->ddev);
-+#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 = pci_register_driver(&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@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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/Kbuild dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/Kbuild
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/Kbuild 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -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
-+
-+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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/Makefile dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/Makefile
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/Makefile 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/opvxd115-diag.c dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/opvxd115-diag.c
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/opvxd115-diag.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/opvxd115-diag.c 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/opvxd115.h dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/opvxd115.h
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/opvxd115.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/opvxd115.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,124 @@
-+/*
-+ * Wildcard T400P FXS Interface Driver for DAHDI Telephony interface
-+ *
-+ * Written by Mark Spencer <markster@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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/vpm450m.c dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/vpm450m.c
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/vpm450m.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/vpm450m.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,597 @@
-+/*
-+ * Copyright (C) 2005-2006 Digium, Inc.
-+ *
-+ * Mark Spencer <markster@digium.com>
-+ * Modified by mark.liu@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? */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
-+ struct timeval tv;
-+#else
-+ struct timespec64 tv;
-+#endif
-+ unsigned long long total_usecs;
-+ unsigned int mask = ~0;
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
-+ do_gettimeofday(&tv);
-+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
-+ (((unsigned long long)(tv.tv_usec)));
-+#else
-+ ktime_get_real_ts64(&tv);
-+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
-+ (((unsigned long long)(tv.tv_nsec))) / 1000;
-+#endif
-+ 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 -uNr dahdi-linux-2.7.0/drivers/dahdi/opvxd115/vpm450m.h dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/vpm450m.h
---- dahdi-linux-2.7.0/drivers/dahdi/opvxd115/vpm450m.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/opvxd115/vpm450m.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,43 @@
-+/*
-+ * Copyright (C) 2005-2006 Digium, Inc.
-+ *
-+ * Mark Spencer <markster@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 -uNr dahdi-linux-2.7.0/drivers/dahdi/wcopenpci.c dahdi-extra-dahdi-linux/drivers/dahdi/wcopenpci.c
---- dahdi-linux-2.7.0/drivers/dahdi/wcopenpci.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/wcopenpci.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,1792 @@
-+/*
-+ * Voicetronix OpenPCI Interface Driver for Zapata Telephony interface
-+ *
-+ * Written by Mark Spencer <markster@linux-support.net>
-+ * Matthew Fredrickson <creslin@linux-support.net>
-+ * Ben Kramer <ben@voicetronix.com.au>
-+ * Ron Lee <ron@voicetronix.com.au>
-+ *
-+ * Copyright (C) 2001, Linux Support Services, Inc.
-+ * Copyright (C) 2005 - 2007, Voicetronix
-+ *
-+ * 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.
-+ *
-+ */
-+
-+/* Conditional debug options */
-+#define VERBOSE_TIMING 0
-+
-+/* Driver constants */
-+#define DRIVER_DESCRIPTION "Voicetronix OpenPCI DAHDI driver"
-+#define DRIVER_AUTHOR "Mark Spencer <markster@digium.com> "\
-+ "Voicetronix <support@voicetronix.com.au>"
-+
-+#define NAME "wcopenpci"
-+#define MAX_PORTS 8 /* Maximum number of ports on each carrier */
-+#define MAX_CARDS 8 /* Maximum number of carriers per host */
-+
-+#define DEFAULT_COUNTRY "AUSTRALIA"
-+
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/delay.h>
-+#include <linux/sched.h>
-+
-+#include <dahdi/kernel.h>
-+#include <dahdi/version.h>
-+#include "proslic.h"
-+#include <dahdi/wctdm_user.h>
-+#include <linux/interrupt.h>
-+#include <linux/mutex.h>
-+
-+#include "fxo_modes.h"
-+
-+#ifndef IRQF_DISABLED
-+#ifdef SA_INTERRUPT
-+#define IRQF_DISABLED SA_INTERRUPT
-+#else
-+#define IRQF_DISABLED 0x0
-+#endif
-+#endif
-+
-+static struct ps_country_reg {
-+ const char *country;
-+ unsigned short value;
-+} ps_country_regs[] = {
-+ {"ARGENTINA", 0x8},
-+ {"AUSTRALIA", 0xD},
-+ {"AUSTRIA", 0xD},
-+ {"BAHRAIN", 0xC},
-+ {"BELGIUM", 0xC},
-+ {"BRAZIL", 0x8},
-+ {"BULGARIA", 0xD},
-+ {"CANADA", 0x8},
-+ {"CHILE", 0x8},
-+ {"CHINA", 0xC},
-+ {"COLOMBIA", 0x8},
-+ {"CROATIA", 0xC},
-+ {"CYPRUS", 0xC},
-+ {"CZECH", 0xC},
-+ {"DENMARK", 0xC},
-+ {"ECUADOR", 0x8},
-+ {"EGYPT", 0x8},
-+ {"ELSALVADOR", 0x8},
-+ {"FINLAND", 0xC},
-+ {"FRANCE", 0xC},
-+ {"GERMANY", 0xD},
-+ {"GREECE", 0xC},
-+ {"GUAM", 0x8},
-+ {"HONGKONG", 0x8},
-+ {"HUNGARY", 0x8},
-+ {"ICELAND", 0xC},
-+ {"INDIA", 0xF},
-+ {"INDONESIA", 0x8},
-+ {"IRELAND", 0xC},
-+ {"ISRAEL", 0xC},
-+ {"ITALY", 0xC},
-+ {"JAPAN", 0x8},
-+ {"JORDAN", 0x8},
-+ {"KAZAKHSTAN", 0x8},
-+ {"KUWAIT", 0x8},
-+ {"LATVIA", 0xC},
-+ {"LEBANON", 0xC},
-+ {"LUXEMBOURG", 0xC},
-+ {"MACAO", 0x8},
-+ {"MALAYSIA", 0x8},
-+ {"MALTA", 0xC},
-+ {"MEXICO", 0x8},
-+ {"MOROCCO", 0xC},
-+ {"NETHERLANDS", 0xC},
-+ {"NEWZEALAND", 0xF},
-+ {"NIGERIA", 0xC},
-+ {"NORWAY", 0xC},
-+ {"OMAN", 0x8},
-+ {"PAKISTAN", 0x8},
-+ {"PERU", 0x8},
-+ {"PHILIPPINES", 0x8},
-+ {"POLAND", 0x8},
-+ {"PORTUGAL", 0xC},
-+ {"ROMANIA", 0x8},
-+ {"RUSSIA", 0x8},
-+ {"SAUDIARABIA", 0x8},
-+ {"SINGAPORE", 0x8},
-+ {"SLOVAKIA", 0xE},
-+ {"SLOVENIA", 0xE},
-+ {"SOUTHAFRICA", 0xE},
-+ {"SOUTHKOREA", 0x8},
-+ {"SPAIN", 0xC},
-+ {"SWEDEN", 0xC},
-+ {"SWITZERLAND", 0xC},
-+ {"SYRIA", 0x8},
-+ {"TAIWAN", 0x8},
-+ {"THAILAND", 0x8},
-+ {"UAE", 0x8},
-+ {"UK", 0xC},
-+ {"USA", 0x8},
-+ {"YEMEN", 0x8}
-+};
-+
-+#define INOUT 2
-+
-+/* Allocate enough memory for two zt chunks, receive and transmit. Each
-+ * sample uses 32 bits. Allocate an extra set just for control too */
-+#define VT_PCIDMA_BLOCKSIZE (DAHDI_MAX_CHUNKSIZE * INOUT * MAX_PORTS * 2 * 2)
-+#define VT_PCIDMA_MIDDLE (DAHDI_MAX_CHUNKSIZE * MAX_PORTS - 4)
-+#define VT_PCIDMA_END (DAHDI_MAX_CHUNKSIZE * MAX_PORTS * 2 - 4)
-+
-+#define ID_DATA_MAXSIZE 30
-+
-+#define NUM_CAL_REGS 12
-+#define NUM_FXO_REGS 60
-+
-+#define TREG(addr) (wc->ioaddr + addr)
-+
-+#define TJ_CNTL TREG(0x00)
-+#define TJ_OPER TREG(0x01)
-+#define TJ_AUXC TREG(0x02)
-+#define TJ_AUXD TREG(0x03)
-+#define TJ_MASK0 TREG(0x04)
-+#define TJ_MASK1 TREG(0x05)
-+#define TJ_INTSTAT TREG(0x06)
-+#define TJ_AUXR TREG(0x07)
-+
-+#define TJ_DMAWS TREG(0x08)
-+#define TJ_DMAWI TREG(0x0c)
-+#define TJ_DMAWE TREG(0x10)
-+#define TJ_DMAWC TREG(0x14)
-+#define TJ_DMARS TREG(0x18)
-+#define TJ_DMARI TREG(0x1c)
-+#define TJ_DMARE TREG(0x20)
-+#define TJ_DMARC TREG(0x24)
-+
-+#define TJ_AUXINTPOL TREG(0x2A)
-+
-+#define TJ_AUXFUNC TREG(0x2b)
-+#define TJ_SFDELAY TREG(0x2c)
-+#define TJ_SERCTL TREG(0x2d)
-+#define TJ_SFLC TREG(0x2e)
-+#define TJ_FSCDELAY TREG(0x2f)
-+
-+#define TJ_REGBASE TREG(0xc0)
-+
-+#define PIB(addr) (TJ_REGBASE + addr * 4)
-+
-+#define HTXF_READY (inb(PIB(0)) & 0x10)
-+#define HRXF_READY (inb(PIB(0)) & 0x20)
-+
-+
-+#define VT_PORT_EMPTY 0
-+#define VT_PORT_VDAA 1 /* Voice DAA - FXO */
-+#define VT_PORT_PROSLIC 2 /* ProSLIC - FXS */
-+
-+#define VBAT 0xC7
-+
-+#define HKMODE_FWDACT 1
-+#define HKMODE_FWDONACT 2
-+#define HKMODE_RINGING 4
-+
-+#define HOOK_ONHOOK 0
-+#define HOOK_OFFHOOK 1
-+
-+#define DSP_CODEC_RING 12 /* RING rising edge detected */
-+#define DSP_CODEC_HKOFF 22 /* station port off hook */
-+#define DSP_CODEC_HKON 23 /* station port on hook */
-+#define DSP_RING_OFF 24 /* RING falling edge detected */
-+#define DSP_DROP 25
-+
-+#define DSP_CODEC_FLASH 26 /* station port hook flash */
-+
-+#define DSP_LOOP_OFFHOOK 38 /* Loop Off hook from OpenPCI */
-+#define DSP_LOOP_ONHOOK 39 /* Loop On hook from OpenPCI */
-+#define DSP_LOOP_POLARITY 40 /* Loop Polarity from OpenPCI */
-+#define DSP_LOOP_NOBATT 41
-+
-+#define DSP_PROSLIC_SANITY 50 /* Sanity alert from a ProSLIC port */
-+#define DSP_PROSLIC_PWR_ALARM 51 /* Power Alarm from a ProSLIC port */
-+#define DSP_VDAA_ISO_FRAME_E 52 /* ISO-cap frame sync lost on VDAA port*/
-+
-+#if VERBOSE_TIMING
-+ #define REPORT_WAIT(n,x) \
-+ cardinfo(card->cardnum, #n " wait at %d, " #x " = %d", __LINE__, x )
-+#else
-+ #define REPORT_WAIT(n,x)
-+#endif
-+
-+#define BUSY_WAIT(countvar,cond,delay,iter,failret) \
-+ countvar = 0; \
-+ while(cond){ \
-+ udelay(delay); \
-+ if (++countvar > iter){ \
-+ cardcrit(wc->boardnum, "busy wait FAILED at %d", __LINE__); \
-+ return failret; \
-+ } \
-+ } \
-+ REPORT_WAIT(busy,i)
-+
-+#define LOCKED_WAIT(countvar,cond,delay,iter,failret) \
-+ countvar = 0; \
-+ while(cond){ \
-+ udelay(delay); \
-+ if (++countvar > iter){ \
-+ dbginfo(wc->boardnum,"busy wait failed at %d",__LINE__); \
-+ spin_unlock_irqrestore(&wc->lock, flags); \
-+ return failret; \
-+ } \
-+ } \
-+ REPORT_WAIT(locked,i)
-+
-+#define HTXF_WAIT() BUSY_WAIT(i,HTXF_READY,5,500,RET_FAIL)
-+#define HRXF_WAIT() BUSY_WAIT(i,!HRXF_READY,5,70000,RET_FAIL)
-+#define HTXF_WAIT_RET(failret) BUSY_WAIT(i,HTXF_READY,5,500,failret)
-+#define HRXF_WAIT_RET(failret) BUSY_WAIT(i,!HRXF_READY,5,1000,failret)
-+
-+#define HTXF_WAIT_LOCKED() LOCKED_WAIT(i,HTXF_READY,5,500,RET_FAIL)
-+#define HRXF_WAIT_LOCKED() LOCKED_WAIT(i,!HRXF_READY,5,1000,RET_FAIL)
-+#define HTXF_WAIT_LOCKED_RET(failret) LOCKED_WAIT(i,HTXF_READY,5,500,failret)
-+#define HRXF_WAIT_LOCKED_RET(failret) LOCKED_WAIT(i,!HRXF_READY,5,1000,failret)
-+
-+
-+static struct openpci {
-+ struct pci_dev *dev;
-+ char *variety;
-+ int boardnum;
-+ int portcount;
-+ int porttype[MAX_PORTS];
-+
-+ int firmware;
-+ char serial[ID_DATA_MAXSIZE];
-+
-+ spinlock_t lock;
-+
-+ //XXX Replace these with proper try_module_get locking in the dahdi driver.
-+ //int usecount; //XXX
-+ //int dead; //XXX
-+ union {
-+ struct {
-+ int offhook;
-+ } fxo;
-+ struct {
-+ int ohttimer;
-+ int idletxhookstate; /* IDLE changing hook state */
-+ int lasttxhook;
-+ } fxs;
-+ } mod[MAX_PORTS];
-+
-+ unsigned long ioaddr;
-+ dma_addr_t readdma;
-+ dma_addr_t writedma;
-+ volatile unsigned int *writechunk; /* Double-word aligned write memory */
-+ volatile unsigned int *readchunk; /* Double-word aligned read memory */
-+
-+ struct dahdi_chan _chans[MAX_PORTS];
-+ struct dahdi_chan *chans[MAX_PORTS];
-+ struct dahdi_device *ddev;
-+ struct dahdi_span span;
-+} *cards[MAX_CARDS];
-+
-+/* You must hold this lock anytime you access or modify the cards[] array. */
-+static DEFINE_MUTEX(cards_mutex);
-+
-+static unsigned char fxo_port_lookup[8] = { 0x0, 0x8, 0x4, 0xc, 0x10, 0x18, 0x14, 0x1c};
-+static unsigned char fxs_port_lookup[8] = { 0x0, 0x1, 0x2, 0x3, 0x10, 0x11, 0x12, 0x13};
-+static char wcopenpci[] = "Voicetronix OpenPCI";
-+
-+static char *country = DEFAULT_COUNTRY;
-+static int reversepolarity; /* = 0 */
-+static int debug; /* = 0 */
-+
-+module_param(country, charp, 0444);
-+module_param(debug, int, 0600);
-+module_param(reversepolarity, int, 0600);
-+MODULE_PARM_DESC(country, "Set the default country name");
-+MODULE_PARM_DESC(debug, "Enable verbose logging");
-+
-+/* #define DEBUG_LOOP_VOLTAGE 1 */
-+#ifdef DEBUG_LOOP_VOLTAGE
-+ /* This param is a 32 bit bitfield where bit 1 << cardnum * 8 << portnum
-+ * will enable voltage monitoring on that port (fxo only presently)
-+ */
-+ static int voltmeter; /* = 0 */
-+ module_param(voltmeter, int, 0600);
-+ MODULE_PARM_DESC(voltmeter, "Enable loop voltage metering");
-+#endif
-+
-+
-+/* boolean return values */
-+#define RET_OK 1
-+#define RET_FAIL 0
-+
-+/* Convenience macros for logging */
-+#define info(format,...) printk(KERN_INFO NAME ": " format "\n" , ## __VA_ARGS__)
-+#define warn(format,...) printk(KERN_WARNING NAME ": " format "\n" , ## __VA_ARGS__)
-+#define crit(format,...) printk(KERN_CRIT NAME ": " format "\n" , ## __VA_ARGS__)
-+#define cardinfo(cardnum,format,...) info("[%02d] " format, cardnum , ## __VA_ARGS__)
-+#define cardwarn(cardnum,format,...) warn("[%02d] " format, cardnum , ## __VA_ARGS__)
-+#define cardcrit(cardnum,format,...) crit("[%02d] " format, cardnum , ## __VA_ARGS__)
-+#define dbginfo(cardnum,format,...) if (debug) info("[%02d] " format, cardnum , ## __VA_ARGS__)
-+
-+
-+static inline const char *porttype(struct openpci *wc, int port)
-+{
-+ switch( wc->porttype[port] ) {
-+ case VT_PORT_VDAA: return "VDAA";
-+ case VT_PORT_PROSLIC: return "ProSLIC";
-+ case VT_PORT_EMPTY: return "empty port";
-+ default: return "unknown type";
-+ }
-+}
-+
-+
-+static int __read_reg_fxo(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char *value)
-+{
-+ unsigned char portadr = fxo_port_lookup[port];
-+ int i;
-+
-+ if (HRXF_READY) *value = inb(PIB(1));
-+
-+ outb(0x11, PIB(1)); HTXF_WAIT();
-+ outb(0x2, PIB(1)); HTXF_WAIT();
-+ outb(portadr, PIB(1)); HTXF_WAIT();
-+ outb(reg, PIB(1)); HTXF_WAIT();
-+ HRXF_WAIT(); *value = inb(PIB(1));
-+
-+ return RET_OK;
-+}
-+
-+static int read_reg_fxo(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char *value)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (__read_reg_fxo(wc, port, reg, value)) {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardcrit(wc->boardnum, "FXO port %d, reg %d, read failed!", port, reg);
-+ return RET_FAIL;
-+}
-+
-+static int __read_reg_fxs(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char *value)
-+{
-+ unsigned char portadr = fxs_port_lookup[port];
-+ int i;
-+
-+ if (HRXF_READY) *value = inb(PIB(1));
-+
-+ outb(0x13, PIB(1)); HTXF_WAIT();
-+ outb(0x2, PIB(1)); HTXF_WAIT();
-+ outb(portadr, PIB(1)); HTXF_WAIT();
-+ outb(reg, PIB(1)); HTXF_WAIT();
-+ HRXF_WAIT(); *value = inb(PIB(1));
-+
-+ return RET_OK;
-+}
-+
-+static int read_reg_fxs(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char *value)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if ( __read_reg_fxs(wc, port, reg, value) ) {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardcrit(wc->boardnum, "FXS port %d, reg %d, read failed!", port, reg);
-+ return RET_FAIL;
-+}
-+
-+static int __write_reg_fxo(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char value)
-+{
-+ unsigned char portadr = fxo_port_lookup[port];
-+ int i;
-+
-+ outb(0x10, PIB(1) ); HTXF_WAIT();
-+ outb(0x3, PIB(1)); HTXF_WAIT();
-+ outb(portadr, PIB(1)); HTXF_WAIT();
-+ outb(reg, PIB(1)); HTXF_WAIT();
-+ outb(value, PIB(1)); HTXF_WAIT();
-+
-+ return RET_OK;
-+}
-+
-+static int write_reg_fxo(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char value)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (__write_reg_fxo(wc, port, reg, value)) {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardcrit(wc->boardnum, "FXO port %d, reg %d, write(%d) failed!",
-+ port, reg, value);
-+ return RET_FAIL;
-+}
-+
-+static int __write_reg_fxs(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char value)
-+{
-+ unsigned char portadr = fxs_port_lookup[port];
-+ int i;
-+
-+ outb(0x12, PIB(1) ); HTXF_WAIT();
-+ outb(0x3, PIB(1)); HTXF_WAIT();
-+ outb(portadr, PIB(1)); HTXF_WAIT();
-+ outb(reg, PIB(1)); HTXF_WAIT();
-+ outb(value, PIB(1)); HTXF_WAIT();
-+
-+ return RET_OK;
-+}
-+
-+static int write_reg_fxs(struct openpci *wc, int port, unsigned char reg,
-+ unsigned char value)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (__write_reg_fxs(wc, port, reg, value)) {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardcrit(wc->boardnum, "FXS port %d, reg %d, write(%d) failed!", port, reg, value);
-+ return RET_FAIL;
-+}
-+
-+static int __wait_indreg_fxs(struct openpci *wc, int port)
-+{
-+ unsigned char value;
-+ int count = 100;
-+
-+ while (--count) {
-+ if ( __read_reg_fxs(wc, port, I_STATUS, &value)) {
-+ if (value == 0)
-+ return RET_OK;
-+ } else {
-+ cardcrit(wc->boardnum,
-+ "failed to read port %d PS_IND_ADDR_ST, retrying...",
-+ port);
-+ }
-+ udelay(5);
-+ }
-+ cardcrit(wc->boardnum, "Failed to wait for indirect reg write to port %d", port);
-+ return RET_FAIL;
-+}
-+
-+static int write_indreg_fxs(struct openpci *wc, int port, unsigned char reg,
-+ unsigned short value)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (__wait_indreg_fxs(wc, port)
-+ && __write_reg_fxs(wc, port, IDA_LO, value & 0xff)
-+ && __write_reg_fxs(wc, port, IDA_HI, (value & 0xff00)>>8)
-+ && __write_reg_fxs(wc, port, IAA, reg)
-+ && __wait_indreg_fxs(wc, port))
-+ {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardcrit(wc->boardnum, "FXS indreg %d write failed on port %d",
-+ reg, port);
-+ return RET_FAIL;
-+}
-+
-+static int read_indreg_fxs(struct openpci *wc, int port, unsigned char reg, unsigned short *value)
-+{
-+ unsigned long flags;
-+ unsigned char lo, hi;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ if (__wait_indreg_fxs(wc, port)
-+ && __write_reg_fxs(wc, port, IAA, reg)
-+ && __wait_indreg_fxs(wc, port)
-+ && __read_reg_fxs(wc, port, IDA_LO, &lo)
-+ && __read_reg_fxs(wc, port, IDA_HI, &hi) )
-+ {
-+ *value = lo | hi << 8;
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_FAIL;
-+}
-+
-+static void start_dma(struct openpci *wc)
-+{
-+ outb(0x0f, TJ_CNTL);
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ schedule_timeout(1);
-+ outb(0x01, TJ_CNTL);
-+ outb(0x01, TJ_OPER);
-+}
-+
-+static void restart_dma(struct openpci *wc)
-+{
-+ /* Reset Master and TDM */
-+ outb(0x01, TJ_CNTL);
-+ outb(0x01, TJ_OPER);
-+}
-+
-+/* You must hold the card spinlock to call this function */
-+static int __ping_arm(struct openpci *wc)
-+{
-+ int i;
-+ int pong = 0;
-+
-+ while (pong != 0x02) {
-+ outb(0x02, PIB(1)); HTXF_WAIT();
-+ HRXF_WAIT(); pong = inb(PIB(1));
-+ dbginfo(wc->boardnum, "ping_arm returned %x", pong);
-+ }
-+ while (pong == 0x02) {
-+ // Poke no-ops into the arm while it is still returning data,
-+ // if 500 usec elapses with no further response from it then
-+ // the message queue is should be completely cleared.
-+ outb(0x00, PIB(1)); HTXF_WAIT();
-+ i = 100;
-+ while (!HRXF_READY && --i)
-+ udelay(5);
-+ if (i == 0)
-+ break;
-+ pong = inb(PIB(1));
-+ dbginfo(wc->boardnum, "ping_arm returned %x.", pong);
-+ }
-+ return RET_OK;
-+}
-+
-+static void arm_event(struct openpci *wc, char *msg)
-+{
-+ int port = msg[0];
-+
-+ switch (msg[1]) {
-+ case DSP_LOOP_OFFHOOK:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_OFFHOOK);
-+ dbginfo(wc->boardnum, "Port %d Loop OffHook", port);
-+ break;
-+
-+ case DSP_LOOP_ONHOOK:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_ONHOOK);
-+ dbginfo(wc->boardnum, "Port %d Loop OnHook", port);
-+ break;
-+
-+ case DSP_LOOP_POLARITY:
-+ dahdi_qevent_lock(wc->chans[port], DAHDI_EVENT_POLARITY);
-+ dbginfo(wc->boardnum, "Port %d Loop Polarity", port);
-+ break;
-+
-+ case DSP_CODEC_RING:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_RING);
-+ dbginfo(wc->boardnum, "Port %d Ring On", port);
-+ break;
-+
-+ case DSP_RING_OFF:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_OFFHOOK);
-+ dbginfo(wc->boardnum, "Port %d Ring Off", port);
-+ break;
-+
-+ case DSP_CODEC_HKOFF:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_OFFHOOK);
-+ dbginfo(wc->boardnum, "Port %d Station OffHook", port);
-+ if (reversepolarity)
-+ wc->mod[port].fxs.idletxhookstate = 5;
-+ else
-+ wc->mod[port].fxs.idletxhookstate = 1;
-+ break;
-+
-+ case DSP_CODEC_HKON:
-+ dahdi_hooksig(wc->chans[port], DAHDI_RXSIG_ONHOOK);
-+ dbginfo(wc->boardnum, "Port %d Station OnHook", port);
-+ if (reversepolarity)
-+ wc->mod[port].fxs.idletxhookstate = 6;
-+ else
-+ wc->mod[port].fxs.idletxhookstate = 2;
-+ break;
-+
-+ case DSP_CODEC_FLASH:
-+ dahdi_qevent_lock(wc->chans[port],
-+ DAHDI_EVENT_WINKFLASH);
-+ dbginfo(wc->boardnum, "Port %d Station Flash", port);
-+ break;
-+
-+ case DSP_DROP:
-+ case DSP_LOOP_NOBATT:
-+ break;
-+
-+ //XXX What to do to recover from these?
-+ case DSP_PROSLIC_SANITY:
-+ dbginfo(wc->boardnum, "Port %d ProSlic has gone insane!", port);
-+ break;
-+
-+ case DSP_PROSLIC_PWR_ALARM:
-+ {
-+ char errbuf[32] = " Unknown", *p = errbuf;
-+ int i = 49;
-+
-+ msg[2] >>= 2;
-+ for (; i < 55; ++i, msg[2] >>= 1 )
-+ if (msg[2] & 1) {
-+ *(++p) = 'Q';
-+ *(++p) = i;
-+ *(++p) = ',';
-+ }
-+ if (p != errbuf)
-+ *p = '\0';
-+ cardcrit(wc->boardnum,"%d: ProSlic power ALARM:%s",
-+ msg[0], errbuf);
-+ //write_reg_fxs(wc, port, 64, wc->mod[port].fxs.lasttxhook );
-+ return;
-+ }
-+
-+ case DSP_VDAA_ISO_FRAME_E:
-+ dbginfo(wc->boardnum, "Port %d VDAA has lost ISO-Cap frame lock", port);
-+ break;
-+
-+ default:
-+ cardwarn(wc->boardnum, "Unknown message from Arm[%d] for port %d",
-+ msg[1], port);
-+ break;
-+ }
-+}
-+
-+/* You must hold the card spinlock to call this function */
-+static inline int __read_arm_byte( struct openpci *wc, unsigned char *msg)
-+{
-+ int i;
-+
-+ HRXF_WAIT(); *msg = inb(PIB(1));
-+ return RET_OK;
-+}
-+
-+static inline int read_arm_msg( struct openpci *wc, unsigned char *msg)
-+{
-+ unsigned long flags;
-+ int i, d, count;
-+ int ret = RET_OK;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0x08, PIB(1)); HTXF_WAIT_LOCKED();
-+ //XXX Do we need to clear the interrupt flag even if this fails?
-+ HRXF_WAIT_LOCKED(); count = inb(PIB(1));
-+ if (count == 0) {
-+ ret = RET_FAIL;
-+ } else if ( count < 3 || count > 4 ) {
-+ cardcrit(wc->boardnum, "BOGUS arm message size %d, flushing queue", count);
-+ // NB: This may take a while (up to 500usec or more) to complete
-+ // and we are in the isr at present when this is called, so
-+ // we may miss an interrupt or two while this is done in the
-+ // bottom half, but we are already in trouble, so...
-+ d = debug; debug = 5; __ping_arm( wc ); debug = d;
-+ ret = RET_FAIL;
-+ } else while (--count ) {
-+ if (! __read_arm_byte(wc, msg)) {
-+ cardcrit(wc->boardnum,
-+ "Failed to read arm message %d more bytes expected",
-+ count);
-+ ret = RET_FAIL;
-+ break;
-+ }
-+ ++msg;
-+ }
-+ outb(0x09, PIB(1)); HTXF_WAIT_LOCKED();
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return ret;
-+}
-+
-+static void openpci_arm_work( void *cardptr )
-+{
-+ struct openpci *wc = (struct openpci*)cardptr;
-+ unsigned char armmsg[4];
-+
-+ if (read_arm_msg(wc, armmsg))
-+ arm_event(wc, armmsg);
-+}
-+
-+
-+static inline void openpci_write(struct openpci *wc, unsigned char flags)
-+{
-+ int x,y;
-+ volatile unsigned int *writechunk;
-+
-+ if (flags & 0x01)
-+ writechunk = wc->writechunk;
-+ else if (flags & 0x02)
-+ writechunk = wc->writechunk + DAHDI_CHUNKSIZE*2;
-+ else {
-+ cardcrit(wc->boardnum, "bad write interrupt flags %x, at %x",
-+ flags, inb(TJ_DMAWC) );
-+ return;
-+ }
-+ /* get data */
-+ dahdi_transmit(&wc->span);
-+ for (y = 0, x = 0; x < DAHDI_CHUNKSIZE; ++x) {
-+ /* Send a sample, as a 32-bit word */
-+#ifdef __BIG_ENDIAN
-+#warning No big endian support (yet)
-+#else
-+ /* transmit second 4 ports */
-+ writechunk[y] = 0;
-+ if (wc->porttype[4])
-+ writechunk[y] |= (wc->chans[4]->writechunk[x] << 24);
-+ else
-+ writechunk[y] |= (0x01 << 24);
-+ if (wc->porttype[5])
-+ writechunk[y] |= (wc->chans[5]->writechunk[x] << 16);
-+ if (wc->porttype[6])
-+ writechunk[y] |= (wc->chans[6]->writechunk[x] << 8);
-+ if (wc->porttype[7])
-+ writechunk[y] |= (wc->chans[7]->writechunk[x]);
-+ ++y;
-+
-+ /* transmit first 4 ports */
-+ writechunk[y] = 0x01000000;
-+ /* Make sure first port doesnt equal 0x00 */
-+ if (wc->porttype[0]) {
-+ if (wc->chans[0]->writechunk[x] == 0)
-+ writechunk[y] |= (0x01 << 24);
-+ else
-+ writechunk[y] |= (wc->chans[0]->writechunk[x] << 24);
-+ }
-+ //else writechunk[y] |= (0x00 << 24);
-+ if (wc->porttype[1])
-+ writechunk[y] |= (wc->chans[1]->writechunk[x] << 16);
-+ if (wc->porttype[2])
-+ writechunk[y] |= (wc->chans[2]->writechunk[x] << 8);
-+ if (wc->porttype[3])
-+ writechunk[y] |= (wc->chans[3]->writechunk[x]);
-+ ++y;
-+#endif
-+ }
-+}
-+
-+static inline void openpci_read(struct openpci *wc, unsigned char flags)
-+{
-+ int x,y;
-+ volatile unsigned int *readchunk;
-+
-+ if (flags & 0x08)
-+ readchunk = wc->readchunk + DAHDI_CHUNKSIZE*2;
-+ else if (flags & 0x04)
-+ readchunk = wc->readchunk;
-+ else {
-+ cardcrit(wc->boardnum, "bad read interrupt flags %x, at %x",
-+ flags, inb(TJ_DMARC));
-+ return;
-+ }
-+
-+ for (y = 0,x = 0; x < DAHDI_CHUNKSIZE; ++x) {
-+#ifdef __BIG_ENDIAN
-+#warning No big endian support (yet)
-+#else
-+ /* Receive first 4 ports */
-+
-+ if (wc->porttype[0])
-+ wc->chans[0]->readchunk[x] = (readchunk[y] >> 24) & 0xff;
-+ if (wc->porttype[1])
-+ wc->chans[1]->readchunk[x] = (readchunk[y] >> 16) & 0xff;
-+ if (wc->porttype[2])
-+ wc->chans[2]->readchunk[x] = (readchunk[y] >> 8) & 0xff;
-+ if (wc->porttype[3])
-+ wc->chans[3]->readchunk[x] = (readchunk[y]) & 0xff;
-+ ++y;
-+ /* Receive second 4 ports */
-+ if (wc->porttype[4])
-+ wc->chans[4]->readchunk[x] = (readchunk[y] >> 24) & 0xff;
-+ if (wc->porttype[5])
-+ wc->chans[5]->readchunk[x] = (readchunk[y] >> 16) & 0xff;
-+ if (wc->porttype[6])
-+ wc->chans[6]->readchunk[x] = (readchunk[y] >> 8) & 0xff;
-+ if (wc->porttype[7])
-+ wc->chans[7]->readchunk[x] = (readchunk[y]) & 0xff;
-+ ++y;
-+#endif
-+ }
-+ /* XXX We're wasting 8 taps. We should get closer :( */
-+ for (x = 0; x < MAX_PORTS; x++) {
-+ if (wc->porttype[x])
-+ dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk);
-+ }
-+ dahdi_receive(&wc->span);
-+}
-+
-+static irqreturn_t openpci_isr(int irq, void *dev_id)
-+{
-+ struct openpci *wc = dev_id;
-+ unsigned long flags;
-+ unsigned char status;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ status = inb(TJ_INTSTAT);
-+ outb(status, TJ_INTSTAT);
-+
-+ if (!status) {
-+ if (inb(TJ_AUXR) & 0x02) {
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return IRQ_NONE;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ openpci_arm_work(wc);
-+ return IRQ_HANDLED;
-+ }
-+ if (status & 0x10) {
-+ /* PCI Master abort */
-+ cardcrit(wc->boardnum, "PCI Master Abort.");
-+ /* Stop DMA, wait for watchdog */
-+ outb(0x00, TJ_OPER);
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return IRQ_HANDLED;
-+ }
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+
-+ if (status & 0x20) {
-+ /* PCI Target abort */
-+ cardcrit(wc->boardnum, "PCI Target Abort.");
-+ return IRQ_HANDLED;
-+ }
-+ if (status & 0x03) {
-+ openpci_write(wc, status);
-+ }
-+ if (status & 0x0c) {
-+ #ifdef DEBUG_LOOP_VOLTAGE
-+ //{{{
-+ static int counter[MAX_CARDS];
-+ int card = wc->boardnum;
-+ int port = ++counter[card] & 0x07;
-+ int ignore = counter[card] & 0xf0;
-+
-+ if (!ignore && (voltmeter & ((1 << (card * 8)) << port))) {
-+ unsigned char lv;
-+ if (wc->porttype[port] == VT_PORT_VDAA &&
-+ read_reg_fxo(wc, port, 29, &lv))
-+ cardinfo(wc->boardnum, "Port %d loop voltage %d",
-+ port, lv < 128 ? lv :
-+ lv - 256);
-+ }
-+ //}}}
-+ #endif
-+ openpci_read(wc, status);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int openpci_ioctl(struct dahdi_chan *chan, unsigned int cmd,
-+ unsigned long data)
-+{
-+ struct wctdm_stats stats;
-+ struct wctdm_regs regs;
-+ struct wctdm_regop regop;
-+ struct wctdm_echo_coefs echoregs;
-+ struct openpci *wc = chan->pvt;
-+ int port = chan->chanpos - 1;
-+ int x;
-+
-+ switch (cmd) {
-+ case DAHDI_ONHOOKTRANSFER:
-+ if (wc->porttype[port] != VT_PORT_PROSLIC)
-+ return -EINVAL;
-+ if (get_user(x, (int __user *)data))
-+ return -EFAULT;
-+ wc->mod[port].fxs.ohttimer = x << 3;
-+ if (reversepolarity)
-+ wc->mod[port].fxs.idletxhookstate = 0x6; /* OHT mode when idle */
-+ else
-+ wc->mod[port].fxs.idletxhookstate = 0x2;
-+ switch (wc->mod[port].fxs.lasttxhook) {
-+ case 0x1:
-+ case 0x5:
-+ if (reversepolarity)
-+ wc->mod[port].fxs.lasttxhook = 0x6;
-+ else
-+ wc->mod[port].fxs.lasttxhook = 0x2;
-+ if (!write_reg_fxs(wc, port, 64,
-+ wc->mod[port].fxs.lasttxhook))
-+ return -EIO;
-+ }
-+ break;
-+ case DAHDI_SETPOLARITY:
-+ if (get_user(x, (int __user *)data))
-+ return -EFAULT;
-+ if (wc->porttype[port] != VT_PORT_PROSLIC)
-+ return -EINVAL;
-+ /* Can't change polarity while ringing or when open */
-+ if ((wc->mod[port].fxs.lasttxhook == 0x04) ||
-+ (wc->mod[port].fxs.lasttxhook == 0x00))
-+ return -EINVAL;
-+
-+ if ((x && !reversepolarity) || (!x && reversepolarity))
-+ wc->mod[port].fxs.lasttxhook |= 0x04;
-+ else
-+ wc->mod[port].fxs.lasttxhook &= ~0x04;
-+ if (!write_reg_fxs(wc, port, 64, wc->mod[port].fxs.lasttxhook))
-+ return -EIO;
-+ break;
-+ case WCTDM_GET_STATS:
-+ if (wc->porttype[port] == VT_PORT_PROSLIC) {
-+ unsigned char linevolt;
-+ if (read_reg_fxs(wc, port, 80, &linevolt))
-+ stats.tipvolt = linevolt * -376;
-+ else
-+ return -EIO;
-+ if (read_reg_fxs(wc, port, 81, &linevolt))
-+ stats.ringvolt = linevolt * -376;
-+ else
-+ return -EIO;
-+ if (read_reg_fxs(wc, port, 82, &linevolt))
-+ stats.batvolt = linevolt * -376;
-+ else
-+ return -EIO;
-+ } else if (wc->porttype[port] == VT_PORT_VDAA) {
-+ unsigned char linevolt;
-+ if (read_reg_fxo(wc, port, 29, &linevolt))
-+ stats.tipvolt = stats.ringvolt = stats.batvolt = linevolt * 1000;
-+ else
-+ return -EIO;
-+ } else
-+ return -EINVAL;
-+ if (copy_to_user((void __user *)data, &stats, sizeof(stats)))
-+ return -EFAULT;
-+ break;
-+ case WCTDM_GET_REGS:
-+ if (wc->porttype[port] == VT_PORT_PROSLIC) {
-+ for (x = 0; x < NUM_INDIRECT_REGS; x++)
-+ if (!read_indreg_fxs(wc, port, x,
-+ &regs.indirect[x]))
-+ return -EIO;
-+ for (x = 0; x < NUM_REGS; x++)
-+ if (!read_reg_fxs(wc, port, x, &regs.direct[x]))
-+ return -EIO;
-+ } else {
-+ memset(&regs, 0, sizeof(regs));
-+ for (x = 0; x < NUM_FXO_REGS; x++) {
-+ if (!read_reg_fxo(wc, port, x, &regs.direct[x]))
-+ return -EIO;
-+ }
-+ }
-+ if (copy_to_user((void __user *)data, &regs, sizeof(regs)))
-+ return -EFAULT;
-+ break;
-+ case WCTDM_SET_REG:
-+ if (copy_from_user(&regop, (void __user *)data, sizeof(regop)))
-+ return -EFAULT;
-+ if (regop.indirect) {
-+ if (wc->porttype[port] != VT_PORT_PROSLIC)
-+ return -EINVAL;
-+ printk("Setting indirect %d to 0x%04x on %d\n",
-+ regop.reg, regop.val, chan->chanpos);
-+ if (!write_indreg_fxs(wc, port, regop.reg, regop.val))
-+ return -EIO;
-+ } else {
-+ regop.val &= 0xff;
-+ printk("Setting direct %d to %04x on %d\n",
-+ regop.reg, regop.val, chan->chanpos);
-+ if (wc->porttype[port] == VT_PORT_PROSLIC) {
-+ if (!write_reg_fxs(wc, port, regop.reg,
-+ regop.val))
-+ return -EIO;
-+ } else {
-+ if (!write_reg_fxo(wc, port, regop.reg,
-+ regop.val))
-+ return -EIO;
-+ }
-+ }
-+ break;
-+ case WCTDM_SET_ECHOTUNE:
-+ cardinfo(wc->boardnum, "Setting echo registers");
-+ if (copy_from_user(&echoregs, (void __user *)data, sizeof(echoregs)))
-+ return -EFAULT;
-+
-+ if (wc->porttype[port] == VT_PORT_VDAA) {
-+ /* Set the ACIM and digital echo canceller registers */
-+ if (!write_reg_fxo(wc, port, 30, echoregs.acim)
-+ || ! write_reg_fxo(wc, port, 45, echoregs.coef1)
-+ || ! write_reg_fxo(wc, port, 46, echoregs.coef2)
-+ || ! write_reg_fxo(wc, port, 47, echoregs.coef3)
-+ || ! write_reg_fxo(wc, port, 48, echoregs.coef4)
-+ || ! write_reg_fxo(wc, port, 49, echoregs.coef5)
-+ || ! write_reg_fxo(wc, port, 50, echoregs.coef6)
-+ || ! write_reg_fxo(wc, port, 51, echoregs.coef7)
-+ || ! write_reg_fxo(wc, port, 52, echoregs.coef8))
-+ {
-+ cardcrit(wc->boardnum, "Failed to set echo registers");
-+ return -EIO;
-+ }
-+ break;
-+ } else {
-+ return -EINVAL;
-+ }
-+ break;
-+ default:
-+ return -ENOTTY;
-+ }
-+ return 0;
-+}
-+
-+static int openpci_open(struct dahdi_chan *chan)
-+{
-+ struct openpci *wc = chan->pvt;
-+ if (!wc->porttype[chan->chanpos-1])
-+ return -ENODEV;
-+
-+ //XXX This is WRONG and can prang in a race. We must pass THIS_MODULE
-+ // as the owner of the span that holds the pointer to this function,
-+ // then bump the refcount in the dahdi code _BEFORE_ the potentially
-+ // fatal call to an invalid pointer is made.
-+ //if (wc->dead) return -ENODEV;
-+ //wc->usecount++;
-+ try_module_get(THIS_MODULE); //XXX
-+
-+ return 0;
-+}
-+
-+static inline struct openpci* openpci_from_span(struct dahdi_span *span) {
-+ return container_of(span, struct openpci, span);
-+}
-+
-+static int openpci_watchdog(struct dahdi_span *span, int event)
-+{
-+ info("TDM: Restarting DMA");
-+ restart_dma(openpci_from_span(span));
-+ return 0;
-+}
-+
-+static int openpci_close(struct dahdi_chan *chan)
-+{
-+ struct openpci *wc = chan->pvt;
-+ int port = chan->chanpos - 1;
-+
-+ //XXX wc->usecount--;
-+ //XXX This is WRONG and can prang in a race. We must pass THIS_MODULE
-+ // as the owner of the span that holds the pointer to this function,
-+ // then bump the refcount in the dahdi code _BEFORE_ the potentially
-+ // fatal call to an invalid pointer is made.
-+ module_put(THIS_MODULE);
-+ if (wc->porttype[port] == VT_PORT_PROSLIC) {
-+ if (reversepolarity)
-+ wc->mod[port].fxs.idletxhookstate = 5;
-+ else
-+ wc->mod[port].fxs.idletxhookstate = 1;
-+ }
-+ /* If we're dead, release us now */
-+ //XXX if (!wc->usecount && wc->dead) openpci_release(wc);
-+
-+ return 0;
-+}
-+
-+static int openpci_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
-+{
-+ struct openpci *wc = chan->pvt;
-+ int port = chan->chanpos - 1;
-+ int new_hk_state;
-+
-+ dbginfo(wc->boardnum, "Setting %s port %d hook state %s",
-+ wc->porttype[port] == VT_PORT_VDAA ? "FXO" : "FXS",
-+ port,
-+ txsig == 0 ? "ONHOOK" :
-+ txsig == 1 ? "OFFHOOK" :
-+ txsig == 2 ? "START" :
-+ txsig == 3 ? "KEWL" : "UNKNOWN" );
-+
-+ switch(wc->porttype[port]) {
-+ case VT_PORT_VDAA:
-+ switch(txsig) {
-+ case DAHDI_TXSIG_START:
-+ case DAHDI_TXSIG_OFFHOOK:
-+ if (write_reg_fxo(wc, port, 5, 0x9)
-+ && write_reg_fxo(wc, port, 0x20, 0x0))
-+ wc->mod[port].fxo.offhook = 1;
-+ else
-+ cardcrit(wc->boardnum,
-+ "Failed set fxo off-hook");
-+ break;
-+
-+ case DAHDI_TXSIG_ONHOOK:
-+ if (write_reg_fxo(wc, port, 5, 0x8)
-+ && write_reg_fxo(wc, port, 0x20, 0x3))
-+ wc->mod[port].fxo.offhook = 0;
-+ else
-+ cardcrit(wc->boardnum, "Failed set fxo on-hook");
-+ break;
-+
-+ default:
-+ cardcrit(wc->boardnum,
-+ "Can't set FXO port %d tx state to %d",
-+ port, txsig);
-+ }
-+ break;
-+
-+ case VT_PORT_PROSLIC:
-+ new_hk_state = wc->mod[port].fxs.lasttxhook;
-+ switch(txsig) {
-+ case DAHDI_TXSIG_ONHOOK:
-+ switch(chan->sig) {
-+ case DAHDI_SIG_EM:
-+ case DAHDI_SIG_FXOKS:
-+ case DAHDI_SIG_FXOLS:
-+ new_hk_state = wc->mod[port].fxs.idletxhookstate;
-+ break;
-+ case DAHDI_SIG_FXOGS:
-+ new_hk_state = 3;
-+ break;
-+ }
-+ break;
-+
-+ case DAHDI_TXSIG_OFFHOOK:
-+ switch(chan->sig) {
-+ case DAHDI_SIG_EM:
-+ new_hk_state = 5;
-+ break;
-+ default:
-+ new_hk_state = wc->mod[port].fxs.idletxhookstate;
-+ break;
-+ }
-+ break;
-+
-+ case DAHDI_TXSIG_START:
-+ new_hk_state = 4;
-+ break;
-+
-+ case DAHDI_TXSIG_KEWL:
-+ new_hk_state = 0;
-+ break;
-+
-+ default:
-+ cardinfo(wc->boardnum,
-+ "Can't set FXS port %d tx state to %d",
-+ port, txsig);
-+ }
-+ dbginfo(wc->boardnum, "%s port %d hook state old %d, new %d",
-+ wc->porttype[port] == VT_PORT_VDAA ? "FXO" : "FXS",
-+ port, wc->mod[port].fxs.lasttxhook, new_hk_state );
-+
-+ if (new_hk_state != wc->mod[port].fxs.lasttxhook) {
-+ if (write_reg_fxs(wc, port, 64, new_hk_state))
-+ wc->mod[port].fxs.lasttxhook = new_hk_state;
-+ else
-+ cardcrit(wc->boardnum,
-+ "Failed to set port %d fxs hookstate from %d to %d",
-+ port, wc->mod[port].fxs.lasttxhook,
-+ new_hk_state);
-+ }
-+ break;
-+
-+ default:
-+ cardcrit(wc->boardnum,
-+ "Unknown module type %d in openpci_hooksig",
-+ wc->porttype[port] );
-+ }
-+ return 0;
-+}
-+
-+static const struct dahdi_span_ops openpci_span_ops = {
-+ .owner = THIS_MODULE,
-+ .hooksig = openpci_hooksig,
-+ .open = openpci_open,
-+ .close = openpci_close,
-+ .ioctl = openpci_ioctl,
-+ .watchdog = openpci_watchdog
-+};
-+
-+static int span_initialize(struct openpci *wc)
-+{
-+ int x;
-+
-+ wc->ddev = dahdi_create_device();
-+ //XXX Set a THIS_MODULE as the owner of the span...
-+ /* Zapata stuff */
-+ sprintf(wc->span.name, "WCTDM/%d", wc->boardnum);
-+ sprintf(wc->span.desc, "%s Board %d", wc->variety, wc->boardnum + 1);
-+ wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d",
-+ wc->dev->bus->number,
-+ PCI_SLOT(wc->dev->devfn) + 1);
-+ if (!wc->ddev->location)
-+ return -ENOMEM;
-+ for (x = 0; x < MAX_PORTS; x++) {
-+ struct dahdi_chan *chan = &wc->_chans[x];
-+ wc->chans[x] = chan;
-+ sprintf(chan->name, "WCTDM/%d/%d", wc->boardnum, x);
-+ chan->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS
-+ | DAHDI_SIG_FXOGS | DAHDI_SIG_SF | DAHDI_SIG_EM
-+ | DAHDI_SIG_CLEAR;
-+ chan->sigcap |= DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS
-+ | DAHDI_SIG_SF | DAHDI_SIG_CLEAR;
-+ chan->chanpos = x+1;
-+ chan->pvt = wc;
-+ }
-+ wc->ddev->manufacturer = "Voicetronix";
-+ wc->ddev->devicetype = wc->variety;
-+ wc->span.deflaw = DAHDI_LAW_MULAW;
-+ wc->span.chans = wc->chans;
-+ wc->span.channels = MAX_PORTS;
-+ wc->span.flags = DAHDI_FLAG_RBS;
-+ wc->span.ops = &openpci_span_ops;
-+
-+ list_add_tail(&wc->span.device_node, &wc->ddev->spans);
-+ if (dahdi_register_device(wc->ddev, &wc->dev->dev)) {
-+ cardcrit(wc->boardnum, "Unable to register device with dahdi");
-+ return RET_FAIL;
-+ }
-+ return RET_OK;
-+}
-+
-+static int get_port_type(struct openpci *wc, int port)
-+{
-+ int i, type;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0x20, PIB(1)); HTXF_WAIT_LOCKED_RET(VT_PORT_EMPTY);
-+ outb(port, PIB(1)); HTXF_WAIT_LOCKED_RET(VT_PORT_EMPTY);
-+ HRXF_WAIT_LOCKED_RET(VT_PORT_EMPTY); type = inb(PIB(1));
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+
-+ return type;
-+}
-+
-+static int check_ports(struct openpci *wc)
-+{
-+ int i = 0;
-+
-+ wc->portcount = 0;
-+ for (; i < MAX_PORTS; ++i ) {
-+ wc->porttype[i] = get_port_type(wc, i);
-+ dbginfo(wc->boardnum,"%d: %s", i, porttype(wc,i));
-+
-+ switch( wc->porttype[i] ) {
-+ case VT_PORT_PROSLIC:
-+ /* By default, don't send on hook */
-+ if (reversepolarity)
-+ wc->mod[i].fxs.idletxhookstate = 5;
-+ else
-+ wc->mod[i].fxs.idletxhookstate = 1;
-+ /* FALLTHROUGH */
-+ case VT_PORT_VDAA:
-+ ++wc->portcount;
-+ }
-+ }
-+ /* we 'succeed' if any ports were discovered. */
-+ return wc->portcount ? RET_OK : RET_FAIL;
-+}
-+
-+static int configure_vdaa_country(struct openpci *wc, int port, char *name)
-+{
-+ unsigned char value;
-+ int i;
-+
-+ for (i = 0; i < sizeof(fxo_modes)/sizeof(struct fxo_mode); ++i) {
-+ if (!strcmp(fxo_modes[i].name, name)) {
-+ dbginfo(wc->boardnum, "%d: Setting country to %s",
-+ port, name);
-+ goto part2;
-+ }
-+ }
-+ i = 3;
-+ cardinfo(wc->boardnum, "Using default country %s", fxo_modes[i].name);
-+
-+part2:
-+ value = (fxo_modes[i].ohs << 6);
-+ value |= (fxo_modes[i].rz << 1);
-+ value |= (fxo_modes[i].rt << 0);
-+ if (!write_reg_fxo(wc, port, 16, value)) goto hell;
-+
-+ /* DC Termination Control - Register 26 */
-+ value = (fxo_modes[i].dcv << 6);
-+ value |= (fxo_modes[i].mini << 4);
-+ value |= (fxo_modes[i].ilim << 1);
-+ if (!write_reg_fxo(wc, port, 26, value)) goto hell;
-+
-+ /* AC Termination Control - Register 30 */
-+ value = (fxo_modes[i].acim << 0);
-+ if (!write_reg_fxo(wc, port, 30, value)) goto hell;
-+
-+ /* DAA Control 5 - Register 31 */
-+ msleep(1);
-+ if (!read_reg_fxo(wc, port, 31, &value)) goto hell;
-+
-+ value = (value & 0xf7) | (fxo_modes[i].ohs2 << 3);
-+ value = value | 0x02;
-+ if (! write_reg_fxo(wc, port, 31, value)) goto hell;
-+
-+ return RET_OK;
-+
-+hell:
-+ cardcrit(wc->boardnum, "port %d failed configure vdaa country", port);
-+ return RET_FAIL;
-+}
-+
-+/* Do not call this from an interrupt context, it may sleep. */
-+static void configure_vdaa_port(struct openpci *wc, int port)
-+{
-+ /* Set Country - default to Australia */
-+ if (configure_vdaa_country(wc, port, country))
-+ ++wc->portcount;
-+ else {
-+ cardcrit(wc->boardnum, "FAILED to configure vdaa port %d. Disabled.", port);
-+ wc->porttype[port] = VT_PORT_EMPTY;
-+ }
-+}
-+
-+static int configure_proslic_country(struct openpci *wc, int port,
-+ const char *name)
-+{
-+ int i;
-+
-+ for (i = 0; i < sizeof(ps_country_regs)/sizeof(struct ps_country_reg);
-+ ++i) {
-+ if (!strcmp(ps_country_regs[i].country, name)) {
-+ dbginfo(wc->boardnum, "%d: Setting country to %s",
-+ port, name);
-+ goto part2;
-+ }
-+ }
-+ return -EINVAL;
-+
-+part2:
-+
-+ if (!write_reg_fxs(wc, port, 10, ps_country_regs[i].value)) {
-+ cardcrit(wc->boardnum,"%d: failed to write PS_IMPEDANCE", port);
-+ return -EIO;
-+ }
-+ return 0;
-+}
-+
-+/* Do not call this from an interrupt context, it may sleep. */
-+static void configure_proslic_port(struct openpci *wc, int port)
-+{
-+ /* Set Country - default to Australia */
-+ switch (configure_proslic_country(wc, port, country)) {
-+ case 0:
-+ break;
-+
-+ case -EINVAL:
-+ cardwarn(wc->boardnum, "%d: Country '%s' unknown, using default",
-+ port, country);
-+ if (configure_proslic_country(wc, port,
-+ DEFAULT_COUNTRY) == 0 )
-+ goto hell;
-+
-+ default:
-+ goto hell;
-+ }
-+
-+ ++wc->portcount;
-+ return;
-+
-+hell:
-+ cardcrit(wc->boardnum, "FAILED to configure proslic port %d. Disabled.",
-+ port);
-+ wc->porttype[port] = VT_PORT_EMPTY;
-+}
-+
-+/* Do not call this from an interrupt context, it may (indirectly) sleep. */
-+static int configure_ports(struct openpci *wc)
-+{
-+ unsigned long flags;
-+ int i;
-+
-+ wc->portcount = 0;
-+ for (i = 0; i < MAX_PORTS; ++i) {
-+ switch (wc->porttype[i]) {
-+ case VT_PORT_VDAA: configure_vdaa_port(wc,i); break;
-+ case VT_PORT_PROSLIC: configure_proslic_port(wc,i); break;
-+ }
-+ }
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0x2c, PIB(1)); HTXF_WAIT_LOCKED();
-+ outb(0xff, PIB(1)); HTXF_WAIT_LOCKED();
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+
-+ /* otherwise we 'succeed' if any ports were configured successfully. */
-+ return wc->portcount ? RET_OK : RET_FAIL;
-+}
-+
-+static int __get_arm_id(struct openpci *wc, int field, char *value)
-+{
-+ int i;
-+ int x = 0;
-+ int count = 0;
-+
-+ outb(0x01, PIB(1)); HTXF_WAIT();
-+ outb(field, PIB(1)); HTXF_WAIT();
-+ HRXF_WAIT(); count = inb(PIB(1));
-+ if (count > ID_DATA_MAXSIZE) {
-+ cardcrit(wc->boardnum, "Too many bytes of id(%d) data %d/%d",
-+ field, count, ID_DATA_MAXSIZE);
-+ return RET_FAIL;
-+ }
-+ //cardinfo(wc->boardnum, "get_arm_id(%d): byte count %d",field,count);
-+ for (; x < count; ++x) {
-+ HRXF_WAIT(); *value = inb(PIB(1));
-+ //cardinfo(wc->boardnum, "get_arm_id(%d): byte %d => 0x%02x",field,x,tmp);
-+ ++value;
-+ }
-+ return RET_OK;
-+}
-+
-+static void enable_interrupts(struct openpci *wc)
-+{
-+ outb(0x3f, TJ_MASK0);
-+ outb(0x02, TJ_MASK1);
-+}
-+
-+static void disable_interrupts(struct openpci *wc)
-+{
-+ outb(0x00, TJ_MASK0);
-+ outb(0x00, TJ_MASK1);
-+}
-+
-+/* Do not call this from an interrupt context, it may sleep. */
-+static int check_arm(struct openpci *wc)
-+{
-+ char model[ID_DATA_MAXSIZE + 1] = { 0 };
-+ char date[ID_DATA_MAXSIZE + 1] = { 0 };
-+ unsigned long flags;
-+ int i = 0;
-+ int tmp = 0;
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ while ((tmp != 0x88) && (++i < 100)) {
-+ outb(0x88, PIB(0));
-+ msleep(1);
-+ tmp = inb(PIB(1));
-+ }
-+ if (i >= 1000)
-+ goto limbo;
-+ dbginfo(wc->boardnum, "Arm responded on attempt %d", i);
-+
-+ /* Flush out the queue if we sent several pings before a response. */
-+ if (i > 1)
-+ __ping_arm(wc);
-+
-+ if (!__get_arm_id(wc, 0, model))
-+ goto hell;
-+ sscanf(model, "OpenPCI8.%02d", &(wc->firmware));
-+ cardinfo(wc->boardnum, " model: %s", model);
-+
-+ if (!__get_arm_id(wc, 1, date))
-+ goto hell;
-+ cardinfo(wc->boardnum, " date: %s", date);
-+
-+ if (!__get_arm_id(wc, 2, wc->serial))
-+ goto hell;
-+ cardinfo(wc->boardnum, " serial: %s", wc->serial);
-+
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_OK;
-+
-+hell:
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ cardwarn(wc->boardnum, "Found ARM processor, dumb firmware.");
-+ return RET_OK;
-+
-+limbo:
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ return RET_FAIL;
-+}
-+
-+static int arm_monitor(struct openpci *wc, int on)
-+{
-+ int i;
-+ outb(on ? 0x06 : 0x07, PIB(1)); HTXF_WAIT();
-+ return RET_OK;
-+}
-+
-+static int __devinit openpci_probe_board(struct pci_dev *pdev,
-+ const struct pci_device_id *ent)
-+{
-+ struct openpci *wc;
-+ int boardnum = 0;
-+ int failret = -ENOMEM;
-+ int tmp = 0;
-+ int i;
-+ unsigned long flags;
-+
-+ if (ent->driver_data != (kernel_ulong_t)&wcopenpci) {
-+ info("Probe of non-OpenPCI card, ignoring.");
-+ return -EINVAL;
-+ }
-+ wc = kzalloc(sizeof(struct openpci), GFP_KERNEL);
-+ if (!wc)
-+ return -ENOMEM;
-+
-+ mutex_lock(&cards_mutex);
-+ for (; boardnum < MAX_CARDS && cards[boardnum]; ++boardnum)
-+ ;
-+ if (boardnum >= MAX_CARDS) {
-+ crit("Too many OpenPCI cards(%d), max is %d.",
-+ boardnum, MAX_CARDS);
-+ mutex_unlock(&cards_mutex);
-+ goto hell;
-+ }
-+ cards[boardnum] = wc;
-+ mutex_unlock(&cards_mutex);
-+
-+ spin_lock_init(&wc->lock);
-+ pci_set_drvdata(pdev, wc);
-+
-+ wc->boardnum = boardnum;
-+ wc->dev = pdev;
-+ wc->variety = wcopenpci;
-+
-+ cardinfo(boardnum, "Initialising card");
-+ if (pci_enable_device(pdev)) {
-+ failret = -EIO;
-+ goto hell_2;
-+ }
-+ wc->ioaddr = pci_resource_start(pdev, 0);
-+ if (!request_region(wc->ioaddr, 0xff, NAME)) {
-+ cardcrit(boardnum, "Failed to lock IO region, another driver already using it");
-+ failret = -EBUSY;
-+ goto hell_2;
-+ }
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0xff, TJ_AUXD); /* Set up TJ to access the ARM */
-+ outb(0x78, TJ_AUXC); /* Set up for Jtag */
-+ outb(0x00, TJ_CNTL); /* pull ERST low */
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ msleep(1); /* Wait a bit */
-+
-+ dbginfo(boardnum, "Starting ARM");
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0x01, TJ_CNTL); /* pull ERST high again */
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+ msleep(100); /* Give it all a chance to boot */
-+
-+ if (!check_arm(wc)) {
-+ cardcrit(boardnum, "Couldnt find ARM processor");
-+ failret = -EIO;
-+ goto hell_3;
-+ }
-+ if (wc->firmware < 11) {
-+ cardcrit(boardnum,
-+ "Firmware version %d not supported by this driver",
-+ wc->firmware);
-+ cardcrit(boardnum, " contact Voicetronix to have it updated");
-+ failret = -ENODEV;
-+ goto hell_3;
-+ }
-+ if (!check_ports(wc)) {
-+ cardcrit(boardnum, "Couldnt find ports!");
-+ failret = -EIO;
-+ goto hell_3;
-+ }
-+
-+ wc->writechunk = pci_alloc_consistent(pdev, VT_PCIDMA_BLOCKSIZE,
-+ &wc->writedma);
-+ if (!wc->writechunk) {
-+ cardcrit(boardnum, "Couldnt get DMA memory.");
-+ goto hell_3;
-+ }
-+ wc->readchunk = wc->writechunk + DAHDI_MAX_CHUNKSIZE *
-+ (MAX_PORTS * 2 / sizeof(int));
-+ wc->readdma = wc->writedma + DAHDI_MAX_CHUNKSIZE * (MAX_PORTS*2);
-+
-+ memset((void *)wc->writechunk, 0, VT_PCIDMA_BLOCKSIZE);
-+
-+ spin_lock_irqsave(&wc->lock, flags);
-+ outb(0xc1, TJ_SERCTL);
-+ outb(0x0, TJ_FSCDELAY);
-+
-+ outl(wc->writedma, TJ_DMAWS);
-+ outl(wc->writedma + VT_PCIDMA_MIDDLE, TJ_DMAWI);
-+ outl(wc->writedma + VT_PCIDMA_END, TJ_DMAWE);
-+ outl(wc->readdma, TJ_DMARS);
-+ outl(wc->readdma + VT_PCIDMA_MIDDLE, TJ_DMARI);
-+ outl(wc->readdma + VT_PCIDMA_END, TJ_DMARE);
-+
-+ /* Clear interrupts */
-+ outb(0xff, TJ_INTSTAT);
-+ spin_unlock_irqrestore(&wc->lock, flags);
-+
-+ if (!arm_monitor(wc, 1)) {
-+ cardcrit(boardnum, "failed to start arm monitoring");
-+ failret = -EIO;
-+ goto hell_4;
-+ }
-+ msleep(1000);
-+
-+ i = 0;
-+ while (tmp != 0x88 && ++i < 1000) {
-+ outb(0x88, PIB(0));
-+ msleep(250);
-+ tmp = inb(PIB(1));
-+ }
-+ if (i >= 1000) {
-+ cardcrit(boardnum, "FAILED to initialise board");
-+ goto hell_4;
-+ }
-+
-+ if (!check_ports(wc)) {
-+ cardcrit(boardnum, "FAILED to initialise ports");
-+ failret = -EIO;
-+ goto hell_4;
-+ }
-+ if (!configure_ports(wc)) {
-+ cardcrit(boardnum, "Failed to configure ports.");
-+ failret = -EIO;
-+ goto hell_4;
-+ }
-+ cardinfo(wc->boardnum, "have %d configured ports", wc->portcount);
-+
-+ if (!span_initialize(wc)) {
-+ cardcrit(boardnum, "Failed to register with dahdi driver");
-+ failret = -EFAULT;
-+ goto hell_4;
-+ }
-+
-+ /* Finalize signalling */
-+ for (i = 0; i < MAX_PORTS; ++i) {
-+ if (wc->porttype[i] == VT_PORT_VDAA)
-+ wc->chans[i]->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS
-+ | DAHDI_SIG_CLEAR | DAHDI_SIG_SF;
-+ else if (wc->porttype[i] == VT_PORT_PROSLIC)
-+ wc->chans[i]->sigcap = DAHDI_SIG_FXOKS | DAHDI_SIG_FXOLS
-+ | DAHDI_SIG_FXOGS | DAHDI_SIG_SF
-+ | DAHDI_SIG_CLEAR | DAHDI_SIG_EM;
-+ else if (wc->porttype[i])
-+ cardcrit(wc->boardnum, "Port %d has unknown type (%d)",
-+ i, wc->porttype[i]);
-+ }
-+
-+ /* Enable bus mastering */
-+ pci_set_master(pdev);
-+
-+ if (request_irq(pdev->irq, openpci_isr, IRQF_SHARED, NAME, wc)) {
-+ cardcrit(boardnum, "Cant get IRQ!");
-+ failret = -EIO;
-+ goto hell_5;
-+ }
-+ cardinfo(boardnum, "Got IRQ %d", pdev->irq);
-+
-+ enable_interrupts(wc);
-+ start_dma(wc);
-+
-+ cardinfo(boardnum, "Initialised card.");
-+ return 0;
-+
-+hell_5:
-+ dahdi_unregister_device(wc->ddev);
-+hell_4:
-+ if (wc->writechunk)
-+ pci_free_consistent(pdev, VT_PCIDMA_BLOCKSIZE,
-+ (void *)wc->writechunk, wc->writedma);
-+hell_3:
-+ outb(0x00, TJ_CNTL);
-+ release_region(wc->ioaddr, 0xff);
-+hell_2:
-+ cards[boardnum] = NULL;
-+hell:
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+ kfree(wc);
-+ return failret;
-+}
-+
-+static void __devexit openpci_remove_board(struct pci_dev *pdev)
-+{
-+ struct openpci *wc = pci_get_drvdata(pdev);
-+
-+ if (!wc)
-+ return;
-+
-+ arm_monitor(wc, 0);
-+
-+ /* Stop DMA */
-+ outb(0x00, TJ_OPER);
-+ disable_interrupts(wc);
-+
-+ //XXX Replace this usecount business...
-+ // and do this BEFORE we invalidate everything above...
-+ // check that we wont try to write to it in the meantime.
-+ /* Release span, possibly delayed */
-+ //XXX if (!wc->usecount) openpci_release(wc); else wc->dead = 1;
-+
-+ dahdi_unregister_device(wc->ddev);
-+ outb(0x00, TJ_CNTL);
-+
-+ pci_free_consistent(pdev, VT_PCIDMA_BLOCKSIZE,
-+ (void *)wc->writechunk, wc->writedma);
-+ free_irq(pdev->irq, wc);
-+
-+ release_region(wc->ioaddr, 0xff);
-+
-+ mutex_lock(&cards_mutex);
-+ cards[wc->boardnum] = NULL;
-+ mutex_unlock(&cards_mutex);
-+
-+ kfree(wc->ddev->location);
-+ dahdi_free_device(wc->ddev);
-+ kfree(wc);
-+ cardinfo(wc->boardnum, "Removed OpenPCI card.");
-+}
-+
-+static DEFINE_PCI_DEVICE_TABLE(openpci_pci_tbl) = {
-+ { 0xe159, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t) &wcopenpci },
-+ { 0 }
-+};
-+
-+MODULE_DEVICE_TABLE(pci, openpci_pci_tbl);
-+
-+static struct pci_driver openpci_driver = {
-+ .name = NAME,
-+ .probe = openpci_probe_board,
-+ .remove = __devexit_p(openpci_remove_board),
-+ .id_table = openpci_pci_tbl,
-+};
-+
-+static int __init openpci_init(void)
-+{
-+#ifdef __BIG_ENDIAN
-+ warn("No big endian support (yet)");
-+ return -ENODEV;
-+#endif
-+
-+ if (pci_register_driver(&openpci_driver))
-+ return -ENODEV;
-+
-+ info("Module loaded %s", debug ? "with debug enabled" : "");
-+ return 0;
-+}
-+
-+static void __exit openpci_cleanup(void)
-+{
-+ pci_unregister_driver(&openpci_driver);
-+ info("Module exit");
-+}
-+
-+module_init(openpci_init);
-+module_exit(openpci_cleanup);
-+
-+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_VERSION(DAHDI_VERSION);
-+MODULE_LICENSE("GPL");
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/zaphfc/base.c dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/base.c
---- dahdi-linux-2.7.0/drivers/dahdi/zaphfc/base.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/base.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,1720 @@
-+/*
-+ * zaphfc.c - Dahdi driver for HFC-S PCI A based ISDN BRI cards
-+ *
-+ * Dahdi rewrite in hardhdlc mode
-+ * Jose A. Deniz <odicha@hotmail.com>
-+ *
-+ * Copyright (C) 2009, Jose A. Deniz
-+ * Copyright (C) 2006, headiisue GmbH; Jens Wilke
-+ * Copyright (C) 2004 Daniele Orlandi
-+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
-+ *
-+ * Jens Wilke <jw_vzaphfc@headissue.com>
-+ *
-+ * Original author of this code is
-+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
-+ *
-+ * Major rewrite of the driver made by
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * This program is free software and may be modified and
-+ * distributed under the terms of the GNU Public License.
-+ *
-+ * Please read the README file for important infos.
-+ */
-+
-+#include <linux/spinlock.h>
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/sched.h>
-+#include <linux/proc_fs.h>
-+#include <linux/if_arp.h>
-+
-+#include <dahdi/kernel.h>
-+
-+#include "zaphfc.h"
-+#include "fifo.h"
-+
-+#ifdef CONFIG_PCI
-+
-+#define DAHDI_B1 0
-+#define DAHDI_B2 1
-+#define DAHDI_D 2
-+
-+#define D 0
-+#define B1 1
-+#define B2 2
-+
-+/*
-+ * Mode Te for all
-+ */
-+static int modes;
-+static int nt_modes[hfc_MAX_BOARDS];
-+static int nt_modes_count;
-+static int force_l1_up;
-+static struct proc_dir_entry *hfc_proc_zaphfc_dir;
-+
-+#ifdef DEBUG
-+int debug_level;
-+#endif
-+
-+#ifndef FALSE
-+#define FALSE 0
-+#endif
-+#ifndef TRUE
-+#define TRUE (!FALSE)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
-+#define SET_PROC_DIRENTRY_OWNER(p) do { (p)->owner = THIS_MODULE; } while (0);
-+#else
-+#define SET_PROC_DIRENTRY_OWNER(p) do { } while (0);
-+#endif
-+
-+static struct pci_device_id hfc_pci_ids[] = {
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_3069,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-+ {0,}
-+};
-+
-+MODULE_DEVICE_TABLE(pci, hfc_pci_ids);
-+
-+static int __devinit hfc_probe(struct pci_dev *dev
-+ , const struct pci_device_id *ent);
-+static void __devexit hfc_remove(struct pci_dev *dev);
-+
-+static struct pci_driver hfc_driver = {
-+ .name = hfc_DRIVER_NAME,
-+ .id_table = hfc_pci_ids,
-+ .probe = hfc_probe,
-+ .remove = hfc_remove,
-+};
-+
-+/******************************************
-+ * HW routines
-+ ******************************************/
-+
-+static void hfc_softreset(struct hfc_card *card)
-+{
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "resetting\n",
-+ card->cardnum);
-+
-+/*
-+ * Softreset procedure. Put it on, wait and off again
-+ */
-+ hfc_outb(card, hfc_CIRM, hfc_CIRM_RESET);
-+ udelay(6);
-+ hfc_outb(card, hfc_CIRM, 0);
-+
-+ set_current_state(TASK_UNINTERRUPTIBLE);
-+ schedule_timeout((hfc_RESET_DELAY * HZ) / 1000);
-+}
-+
-+static void hfc_resetCard(struct hfc_card *card)
-+{
-+ card->regs.m1 = 0;
-+ hfc_outb(card, hfc_INT_M1, card->regs.m1);
-+
-+ card->regs.m2 = 0;
-+ hfc_outb(card, hfc_INT_M2, card->regs.m2);
-+
-+ hfc_softreset(card);
-+
-+ card->regs.trm = 0;
-+ hfc_outb(card, hfc_TRM, card->regs.trm);
-+
-+ /*
-+ * Select the non-capacitive line mode for the S/T interface
-+ */
-+ card->regs.sctrl = hfc_SCTRL_NONE_CAP;
-+
-+ if (card->nt_mode) {
-+ /*
-+ * ST-Bit delay for NT-Mode
-+ */
-+ hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_NT);
-+
-+ card->regs.sctrl |= hfc_SCTRL_MODE_NT;
-+ } else {
-+ /*
-+ * ST-Bit delay for TE-Mode
-+ */
-+ hfc_outb(card, hfc_CLKDEL, hfc_CLKDEL_TE);
-+
-+ card->regs.sctrl |= hfc_SCTRL_MODE_TE;
-+ }
-+
-+ hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
-+
-+ /*
-+ * S/T Auto awake
-+ */
-+ card->regs.sctrl_e = hfc_SCTRL_E_AUTO_AWAKE;
-+ hfc_outb(card, hfc_SCTRL_E, card->regs.sctrl_e);
-+
-+ /*
-+ * No B-channel enabled at startup
-+ */
-+ card->regs.sctrl_r = 0;
-+ hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
-+
-+ /*
-+ * HFC Master Mode
-+ */
-+ hfc_outb(card, hfc_MST_MODE, hfc_MST_MODE_MASTER);
-+
-+ /*
-+ * Connect internal blocks
-+ */
-+ card->regs.connect =
-+ hfc_CONNECT_B1_HFC_from_ST |
-+ hfc_CONNECT_B1_ST_from_HFC |
-+ hfc_CONNECT_B1_GCI_from_HFC |
-+ hfc_CONNECT_B2_HFC_from_ST |
-+ hfc_CONNECT_B2_ST_from_HFC |
-+ hfc_CONNECT_B2_GCI_from_HFC;
-+ hfc_outb(card, hfc_CONNECT, card->regs.connect);
-+
-+ /*
-+ * All bchans are HDLC by default, not useful, actually
-+ * since mode is set during open()
-+ */
-+ hfc_outb(card, hfc_CTMT, 0);
-+
-+ /*
-+ * bit order
-+ */
-+ hfc_outb(card, hfc_CIRM, 0);
-+
-+ /*
-+ * Enable D-rx FIFO. At least one FIFO must be enabled (by specs)
-+ */
-+ card->regs.fifo_en = hfc_FIFOEN_DRX;
-+ hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en);
-+
-+ card->late_irqs = 0;
-+
-+ /*
-+ * Clear already pending ints
-+ */
-+ hfc_inb(card, hfc_INT_S1);
-+ hfc_inb(card, hfc_INT_S2);
-+
-+ /*
-+ * Enable IRQ output
-+ */
-+ card->regs.m1 = hfc_INTS_DREC | hfc_INTS_L1STATE | hfc_INTS_TIMER;
-+ hfc_outb(card, hfc_INT_M1, card->regs.m1);
-+
-+ card->regs.m2 = hfc_M2_IRQ_ENABLE;
-+ hfc_outb(card, hfc_INT_M2, card->regs.m2);
-+
-+ /*
-+ * Unlocks the states machine
-+ */
-+ hfc_outb(card, hfc_STATES, 0);
-+
-+ /*
-+ * There's no need to explicitly activate L1 now.
-+ * Activation is managed inside the interrupt routine.
-+ */
-+}
-+
-+static void hfc_update_fifo_state(struct hfc_card *card)
-+{
-+ /*
-+ * I'm not sure if irqsave is needed but there could be a race
-+ * condition since hfc_update_fifo_state could be called from
-+ * both the IRQ handler and the *_(open|close) functions
-+ */
-+
-+ unsigned long flags;
-+ spin_lock_irqsave(&card->chans[B1].lock, flags);
-+ if (!card->fifo_suspended &&
-+ (card->chans[B1].status == open_framed ||
-+ card->chans[B1].status == open_voice)) {
-+
-+ if (!(card->regs.fifo_en & hfc_FIFOEN_B1RX)) {
-+ card->regs.fifo_en |= hfc_FIFOEN_B1RX;
-+ hfc_clear_fifo_rx(&card->chans[B1].rx);
-+ }
-+
-+ if (!(card->regs.fifo_en & hfc_FIFOEN_B1TX)) {
-+ card->regs.fifo_en |= hfc_FIFOEN_B1TX;
-+ hfc_clear_fifo_tx(&card->chans[B1].tx);
-+ }
-+ } else {
-+ if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
-+ card->regs.fifo_en &= ~hfc_FIFOEN_B1RX;
-+ if (card->regs.fifo_en & hfc_FIFOEN_B1TX)
-+ card->regs.fifo_en &= ~hfc_FIFOEN_B1TX;
-+ }
-+ spin_unlock_irqrestore(&card->chans[B1].lock, flags);
-+
-+ spin_lock_irqsave(&card->chans[B2].lock, flags);
-+ if (!card->fifo_suspended &&
-+ (card->chans[B2].status == open_framed ||
-+ card->chans[B2].status == open_voice ||
-+ card->chans[B2].status == sniff_aux)) {
-+
-+ if (!(card->regs.fifo_en & hfc_FIFOEN_B2RX)) {
-+ card->regs.fifo_en |= hfc_FIFOEN_B2RX;
-+ hfc_clear_fifo_rx(&card->chans[B2].rx);
-+ }
-+
-+ if (!(card->regs.fifo_en & hfc_FIFOEN_B2TX)) {
-+ card->regs.fifo_en |= hfc_FIFOEN_B2TX;
-+ hfc_clear_fifo_tx(&card->chans[B2].tx);
-+ }
-+ } else {
-+ if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
-+ card->regs.fifo_en &= ~hfc_FIFOEN_B2RX;
-+ if (card->regs.fifo_en & hfc_FIFOEN_B2TX)
-+ card->regs.fifo_en &= ~hfc_FIFOEN_B2TX;
-+ }
-+ spin_unlock_irqrestore(&card->chans[B2].lock, flags);
-+
-+ spin_lock_irqsave(&card->chans[D].lock, flags);
-+ if (!card->fifo_suspended &&
-+ card->chans[D].status == open_framed) {
-+
-+ if (!(card->regs.fifo_en & hfc_FIFOEN_DTX)) {
-+ card->regs.fifo_en |= hfc_FIFOEN_DTX;
-+
-+ card->chans[D].tx.ugly_framebuf_size = 0;
-+ card->chans[D].tx.ugly_framebuf_off = 0;
-+ }
-+ } else {
-+ if (card->regs.fifo_en & hfc_FIFOEN_DTX)
-+ card->regs.fifo_en &= ~hfc_FIFOEN_DTX;
-+ }
-+ spin_unlock_irqrestore(&card->chans[D].lock, flags);
-+
-+ hfc_outb(card, hfc_FIFO_EN, card->regs.fifo_en);
-+}
-+
-+static inline void hfc_suspend_fifo(struct hfc_card *card)
-+{
-+ card->fifo_suspended = TRUE;
-+
-+ hfc_update_fifo_state(card);
-+
-+ /*
-+ * When L1 goes down D rx receives garbage; it is nice to
-+ * clear it to avoid a CRC error on reactivation
-+ * udelay is needed because the FIFO deactivation happens
-+ * in 250us
-+ */
-+ udelay(250);
-+ hfc_clear_fifo_rx(&card->chans[D].rx);
-+
-+#ifdef DEBUG
-+ if (debug_level >= 3) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "FIFOs suspended\n",
-+ card->cardnum);
-+ }
-+#endif
-+}
-+
-+static inline void hfc_resume_fifo(struct hfc_card *card)
-+{
-+ card->fifo_suspended = FALSE;
-+
-+ hfc_update_fifo_state(card);
-+
-+#ifdef DEBUG
-+ if (debug_level >= 3) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "FIFOs resumed\n",
-+ card->cardnum);
-+ }
-+#endif
-+}
-+
-+static void hfc_check_l1_up(struct hfc_card *card)
-+{
-+ if ((!card->nt_mode && card->l1_state != 7)
-+ || (card->nt_mode && card->l1_state != 3)) {
-+
-+ hfc_outb(card, hfc_STATES, hfc_STATES_DO_ACTION |
-+ hfc_STATES_ACTIVATE|
-+ hfc_STATES_NT_G2_G3);
-+
-+ /*
-+ * 0 because this is quite verbose when an inferface is unconnected, jaw
-+ */
-+#if 0
-+ if (debug_level >= 1) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "L1 is down, bringing up L1.\n",
-+ card->cardnum);
-+ }
-+#endif
-+ }
-+}
-+
-+
-+/*******************
-+ * Dahdi interface *
-+ *******************/
-+
-+static int hfc_zap_open(struct dahdi_chan *zaptel_chan)
-+{
-+ struct hfc_chan_duplex *chan = zaptel_chan->pvt;
-+ struct hfc_card *card = chan->card;
-+
-+ spin_lock(&chan->lock);
-+
-+ switch (chan->number) {
-+ case D:
-+ if (chan->status != free &&
-+ chan->status != open_framed) {
-+ spin_unlock(&chan->lock);
-+ return -EBUSY;
-+ }
-+ chan->status = open_framed;
-+ break;
-+
-+ case B1:
-+ case B2:
-+ if (chan->status != free) {
-+ spin_unlock(&chan->lock);
-+ return -EBUSY;
-+ }
-+ chan->status = open_voice;
-+ break;
-+ }
-+
-+ chan->open_by_zaptel = TRUE;
-+ try_module_get(THIS_MODULE);
-+ spin_unlock(&chan->lock);
-+
-+ switch (chan->number) {
-+ case D:
-+ break;
-+
-+ case B1:
-+ card->regs.m2 |= hfc_M2_PROC_TRANS;
-+ /*
-+ * Enable transparent mode
-+ */
-+ card->regs.ctmt |= hfc_CTMT_TRANSB1;
-+ /*
-+ * Reversed bit order
-+ */
-+ card->regs.cirm |= hfc_CIRM_B1_REV;
-+ /*
-+ * Enable transmission
-+ */
-+ card->regs.sctrl |= hfc_SCTRL_B1_ENA;
-+ /*
-+ * Enable reception
-+ */
-+ card->regs.sctrl_r |= hfc_SCTRL_R_B1_ENA;
-+ break;
-+
-+ case B2:
-+ card->regs.m2 |= hfc_M2_PROC_TRANS;
-+ card->regs.ctmt |= hfc_CTMT_TRANSB2;
-+ card->regs.cirm |= hfc_CIRM_B2_REV;
-+ card->regs.sctrl |= hfc_SCTRL_B2_ENA;
-+ card->regs.sctrl_r |= hfc_SCTRL_R_B2_ENA;
-+ break;
-+
-+ }
-+
-+ /*
-+ * If not already enabled, enable processing transition (8KHz)
-+ * interrupt
-+ */
-+ hfc_outb(card, hfc_INT_M2, card->regs.m2);
-+ hfc_outb(card, hfc_CTMT, card->regs.ctmt);
-+ hfc_outb(card, hfc_CIRM, card->regs.cirm);
-+ hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
-+ hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
-+
-+ hfc_update_fifo_state(card);
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s opened as %s.\n",
-+ card->cardnum,
-+ chan->name,
-+ zaptel_chan->name);
-+
-+ return 0;
-+}
-+
-+static int hfc_zap_close(struct dahdi_chan *zaptel_chan)
-+{
-+ struct hfc_chan_duplex *chan = zaptel_chan->pvt;
-+ struct hfc_card *card = chan->card;
-+
-+ if (!card) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "hfc_zap_close called with NULL card\n");
-+ return -1;
-+ }
-+
-+ spin_lock(&chan->lock);
-+
-+ if (chan->status == free) {
-+ spin_unlock(&chan->lock);
-+ return -EINVAL;
-+ }
-+
-+ chan->status = free;
-+ chan->open_by_zaptel = FALSE;
-+
-+ spin_unlock(&chan->lock);
-+
-+ switch (chan->number) {
-+ case D:
-+ break;
-+
-+ case B1:
-+ card->regs.ctmt &= ~hfc_CTMT_TRANSB1;
-+ card->regs.cirm &= ~hfc_CIRM_B1_REV;
-+ card->regs.sctrl &= ~hfc_SCTRL_B1_ENA;
-+ card->regs.sctrl_r &= ~hfc_SCTRL_R_B1_ENA;
-+ break;
-+
-+ case B2:
-+ card->regs.ctmt &= ~hfc_CTMT_TRANSB2;
-+ card->regs.cirm &= ~hfc_CIRM_B2_REV;
-+ card->regs.sctrl &= ~hfc_SCTRL_B2_ENA;
-+ card->regs.sctrl_r &= ~hfc_SCTRL_R_B2_ENA;
-+ break;
-+ }
-+
-+ if (card->chans[B1].status == free &&
-+ card->chans[B2].status == free)
-+ card->regs.m2 &= ~hfc_M2_PROC_TRANS;
-+
-+ hfc_outb(card, hfc_INT_M2, card->regs.m2);
-+ hfc_outb(card, hfc_CTMT, card->regs.ctmt);
-+ hfc_outb(card, hfc_CIRM, card->regs.cirm);
-+ hfc_outb(card, hfc_SCTRL, card->regs.sctrl);
-+ hfc_outb(card, hfc_SCTRL_R, card->regs.sctrl_r);
-+
-+ hfc_update_fifo_state(card);
-+
-+ module_put(THIS_MODULE);
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s closed as %s.\n",
-+ card->cardnum,
-+ chan->name,
-+ zaptel_chan->name);
-+
-+ return 0;
-+}
-+
-+static int hfc_zap_rbsbits(struct dahdi_chan *chan, int bits)
-+{
-+ return 0;
-+}
-+
-+static int hfc_zap_ioctl(struct dahdi_chan *chan,
-+ unsigned int cmd, unsigned long data)
-+{
-+ switch (cmd) {
-+
-+ default:
-+ return -ENOTTY;
-+ }
-+
-+ return 0;
-+}
-+
-+static void hfc_hdlc_hard_xmit(struct dahdi_chan *d_chan)
-+{
-+ struct hfc_chan_duplex *chan = d_chan->pvt;
-+ struct hfc_card *card = chan->card;
-+ struct dahdi_hfc *hfccard = card->ztdev;
-+
-+ atomic_inc(&hfccard->hdlc_pending);
-+
-+}
-+
-+static int hfc_zap_startup(struct file *file, struct dahdi_span *span)
-+{
-+ struct dahdi_hfc *zthfc = dahdi_hfc_from_span(span);
-+ struct hfc_card *hfctmp = zthfc->card;
-+ int alreadyrunning;
-+
-+ if (!hfctmp) {
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "no card for span at startup!\n",
-+ hfctmp->cardnum);
-+ }
-+
-+ alreadyrunning = span->flags & DAHDI_FLAG_RUNNING;
-+
-+ if (!alreadyrunning)
-+ span->flags |= DAHDI_FLAG_RUNNING;
-+
-+ return 0;
-+}
-+
-+static int hfc_zap_shutdown(struct dahdi_span *span)
-+{
-+ return 0;
-+}
-+
-+static int hfc_zap_maint(struct dahdi_span *span, int cmd)
-+{
-+ return 0;
-+}
-+
-+static int hfc_zap_chanconfig(struct file *file, struct dahdi_chan *d_chan,
-+ int sigtype)
-+{
-+ struct hfc_chan_duplex *chan = d_chan->pvt;
-+ struct hfc_card *card = chan->card;
-+ struct dahdi_hfc *hfccard = card->ztdev;
-+
-+ if ((sigtype == DAHDI_SIG_HARDHDLC) && (hfccard->sigchan == d_chan)) {
-+ hfccard->sigactive = 0;
-+ atomic_set(&hfccard->hdlc_pending, 0);
-+ }
-+
-+ return 0;
-+}
-+
-+static int hfc_zap_spanconfig(struct file *file, struct dahdi_span *span,
-+ struct dahdi_lineconfig *lc)
-+{
-+ span->lineconfig = lc->lineconfig;
-+
-+ return 0;
-+}
-+
-+static const struct dahdi_span_ops hfc_zap_span_ops = {
-+ .owner = THIS_MODULE,
-+ .chanconfig = hfc_zap_chanconfig,
-+ .spanconfig = hfc_zap_spanconfig,
-+ .startup = hfc_zap_startup,
-+ .shutdown = hfc_zap_shutdown,
-+ .maint = hfc_zap_maint,
-+ .rbsbits = hfc_zap_rbsbits,
-+ .open = hfc_zap_open,
-+ .close = hfc_zap_close,
-+ .ioctl = hfc_zap_ioctl,
-+ .hdlc_hard_xmit = hfc_hdlc_hard_xmit
-+};
-+
-+static int hfc_zap_initialize(struct dahdi_hfc *hfccard)
-+{
-+ struct hfc_card *hfctmp = hfccard->card;
-+ int i;
-+
-+ hfccard->ddev = dahdi_create_device();
-+ hfccard->ddev->manufacturer = "Cologne Chips";
-+ hfccard->ddev->devicetype = "HFC-S PCI-A ISDN";
-+ hfccard->ddev->location = kasprintf(GFP_KERNEL,
-+ "PCI Bus %02d Slot %02d",
-+ hfctmp->pcidev->bus->number,
-+ PCI_SLOT(hfctmp->pcidev->devfn) + 1);
-+ memset(&hfccard->span, 0x0, sizeof(struct dahdi_span));
-+ sprintf(hfccard->span.name, "ZTHFC%d", hfctmp->cardnum + 1);
-+ sprintf(hfccard->span.desc,
-+ "HFC-S PCI A ISDN card %d [%s] ",
-+ hfctmp->cardnum,
-+ hfctmp->nt_mode ? "NT" : "TE");
-+ hfccard->span.spantype = hfctmp->nt_mode ? SPANTYPE_DIGITAL_BRI_NT :
-+ SPANTYPE_DIGITAL_BRI_TE;
-+ hfccard->span.flags = 0;
-+ hfccard->span.ops = &hfc_zap_span_ops;
-+ hfccard->span.chans = hfccard->_chans;
-+ hfccard->span.channels = 3;
-+ for (i = 0; i < hfccard->span.channels; i++)
-+ hfccard->_chans[i] = &hfccard->chans[i];
-+ hfccard->span.deflaw = DAHDI_LAW_ALAW;
-+ hfccard->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS;
-+ hfccard->span.offset = 0;
-+
-+ for (i = 0; i < hfccard->span.channels; i++) {
-+ memset(&hfccard->chans[i], 0x0, sizeof(struct dahdi_chan));
-+
-+ sprintf(hfccard->chans[i].name,
-+ "ZTHFC%d/%d/%d",
-+ hfctmp->cardnum + 1, 0, i + 1);
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "registered %s\n",
-+ hfctmp->cardnum,
-+ hfccard->chans[i].name);
-+
-+ if (i == hfccard->span.channels - 1) {
-+ hfccard->chans[i].sigcap = DAHDI_SIG_HARDHDLC;
-+ hfccard->sigchan = &hfccard->chans[DAHDI_D];
-+ hfccard->sigactive = 0;
-+ atomic_set(&hfccard->hdlc_pending, 0);
-+ } else {
-+ hfccard->chans[i].sigcap =
-+ DAHDI_SIG_CLEAR | DAHDI_SIG_DACS;
-+ }
-+
-+ hfccard->chans[i].chanpos = i + 1;
-+ }
-+
-+ hfccard->chans[DAHDI_D].readchunk =
-+ hfctmp->chans[D].rx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_D].writechunk =
-+ hfctmp->chans[D].tx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_D].pvt = &hfctmp->chans[D];
-+
-+ hfccard->chans[DAHDI_B1].readchunk =
-+ hfctmp->chans[B1].rx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_B1].writechunk =
-+ hfctmp->chans[B1].tx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_B1].pvt = &hfctmp->chans[B1];
-+
-+ hfccard->chans[DAHDI_B2].readchunk =
-+ hfctmp->chans[B2].rx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_B2].writechunk =
-+ hfctmp->chans[B2].tx.zaptel_buffer;
-+
-+ hfccard->chans[DAHDI_B2].pvt = &hfctmp->chans[B2];
-+
-+ list_add_tail(&hfccard->span.device_node, &hfccard->ddev->spans);
-+ if (dahdi_register_device(hfccard->ddev, &hfctmp->pcidev->dev)) {
-+ printk(KERN_ERR "unable to register DAHDI device %s!\n",
-+ hfccard->span.name);
-+ return -1; /* FIXME: release resources? */
-+ }
-+
-+ return 0;
-+}
-+
-+static void hfc_dahdi_free(struct dahdi_hfc *hfccard)
-+{
-+ kfree(hfccard->ddev->location);
-+ dahdi_free_device(hfccard->ddev);
-+}
-+
-+static void hfc_zap_transmit(struct hfc_chan_simplex *chan)
-+{
-+ hfc_fifo_put(chan, chan->zaptel_buffer, DAHDI_CHUNKSIZE);
-+}
-+
-+static void hfc_zap_receive(struct hfc_chan_simplex *chan)
-+{
-+ hfc_fifo_get(chan, chan->zaptel_buffer, DAHDI_CHUNKSIZE);
-+}
-+
-+/******************************************
-+ * Interrupt Handler
-+ ******************************************/
-+
-+static void hfc_handle_timer_interrupt(struct hfc_card *card);
-+static void hfc_handle_state_interrupt(struct hfc_card *card);
-+static void hfc_handle_processing_interrupt(struct hfc_card *card);
-+static void hfc_frame_arrived(struct hfc_chan_duplex *chan);
-+static void hfc_handle_voice(struct hfc_card *card);
-+
-+#if (KERNEL_VERSION(2, 6, 24) < LINUX_VERSION_CODE)
-+static irqreturn_t hfc_interrupt(int irq, void *dev_id)
-+#else
-+static irqreturn_t hfc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+#endif
-+{
-+ struct hfc_card *card = dev_id;
-+ unsigned long flags;
-+ u8 status, s1, s2;
-+
-+ if (!card) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "spurious interrupt (IRQ %d)\n",
-+ irq);
-+ return IRQ_NONE;
-+ }
-+
-+ spin_lock_irqsave(&card->lock, flags);
-+ status = hfc_inb(card, hfc_STATUS);
-+ if (!(status & hfc_STATUS_ANYINT)) {
-+ /*
-+ * maybe we are sharing the irq
-+ */
-+ spin_unlock_irqrestore(&card->lock, flags);
-+ return IRQ_NONE;
-+ }
-+
-+ /* We used to ingore the IRQ when the card was in processing
-+ * state but apparently there is no restriction to access the
-+ * card in such state:
-+ *
-+ * Joerg Ciesielski wrote:
-+ * > There is no restriction for the IRQ handler to access
-+ * > HFC-S PCI during processing phase. A IRQ latency of 375 us
-+ * > is also no problem since there are no interrupt sources in
-+ * > HFC-S PCI which must be handled very fast.
-+ * > Due to its deep fifos the IRQ latency can be several ms with
-+ * > out the risk of loosing data. Even the S/T state interrupts
-+ * > must not be handled with a latency less than <5ms.
-+ * >
-+ * > The processing phase only indicates that HFC-S PCI is
-+ * > processing the Fifos as PCI master so that data is read and
-+ * > written in the 32k memory window. But there is no restriction
-+ * > to access data in the memory window during this time.
-+ *
-+ * // if (status & hfc_STATUS_PCI_PROC) {
-+ * // return IRQ_HANDLED;
-+ * // }
-+ */
-+
-+ s1 = hfc_inb(card, hfc_INT_S1);
-+ s2 = hfc_inb(card, hfc_INT_S2);
-+
-+ if (s1 != 0) {
-+ if (s1 & hfc_INTS_TIMER) {
-+ /*
-+ * timer (bit 7)
-+ */
-+ hfc_handle_timer_interrupt(card);
-+ }
-+
-+ if (s1 & hfc_INTS_L1STATE) {
-+ /*
-+ * state machine (bit 6)
-+ */
-+ hfc_handle_state_interrupt(card);
-+ }
-+
-+ if (s1 & hfc_INTS_DREC) {
-+ /*
-+ * D chan RX (bit 5)
-+ */
-+ hfc_frame_arrived(&card->chans[D]);
-+ }
-+
-+ if (s1 & hfc_INTS_B1REC) {
-+ /*
-+ * B1 chan RX (bit 3)
-+ */
-+ hfc_frame_arrived(&card->chans[B1]);
-+ }
-+
-+ if (s1 & hfc_INTS_B2REC) {
-+ /*
-+ * B2 chan RX (bit 4)
-+ */
-+ hfc_frame_arrived(&card->chans[B2]);
-+ }
-+
-+ if (s1 & hfc_INTS_DTRANS) {
-+ /*
-+ * D chan TX (bit 2)
-+ */
-+ }
-+
-+ if (s1 & hfc_INTS_B1TRANS) {
-+ /*
-+ * B1 chan TX (bit 0)
-+ */
-+ }
-+
-+ if (s1 & hfc_INTS_B2TRANS) {
-+ /*
-+ * B2 chan TX (bit 1)
-+ */
-+ }
-+
-+ }
-+
-+ if (s2 != 0) {
-+ if (s2 & hfc_M2_PMESEL) {
-+ /*
-+ * kaboom irq (bit 7)
-+ *
-+ * CologneChip says:
-+ *
-+ * the meaning of this fatal error bit is that HFC-S
-+ * PCI as PCI master could not access the PCI bus
-+ * within 125us to finish its data processing. If this
-+ * happens only very seldom it does not cause big
-+ * problems but of course some B-channel or D-channel
-+ * data will be corrupted due to this event.
-+ *
-+ * Unfortunately this bit is only set once after the
-+ * problem occurs and can only be reseted by a
-+ * software reset. That means it is not easily
-+ * possible to check how often this fatal error
-+ * happens.
-+ *
-+ */
-+
-+ if (!card->sync_loss_reported) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "sync lost, pci performance too low!\n",
-+ card->cardnum);
-+
-+ card->sync_loss_reported = TRUE;
-+ }
-+ }
-+
-+ if (s2 & hfc_M2_GCI_MON_REC) {
-+ /*
-+ * RxR monitor channel (bit 2)
-+ */
-+ }
-+
-+ if (s2 & hfc_M2_GCI_I_CHG) {
-+ /*
-+ * GCI I-change (bit 1)
-+ */
-+ }
-+
-+ if (s2 & hfc_M2_PROC_TRANS) {
-+ /*
-+ * processing/non-processing transition (bit 0)
-+ */
-+ hfc_handle_processing_interrupt(card);
-+ }
-+
-+ }
-+
-+ spin_unlock_irqrestore(&card->lock, flags);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void hfc_handle_timer_interrupt(struct hfc_card *card)
-+{
-+ if (card->ignore_first_timer_interrupt) {
-+ card->ignore_first_timer_interrupt = FALSE;
-+ return;
-+ }
-+
-+ if ((card->nt_mode && card->l1_state == 3) ||
-+ (!card->nt_mode && card->l1_state == 7)) {
-+
-+ card->regs.ctmt &= ~hfc_CTMT_TIMER_MASK;
-+ hfc_outb(card, hfc_CTMT, card->regs.ctmt);
-+
-+ hfc_resume_fifo(card);
-+ }
-+}
-+
-+static void hfc_handle_state_interrupt(struct hfc_card *card)
-+{
-+ u8 new_state = hfc_inb(card, hfc_STATES) & hfc_STATES_STATE_MASK;
-+
-+#ifdef DEBUG
-+ if (debug_level >= 1) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "layer 1 state = %c%d\n",
-+ card->cardnum,
-+ card->nt_mode ? 'G' : 'F',
-+ new_state);
-+ }
-+#endif
-+
-+ if (card->nt_mode) {
-+ /*
-+ * NT mode
-+ */
-+
-+ if (new_state == 3) {
-+ /*
-+ * fix to G3 state (see specs)
-+ */
-+ hfc_outb(card, hfc_STATES, hfc_STATES_LOAD_STATE | 3);
-+ }
-+
-+ if (new_state == 3 && card->l1_state != 3)
-+ hfc_resume_fifo(card);
-+
-+ if (new_state != 3 && card->l1_state == 3)
-+ hfc_suspend_fifo(card);
-+
-+ } else {
-+ if (new_state == 3) {
-+ /*
-+ * Keep L1 up... zaptel & libpri expects
-+ * a always up L1...
-+ * Enable only when using an unpatched libpri
-+ */
-+
-+ if (force_l1_up) {
-+ hfc_outb(card, hfc_STATES,
-+ hfc_STATES_DO_ACTION |
-+ hfc_STATES_ACTIVATE|
-+ hfc_STATES_NT_G2_G3);
-+ }
-+ }
-+
-+ if (new_state == 7 && card->l1_state != 7) {
-+ /*
-+ * TE is now active, schedule FIFO activation after
-+ * some time, otherwise the first frames are lost
-+ */
-+
-+ card->regs.ctmt |= hfc_CTMT_TIMER_50 |
-+ hfc_CTMT_TIMER_CLEAR;
-+ hfc_outb(card, hfc_CTMT, card->regs.ctmt);
-+
-+ /*
-+ * Activating the timer firest an
-+ * interrupt immediately, we
-+ * obviously need to ignore it
-+ */
-+ card->ignore_first_timer_interrupt = TRUE;
-+ }
-+
-+ if (new_state != 7 && card->l1_state == 7) {
-+ /*
-+ * TE has become inactive, disable FIFO
-+ */
-+ hfc_suspend_fifo(card);
-+ }
-+ }
-+
-+ card->l1_state = new_state;
-+}
-+
-+static void hfc_handle_processing_interrupt(struct hfc_card *card)
-+{
-+ int available_bytes = 0;
-+
-+ /*
-+ * Synchronize with the first enabled channel
-+ */
-+ if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
-+ available_bytes = hfc_fifo_used_rx(&card->chans[B1].rx);
-+ if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
-+ available_bytes = hfc_fifo_used_rx(&card->chans[B2].rx);
-+ else
-+ available_bytes = -1;
-+
-+ if ((available_bytes == -1 && card->ticks == 8) ||
-+ available_bytes >= DAHDI_CHUNKSIZE + hfc_RX_FIFO_PRELOAD) {
-+ card->ticks = 0;
-+
-+ if (available_bytes > DAHDI_CHUNKSIZE*2 + hfc_RX_FIFO_PRELOAD) {
-+ card->late_irqs++;
-+ /*
-+ * we are out of sync, clear fifos, jaw
-+ */
-+ hfc_clear_fifo_rx(&card->chans[B1].rx);
-+ hfc_clear_fifo_tx(&card->chans[B1].tx);
-+ hfc_clear_fifo_rx(&card->chans[B2].rx);
-+ hfc_clear_fifo_tx(&card->chans[B2].tx);
-+
-+#ifdef DEBUG
-+ if (debug_level >= 4) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "late IRQ, %d bytes late\n",
-+ card->cardnum,
-+ available_bytes -
-+ (DAHDI_CHUNKSIZE +
-+ hfc_RX_FIFO_PRELOAD));
-+ }
-+#endif
-+ } else {
-+ hfc_handle_voice(card);
-+ }
-+ }
-+
-+ card->ticks++;
-+}
-+
-+
-+static void hfc_handle_voice(struct hfc_card *card)
-+{
-+ struct dahdi_hfc *hfccard = card->ztdev;
-+ int frame_left, res;
-+ unsigned char buf[hfc_HDLC_BUF_LEN];
-+ unsigned int size = sizeof(buf) / sizeof(buf[0]);
-+
-+
-+ if (card->chans[B1].status != open_voice &&
-+ card->chans[B2].status != open_voice)
-+ return;
-+
-+ dahdi_transmit(&hfccard->span);
-+
-+ if (card->regs.fifo_en & hfc_FIFOEN_B1TX)
-+ hfc_zap_transmit(&card->chans[B1].tx);
-+ if (card->regs.fifo_en & hfc_FIFOEN_B2TX)
-+ hfc_zap_transmit(&card->chans[B2].tx);
-+
-+ /*
-+ * dahdi hdlc frame tx
-+ */
-+
-+ if (atomic_read(&hfccard->hdlc_pending)) {
-+ hfc_check_l1_up(card);
-+ res = dahdi_hdlc_getbuf(hfccard->sigchan, buf, &size);
-+ if (size > 0) {
-+ hfccard->sigactive = 1;
-+ memcpy(card->chans[D].tx.ugly_framebuf +
-+ card->chans[D].tx.ugly_framebuf_size,
-+ buf, size);
-+ card->chans[D].tx.ugly_framebuf_size += size;
-+ if (res != 0) {
-+ hfc_fifo_put_frame(&card->chans[D].tx,
-+ card->chans[D].tx.ugly_framebuf,
-+ card->chans[D].tx.ugly_framebuf_size);
-+ ++hfccard->frames_out;
-+ hfccard->sigactive = 0;
-+ card->chans[D].tx.ugly_framebuf_size
-+ = 0;
-+ atomic_dec(&hfccard->hdlc_pending);
-+ }
-+ }
-+ }
-+ /*
-+ * dahdi hdlc frame tx done
-+ */
-+
-+ if (card->regs.fifo_en & hfc_FIFOEN_B1RX)
-+ hfc_zap_receive(&card->chans[B1].rx);
-+ else
-+ memset(&card->chans[B1].rx.zaptel_buffer, 0x7f,
-+ sizeof(card->chans[B1].rx.zaptel_buffer));
-+
-+ if (card->regs.fifo_en & hfc_FIFOEN_B2RX)
-+ hfc_zap_receive(&card->chans[B2].rx);
-+ else
-+ memset(&card->chans[B2].rx.zaptel_buffer, 0x7f,
-+ sizeof(card->chans[B1].rx.zaptel_buffer));
-+
-+ /*
-+ * Echo cancellation
-+ */
-+ dahdi_ec_chunk(&hfccard->chans[DAHDI_B1],
-+ card->chans[B1].rx.zaptel_buffer,
-+ card->chans[B1].tx.zaptel_buffer);
-+ dahdi_ec_chunk(&hfccard->chans[DAHDI_B2],
-+ card->chans[B2].rx.zaptel_buffer,
-+ card->chans[B2].tx.zaptel_buffer);
-+
-+ /*
-+ * dahdi hdlc frame rx
-+ */
-+ if (hfc_fifo_has_frames(&card->chans[D].rx))
-+ hfc_frame_arrived(&card->chans[D]);
-+
-+ if (card->chans[D].rx.ugly_framebuf_size) {
-+ frame_left = card->chans[D].rx.ugly_framebuf_size -
-+ card->chans[D].rx.ugly_framebuf_off ;
-+ if (frame_left > hfc_HDLC_BUF_LEN) {
-+ dahdi_hdlc_putbuf(hfccard->sigchan,
-+ card->chans[D].rx.ugly_framebuf +
-+ card->chans[D].rx.ugly_framebuf_off,
-+ hfc_HDLC_BUF_LEN);
-+ card->chans[D].rx.ugly_framebuf_off +=
-+ hfc_HDLC_BUF_LEN;
-+ } else {
-+ dahdi_hdlc_putbuf(hfccard->sigchan,
-+ card->chans[D].rx.ugly_framebuf +
-+ card->chans[D].rx.ugly_framebuf_off,
-+ frame_left);
-+ dahdi_hdlc_finish(hfccard->sigchan);
-+ card->chans[D].rx.ugly_framebuf_size = 0;
-+ card->chans[D].rx.ugly_framebuf_off = 0;
-+ }
-+ }
-+ /*
-+ * dahdi hdlc frame rx done
-+ */
-+
-+ if (hfccard->span.flags & DAHDI_FLAG_RUNNING)
-+ dahdi_receive(&hfccard->span);
-+
-+}
-+
-+static void hfc_frame_arrived(struct hfc_chan_duplex *chan)
-+{
-+ struct hfc_card *card = chan->card;
-+ int antiloop = 16;
-+ struct sk_buff *skb;
-+
-+ while (hfc_fifo_has_frames(&chan->rx) && --antiloop) {
-+ int frame_size = hfc_fifo_get_frame_size(&chan->rx);
-+
-+ if (frame_size < 3) {
-+#ifdef DEBUG
-+ if (debug_level >= 2)
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "invalid frame received, "
-+ "just %d bytes\n",
-+ card->cardnum,
-+ chan->name,
-+ frame_size);
-+#endif
-+
-+ hfc_fifo_drop_frame(&chan->rx);
-+
-+
-+ continue;
-+ } else if (frame_size == 3) {
-+#ifdef DEBUG
-+ if (debug_level >= 2)
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "empty frame received\n",
-+ card->cardnum,
-+ chan->name);
-+#endif
-+
-+ hfc_fifo_drop_frame(&chan->rx);
-+
-+
-+ continue;
-+ }
-+
-+ if (chan->open_by_zaptel &&
-+ card->chans[D].rx.ugly_framebuf_size) {
-+
-+ /*
-+ * We have to wait for Dahdi to transmit the
-+ * frame... wait for next time
-+ */
-+
-+ break;
-+ }
-+
-+ skb = dev_alloc_skb(frame_size - 3);
-+
-+ if (!skb) {
-+ printk(KERN_ERR hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "cannot allocate skb: frame dropped\n",
-+ card->cardnum,
-+ chan->name);
-+
-+ hfc_fifo_drop_frame(&chan->rx);
-+
-+
-+ continue;
-+ }
-+
-+
-+ /*
-+ * HFC does the checksum
-+ */
-+#ifndef CHECKSUM_HW
-+ skb->ip_summed = CHECKSUM_COMPLETE;
-+#else
-+ skb->ip_summed = CHECKSUM_HW;
-+#endif
-+
-+ if (chan->open_by_zaptel) {
-+ card->chans[D].rx.ugly_framebuf_size = frame_size - 1;
-+
-+ if (hfc_fifo_get_frame(&card->chans[D].rx,
-+ card->chans[D].rx.ugly_framebuf,
-+ frame_size - 1) == -1) {
-+ dev_kfree_skb(skb);
-+ continue;
-+ }
-+
-+ memcpy(skb_put(skb, frame_size - 3),
-+ card->chans[D].rx.ugly_framebuf,
-+ frame_size - 3);
-+ } else {
-+ if (hfc_fifo_get_frame(&chan->rx,
-+ skb_put(skb, frame_size - 3),
-+ frame_size - 3) == -1) {
-+ dev_kfree_skb(skb);
-+ continue;
-+ }
-+ }
-+ }
-+
-+ if (!antiloop)
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "Infinite loop detected\n",
-+ card->cardnum);
-+}
-+
-+/******************************************
-+ * Module initialization and cleanup
-+ ******************************************/
-+
-+static int __devinit hfc_probe(struct pci_dev *pci_dev,
-+ const struct pci_device_id *ent)
-+{
-+ static int cardnum;
-+ int err;
-+ int i;
-+
-+ struct hfc_card *card = NULL;
-+ struct dahdi_hfc *zthfc = NULL;
-+ card = kmalloc(sizeof(struct hfc_card), GFP_KERNEL);
-+ if (!card) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "unable to kmalloc!\n");
-+ err = -ENOMEM;
-+ goto err_alloc_hfccard;
-+ }
-+
-+ memset(card, 0x00, sizeof(struct hfc_card));
-+ card->cardnum = cardnum;
-+ card->pcidev = pci_dev;
-+ spin_lock_init(&card->lock);
-+
-+ pci_set_drvdata(pci_dev, card);
-+
-+ err = pci_enable_device(pci_dev);
-+ if (err)
-+ goto err_pci_enable_device;
-+
-+ err = pci_set_dma_mask(pci_dev, PCI_DMA_32BIT);
-+ if (err) {
-+ printk(KERN_ERR hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "No suitable DMA configuration available.\n",
-+ card->cardnum);
-+ goto err_pci_set_dma_mask;
-+ }
-+
-+ pci_write_config_word(pci_dev, PCI_COMMAND, PCI_COMMAND_MEMORY);
-+ err = pci_request_regions(pci_dev, hfc_DRIVER_NAME);
-+ if (err) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "cannot request I/O memory region\n",
-+ card->cardnum);
-+ goto err_pci_request_regions;
-+ }
-+
-+ pci_set_master(pci_dev);
-+
-+ if (!pci_dev->irq) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "no irq!\n",
-+ card->cardnum);
-+ err = -ENODEV;
-+ goto err_noirq;
-+ }
-+
-+ card->io_bus_mem = pci_resource_start(pci_dev, 1);
-+ if (!card->io_bus_mem) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "no iomem!\n",
-+ card->cardnum);
-+ err = -ENODEV;
-+ goto err_noiobase;
-+ }
-+
-+ card->io_mem = ioremap(card->io_bus_mem, hfc_PCI_MEM_SIZE);
-+ if (!(card->io_mem)) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "cannot ioremap I/O memory\n",
-+ card->cardnum);
-+ err = -ENODEV;
-+ goto err_ioremap;
-+ }
-+
-+ /*
-+ * pci_alloc_consistent guarantees alignment
-+ * (Documentation/DMA-mapping.txt)
-+ */
-+ card->fifo_mem = pci_alloc_consistent(pci_dev,
-+ hfc_FIFO_SIZE, &card->fifo_bus_mem);
-+ if (!card->fifo_mem) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "unable to allocate FIFO DMA memory!\n",
-+ card->cardnum);
-+ err = -ENOMEM;
-+ goto err_alloc_fifo;
-+ }
-+
-+ memset(card->fifo_mem, 0x00, hfc_FIFO_SIZE);
-+
-+ card->fifos = card->fifo_mem;
-+
-+ pci_write_config_dword(card->pcidev, hfc_PCI_MWBA, card->fifo_bus_mem);
-+
-+ err = request_irq(card->pcidev->irq, &hfc_interrupt,
-+
-+#if (KERNEL_VERSION(2, 6, 23) < LINUX_VERSION_CODE)
-+ IRQF_SHARED, hfc_DRIVER_NAME, card);
-+#else
-+ SA_SHIRQ, hfc_DRIVER_NAME, card);
-+#endif
-+
-+ if (err) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "unable to register irq\n",
-+ card->cardnum);
-+ goto err_request_irq;
-+ }
-+
-+ card->nt_mode = FALSE;
-+
-+ if (modes & (1 << card->cardnum))
-+ card->nt_mode = TRUE;
-+
-+ for (i = 0; i < nt_modes_count; i++) {
-+ if (nt_modes[i] == card->cardnum)
-+ card->nt_mode = TRUE;
-+ }
-+
-+ /*
-+ * D Channel
-+ */
-+ card->chans[D].card = card;
-+ card->chans[D].name = "D";
-+ card->chans[D].status = free;
-+ card->chans[D].number = D;
-+ spin_lock_init(&card->chans[D].lock);
-+
-+ card->chans[D].rx.chan = &card->chans[D];
-+ card->chans[D].rx.fifo_base = card->fifos + 0x4000;
-+ card->chans[D].rx.z_base = card->fifos + 0x4000;
-+ card->chans[D].rx.z1_base = card->fifos + 0x6080;
-+ card->chans[D].rx.z2_base = card->fifos + 0x6082;
-+ card->chans[D].rx.z_min = 0x0000;
-+ card->chans[D].rx.z_max = 0x01FF;
-+ card->chans[D].rx.f_min = 0x10;
-+ card->chans[D].rx.f_max = 0x1F;
-+ card->chans[D].rx.f1 = card->fifos + 0x60a0;
-+ card->chans[D].rx.f2 = card->fifos + 0x60a1;
-+ card->chans[D].rx.fifo_size = card->chans[D].rx.z_max
-+ - card->chans[D].rx.z_min + 1;
-+ card->chans[D].rx.f_num = card->chans[D].rx.f_max
-+ - card->chans[D].rx.f_min + 1;
-+
-+ card->chans[D].tx.chan = &card->chans[D];
-+ card->chans[D].tx.fifo_base = card->fifos + 0x0000;
-+ card->chans[D].tx.z_base = card->fifos + 0x0000;
-+ card->chans[D].tx.z1_base = card->fifos + 0x2080;
-+ card->chans[D].tx.z2_base = card->fifos + 0x2082;
-+ card->chans[D].tx.z_min = 0x0000;
-+ card->chans[D].tx.z_max = 0x01FF;
-+ card->chans[D].tx.f_min = 0x10;
-+ card->chans[D].tx.f_max = 0x1F;
-+ card->chans[D].tx.f1 = card->fifos + 0x20a0;
-+ card->chans[D].tx.f2 = card->fifos + 0x20a1;
-+ card->chans[D].tx.fifo_size = card->chans[D].tx.z_max -
-+ card->chans[D].tx.z_min + 1;
-+ card->chans[D].tx.f_num = card->chans[D].tx.f_max -
-+ card->chans[D].tx.f_min + 1;
-+
-+ /*
-+ * B1 Channel
-+ */
-+ card->chans[B1].card = card;
-+ card->chans[B1].name = "B1";
-+ card->chans[B1].status = free;
-+ card->chans[B1].number = B1;
-+ card->chans[B1].protocol = 0;
-+ spin_lock_init(&card->chans[B1].lock);
-+
-+ card->chans[B1].rx.chan = &card->chans[B1];
-+ card->chans[B1].rx.fifo_base = card->fifos + 0x4200;
-+ card->chans[B1].rx.z_base = card->fifos + 0x4000;
-+ card->chans[B1].rx.z1_base = card->fifos + 0x6000;
-+ card->chans[B1].rx.z2_base = card->fifos + 0x6002;
-+ card->chans[B1].rx.z_min = 0x0200;
-+ card->chans[B1].rx.z_max = 0x1FFF;
-+ card->chans[B1].rx.f_min = 0x00;
-+ card->chans[B1].rx.f_max = 0x1F;
-+ card->chans[B1].rx.f1 = card->fifos + 0x6080;
-+ card->chans[B1].rx.f2 = card->fifos + 0x6081;
-+ card->chans[B1].rx.fifo_size = card->chans[B1].rx.z_max -
-+ card->chans[B1].rx.z_min + 1;
-+ card->chans[B1].rx.f_num = card->chans[B1].rx.f_max -
-+ card->chans[B1].rx.f_min + 1;
-+
-+ card->chans[B1].tx.chan = &card->chans[B1];
-+ card->chans[B1].tx.fifo_base = card->fifos + 0x0200;
-+ card->chans[B1].tx.z_base = card->fifos + 0x0000;
-+ card->chans[B1].tx.z1_base = card->fifos + 0x2000;
-+ card->chans[B1].tx.z2_base = card->fifos + 0x2002;
-+ card->chans[B1].tx.z_min = 0x0200;
-+ card->chans[B1].tx.z_max = 0x1FFF;
-+ card->chans[B1].tx.f_min = 0x00;
-+ card->chans[B1].tx.f_max = 0x1F;
-+ card->chans[B1].tx.f1 = card->fifos + 0x2080;
-+ card->chans[B1].tx.f2 = card->fifos + 0x2081;
-+ card->chans[B1].tx.fifo_size = card->chans[B1].tx.z_max -
-+ card->chans[B1].tx.z_min + 1;
-+ card->chans[B1].tx.f_num = card->chans[B1].tx.f_max -
-+ card->chans[B1].tx.f_min + 1;
-+
-+ /*
-+ * B2 Channel
-+ */
-+ card->chans[B2].card = card;
-+ card->chans[B2].name = "B2";
-+ card->chans[B2].status = free;
-+ card->chans[B2].number = B2;
-+ card->chans[B2].protocol = 0;
-+ spin_lock_init(&card->chans[B2].lock);
-+
-+ card->chans[B2].rx.chan = &card->chans[B2];
-+ card->chans[B2].rx.fifo_base = card->fifos + 0x6200,
-+ card->chans[B2].rx.z_base = card->fifos + 0x6000;
-+ card->chans[B2].rx.z1_base = card->fifos + 0x6100;
-+ card->chans[B2].rx.z2_base = card->fifos + 0x6102;
-+ card->chans[B2].rx.z_min = 0x0200;
-+ card->chans[B2].rx.z_max = 0x1FFF;
-+ card->chans[B2].rx.f_min = 0x00;
-+ card->chans[B2].rx.f_max = 0x1F;
-+ card->chans[B2].rx.f1 = card->fifos + 0x6180;
-+ card->chans[B2].rx.f2 = card->fifos + 0x6181;
-+ card->chans[B2].rx.fifo_size = card->chans[B2].rx.z_max -
-+ card->chans[B2].rx.z_min + 1;
-+ card->chans[B2].rx.f_num = card->chans[B2].rx.f_max -
-+ card->chans[B2].rx.f_min + 1;
-+
-+ card->chans[B2].tx.chan = &card->chans[B2];
-+ card->chans[B2].tx.fifo_base = card->fifos + 0x2200;
-+ card->chans[B2].tx.z_base = card->fifos + 0x2000;
-+ card->chans[B2].tx.z1_base = card->fifos + 0x2100;
-+ card->chans[B2].tx.z2_base = card->fifos + 0x2102;
-+ card->chans[B2].tx.z_min = 0x0200;
-+ card->chans[B2].tx.z_max = 0x1FFF;
-+ card->chans[B2].tx.f_min = 0x00;
-+ card->chans[B2].tx.f_max = 0x1F;
-+ card->chans[B2].tx.f1 = card->fifos + 0x2180;
-+ card->chans[B2].tx.f2 = card->fifos + 0x2181;
-+ card->chans[B2].tx.fifo_size = card->chans[B2].tx.z_max -
-+ card->chans[B2].tx.z_min + 1;
-+ card->chans[B2].tx.f_num = card->chans[B2].tx.f_max -
-+ card->chans[B2].tx.f_min + 1;
-+
-+ /*
-+ * All done
-+ */
-+
-+ zthfc = kmalloc(sizeof(struct dahdi_hfc), GFP_KERNEL);
-+ if (!zthfc) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "unable to kmalloc!\n");
-+ goto err_request_irq;
-+ }
-+ memset(zthfc, 0x0, sizeof(struct dahdi_hfc));
-+
-+ zthfc->card = card;
-+ hfc_zap_initialize(zthfc);
-+ card->ztdev = zthfc;
-+
-+ snprintf(card->proc_dir_name,
-+ sizeof(card->proc_dir_name),
-+ "%d", card->cardnum);
-+ card->proc_dir = proc_mkdir(card->proc_dir_name, hfc_proc_zaphfc_dir);
-+ SET_PROC_DIRENTRY_OWNER(card->proc_dir);
-+
-+ hfc_resetCard(card);
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d configured for %s mode at mem %#lx (0x%p) IRQ %u\n",
-+ card->cardnum,
-+ card->nt_mode ? "NT" : "TE",
-+ card->io_bus_mem,
-+ card->io_mem,
-+ card->pcidev->irq);
-+
-+ cardnum++;
-+
-+ return 0;
-+
-+err_request_irq:
-+ pci_free_consistent(pci_dev, hfc_FIFO_SIZE,
-+ card->fifo_mem, card->fifo_bus_mem);
-+err_alloc_fifo:
-+ iounmap(card->io_mem);
-+err_ioremap:
-+err_noiobase:
-+err_noirq:
-+ pci_release_regions(pci_dev);
-+err_pci_request_regions:
-+err_pci_set_dma_mask:
-+err_pci_enable_device:
-+ kfree(card);
-+err_alloc_hfccard:
-+ return err;
-+}
-+
-+static void __devexit hfc_remove(struct pci_dev *pci_dev)
-+{
-+ struct hfc_card *card = pci_get_drvdata(pci_dev);
-+
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "shutting down card at %p.\n",
-+ card->cardnum,
-+ card->io_mem);
-+
-+ hfc_softreset(card);
-+
-+ dahdi_unregister_device(card->ztdev->ddev);
-+ hfc_dahdi_free(card->ztdev);
-+
-+
-+ /*
-+ * disable memio and bustmaster
-+ */
-+ pci_write_config_word(pci_dev, PCI_COMMAND, 0);
-+
-+ remove_proc_entry("bufs", card->proc_dir);
-+ remove_proc_entry("fifos", card->proc_dir);
-+ remove_proc_entry("info", card->proc_dir);
-+ remove_proc_entry(card->proc_dir_name, hfc_proc_zaphfc_dir);
-+
-+ free_irq(pci_dev->irq, card);
-+
-+ pci_free_consistent(pci_dev, hfc_FIFO_SIZE,
-+ card->fifo_mem, card->fifo_bus_mem);
-+
-+ iounmap(card->io_mem);
-+
-+ pci_release_regions(pci_dev);
-+
-+ pci_disable_device(pci_dev);
-+
-+ kfree(card);
-+}
-+
-+/******************************************
-+ * Module stuff
-+ ******************************************/
-+
-+static int __init hfc_init_module(void)
-+{
-+ int ret;
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ hfc_DRIVER_STRING " loading\n");
-+
-+#if (KERNEL_VERSION(2, 6, 26) <= LINUX_VERSION_CODE)
-+ hfc_proc_zaphfc_dir = proc_mkdir(hfc_DRIVER_NAME, NULL);
-+#else
-+ hfc_proc_zaphfc_dir = proc_mkdir(hfc_DRIVER_NAME, proc_root_driver);
-+#endif
-+
-+ ret = pci_register_driver(&hfc_driver);
-+ return ret;
-+}
-+
-+module_init(hfc_init_module);
-+
-+static void __exit hfc_module_exit(void)
-+{
-+ pci_unregister_driver(&hfc_driver);
-+
-+#if (KERNEL_VERSION(2, 6, 26) <= LINUX_VERSION_CODE)
-+ remove_proc_entry(hfc_DRIVER_NAME, NULL);
-+#else
-+ remove_proc_entry(hfc_DRIVER_NAME, proc_root_driver);
-+#endif
-+
-+ printk(KERN_INFO hfc_DRIVER_PREFIX
-+ hfc_DRIVER_STRING " unloaded\n");
-+}
-+
-+module_exit(hfc_module_exit);
-+
-+#endif
-+
-+MODULE_DESCRIPTION(hfc_DRIVER_DESCR);
-+MODULE_AUTHOR("Jens Wilke <jw_vzaphfc@headissue.com>, "
-+ "Daniele (Vihai) Orlandi <daniele@orlandi.com>, "
-+ "Jose A. Deniz <odicha@hotmail.com>");
-+MODULE_ALIAS("vzaphfc");
-+#ifdef MODULE_LICENSE
-+MODULE_LICENSE("GPL");
-+#endif
-+
-+
-+module_param(modes, int, 0444);
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
-+module_param_array(nt_modes, int, &nt_modes_count, 0444);
-+#else
-+module_param_array(nt_modes, int, nt_modes_count, 0444);
-+#endif
-+
-+module_param(force_l1_up, int, 0444);
-+#ifdef DEBUG
-+module_param(debug_level, int, 0444);
-+#endif
-+
-+MODULE_PARM_DESC(modes, "[Deprecated] bit-mask to configure NT mode");
-+MODULE_PARM_DESC(nt_modes,
-+ "Comma-separated list of card IDs to configure in NT mode");
-+MODULE_PARM_DESC(force_l1_up, "Don't allow L1 to go down");
-+#ifdef DEBUG
-+MODULE_PARM_DESC(debug_level, "Debug verbosity level");
-+#endif
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/zaphfc/fifo.c dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/fifo.c
---- dahdi-linux-2.7.0/drivers/dahdi/zaphfc/fifo.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/fifo.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,375 @@
-+/*
-+ * fifo.c - HFC FIFO management routines
-+ *
-+ * Copyright (C) 2006 headissue GmbH; Jens Wilke
-+ * Copyright (C) 2004 Daniele Orlandi
-+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
-+ *
-+ * Original author of this code is
-+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
-+ *
-+ * This program is free software and may be modified and
-+ * distributed under the terms of the GNU Public License.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+
-+#include <dahdi/kernel.h>
-+
-+#include "fifo.h"
-+
-+static void hfc_fifo_mem_read(struct hfc_chan_simplex *chan,
-+ int z_start,
-+ void *data, int size)
-+{
-+ int bytes_to_boundary = chan->z_max - z_start + 1;
-+ if (bytes_to_boundary >= size) {
-+ memcpy(data,
-+ chan->z_base + z_start,
-+ size);
-+ } else {
-+ /*
-+ * Buffer wrap
-+ */
-+ memcpy(data,
-+ chan->z_base + z_start,
-+ bytes_to_boundary);
-+
-+ memcpy(data + bytes_to_boundary,
-+ chan->fifo_base,
-+ size - bytes_to_boundary);
-+ }
-+}
-+
-+static void hfc_fifo_mem_write(struct hfc_chan_simplex *chan,
-+ void *data, int size)
-+{
-+ int bytes_to_boundary = chan->z_max - *Z1_F1(chan) + 1;
-+ if (bytes_to_boundary >= size) {
-+ memcpy(chan->z_base + *Z1_F1(chan),
-+ data,
-+ size);
-+ } else {
-+ /*
-+ * FIFO wrap
-+ */
-+
-+ memcpy(chan->z_base + *Z1_F1(chan),
-+ data,
-+ bytes_to_boundary);
-+
-+ memcpy(chan->fifo_base,
-+ data + bytes_to_boundary,
-+ size - bytes_to_boundary);
-+ }
-+}
-+
-+int hfc_fifo_get(struct hfc_chan_simplex *chan,
-+ void *data, int size)
-+{
-+ int available_bytes;
-+
-+ /*
-+ * Some useless statistic
-+ */
-+ chan->bytes += size;
-+
-+ available_bytes = hfc_fifo_used_rx(chan);
-+
-+ if (available_bytes < size && !chan->fifo_underrun++) {
-+ /*
-+ * print the warning only once
-+ */
-+ printk(KERN_WARNING hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "RX FIFO not enough (%d) bytes to receive!\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name,
-+ available_bytes);
-+ return -1;
-+ }
-+
-+ hfc_fifo_mem_read(chan, *Z2_F2(chan), data, size);
-+ *Z2_F2(chan) = Z_inc(chan, *Z2_F2(chan), size);
-+ return available_bytes - size;
-+}
-+
-+void hfc_fifo_put(struct hfc_chan_simplex *chan,
-+ void *data, int size)
-+{
-+ struct hfc_card *card = chan->chan->card;
-+ int used_bytes = hfc_fifo_used_tx(chan);
-+ int free_bytes = hfc_fifo_free_tx(chan);
-+
-+ if (!used_bytes && !chan->fifo_underrun++) {
-+ /*
-+ * print warning only once, to make timing not worse
-+ */
-+ printk(KERN_WARNING hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "TX FIFO has become empty\n",
-+ card->cardnum,
-+ chan->chan->name);
-+ }
-+ if (free_bytes < size) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "TX FIFO full!\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+ chan->fifo_full++;
-+ hfc_clear_fifo_tx(chan);
-+ }
-+
-+ hfc_fifo_mem_write(chan, data, size);
-+ chan->bytes += size;
-+ *Z1_F1(chan) = Z_inc(chan, *Z1_F1(chan), size);
-+}
-+
-+int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size)
-+{
-+ int frame_size;
-+ u16 newz2 ;
-+
-+ if (*chan->f1 == *chan->f2) {
-+ /*
-+ * nothing received, strange uh?
-+ */
-+ printk(KERN_WARNING hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "get_frame called with no frame in FIFO.\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+
-+ return -1;
-+ }
-+
-+ /*
-+ * frame_size includes CRC+CRC+STAT
-+ */
-+ frame_size = hfc_fifo_get_frame_size(chan);
-+
-+#ifdef DEBUG
-+ if (debug_level == 3) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "RX len %2d: ",
-+ chan->chan->card->cardnum,
-+ chan->chan->name,
-+ frame_size);
-+ } else if (debug_level >= 4) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "RX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ",
-+ chan->chan->card->cardnum,
-+ chan->chan->name,
-+ *chan->f1, *chan->f2, *Z1_F2(chan), *Z2_F2(chan),
-+ frame_size);
-+ }
-+
-+ if (debug_level >= 3) {
-+ int i;
-+ for (i = 0; i < frame_size; i++) {
-+ printk("%02x", hfc_fifo_u8(chan,
-+ Z_inc(chan, *Z2_F2(chan), i)));
-+ }
-+
-+ printk("\n");
-+ }
-+#endif
-+
-+ if (frame_size <= 0) {
-+#ifdef DEBUG
-+ if (debug_level >= 2) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "invalid (empty) frame received.\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+ }
-+#endif
-+
-+ hfc_fifo_drop_frame(chan);
-+ return -1;
-+ }
-+
-+ /*
-+ * STAT is not really received
-+ */
-+ chan->bytes += frame_size - 1;
-+
-+ /*
-+ * Calculate beginning of the next frame
-+ */
-+ newz2 = Z_inc(chan, *Z2_F2(chan), frame_size);
-+
-+ /*
-+ * We cannot use hfc_fifo_get because of different semantic of
-+ * "available bytes" and to avoid useless increment of Z2
-+ */
-+ hfc_fifo_mem_read(chan, *Z2_F2(chan), data,
-+ frame_size < max_size ? frame_size : max_size);
-+
-+ if (hfc_fifo_u8(chan, Z_inc(chan, *Z2_F2(chan),
-+ frame_size - 1)) != 0x00) {
-+ /*
-+ * CRC not ok, frame broken, skipping
-+ */
-+#ifdef DEBUG
-+ if (debug_level >= 2) {
-+ printk(KERN_WARNING hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "Received frame with wrong CRC\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+ }
-+#endif
-+
-+ chan->crc++;
-+
-+ hfc_fifo_drop_frame(chan);
-+ return -1;
-+ }
-+
-+ chan->frames++;
-+
-+ *chan->f2 = F_inc(chan, *chan->f2, 1);
-+
-+ /*
-+ * Set Z2 for the next frame we're going to receive
-+ */
-+ *Z2_F2(chan) = newz2;
-+
-+ return frame_size;
-+}
-+
-+void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan)
-+{
-+ int available_bytes;
-+ u16 newz2;
-+
-+ if (*chan->f1 == *chan->f2) {
-+ /*
-+ * nothing received, strange eh?
-+ */
-+ printk(KERN_WARNING hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "skip_frame called with no frame in FIFO.\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+
-+ return;
-+ }
-+
-+ available_bytes = hfc_fifo_used_rx(chan) + 1;
-+
-+ /*
-+ * Calculate beginning of the next frame
-+ */
-+ newz2 = Z_inc(chan, *Z2_F2(chan), available_bytes);
-+
-+ *chan->f2 = F_inc(chan, *chan->f2, 1);
-+
-+ /*
-+ * Set Z2 for the next frame we're going to receive
-+ */
-+ *Z2_F2(chan) = newz2;
-+}
-+
-+void hfc_fifo_put_frame(struct hfc_chan_simplex *chan,
-+ void *data, int size)
-+{
-+ u16 newz1;
-+ int available_frames;
-+
-+#ifdef DEBUG
-+ if (debug_level == 3) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "TX len %2d: ",
-+ chan->chan->card->cardnum,
-+ chan->chan->name,
-+ size);
-+ } else if (debug_level >= 4) {
-+ printk(KERN_DEBUG hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "TX (f1=%02x, f2=%02x, z1=%04x, z2=%04x) len %2d: ",
-+ chan->chan->card->cardnum,
-+ chan->chan->name,
-+ *chan->f1, *chan->f2, *Z1_F1(chan), *Z2_F1(chan),
-+ size);
-+ }
-+
-+ if (debug_level >= 3) {
-+ int i;
-+ for (i = 0; i < size; i++)
-+ printk("%02x", ((u8 *)data)[i]);
-+
-+ printk("\n");
-+ }
-+#endif
-+
-+ available_frames = hfc_fifo_free_frames(chan);
-+
-+ if (available_frames >= chan->f_num) {
-+ printk(KERN_CRIT hfc_DRIVER_PREFIX
-+ "card %d: "
-+ "chan %s: "
-+ "TX FIFO total number of frames exceeded!\n",
-+ chan->chan->card->cardnum,
-+ chan->chan->name);
-+
-+ chan->fifo_full++;
-+
-+ return;
-+ }
-+
-+ hfc_fifo_put(chan, data, size);
-+
-+ newz1 = *Z1_F1(chan);
-+
-+ *chan->f1 = F_inc(chan, *chan->f1, 1);
-+
-+ *Z1_F1(chan) = newz1;
-+
-+ chan->frames++;
-+}
-+
-+void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan)
-+{
-+ *chan->f2 = *chan->f1;
-+ *Z2_F2(chan) = *Z1_F2(chan);
-+}
-+
-+void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan)
-+{
-+ *chan->f1 = *chan->f2;
-+ *Z1_F1(chan) = *Z2_F1(chan);
-+
-+ if (chan->chan->status == open_voice) {
-+ /*
-+ * Make sure that at least hfc_TX_FIFO_PRELOAD bytes are
-+ * present in the TX FIFOs
-+ * Create hfc_TX_FIFO_PRELOAD bytes of empty data
-+ * (0x7f is mute audio)
-+ */
-+ u8 empty_fifo[hfc_TX_FIFO_PRELOAD +
-+ DAHDI_CHUNKSIZE + hfc_RX_FIFO_PRELOAD];
-+ memset(empty_fifo, 0x7f, sizeof(empty_fifo));
-+
-+ hfc_fifo_put(chan, empty_fifo, sizeof(empty_fifo));
-+ }
-+}
-+
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/zaphfc/fifo.h dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/fifo.h
---- dahdi-linux-2.7.0/drivers/dahdi/zaphfc/fifo.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/fifo.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,139 @@
-+/*
-+ * fifo.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
-+ *
-+ * Copyright (C) 2004 Daniele Orlandi
-+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
-+ *
-+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
-+ *
-+ * Major rewrite of the driver made by
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * This program is free software and may be modified and
-+ * distributed under the terms of the GNU Public License.
-+ *
-+ */
-+
-+#ifndef _HFC_FIFO_H
-+#define _HFC_FIFO_H
-+
-+#include "zaphfc.h"
-+
-+static inline u16 *Z1_F1(struct hfc_chan_simplex *chan)
-+{
-+ return chan->z1_base + (*chan->f1 * 4);
-+}
-+
-+static inline u16 *Z2_F1(struct hfc_chan_simplex *chan)
-+{
-+ return chan->z2_base + (*chan->f1 * 4);
-+}
-+
-+static inline u16 *Z1_F2(struct hfc_chan_simplex *chan)
-+{
-+ return chan->z1_base + (*chan->f2 * 4);
-+}
-+
-+static inline u16 *Z2_F2(struct hfc_chan_simplex *chan)
-+{
-+ return chan->z2_base + (*chan->f2 * 4);
-+}
-+
-+static inline u16 Z_inc(struct hfc_chan_simplex *chan, u16 z, u16 inc)
-+{
-+ /*
-+ * declared as u32 in order to manage overflows
-+ */
-+ u32 newz = z + inc;
-+ if (newz > chan->z_max)
-+ newz -= chan->fifo_size;
-+
-+ return newz;
-+}
-+
-+static inline u8 F_inc(struct hfc_chan_simplex *chan, u8 f, u8 inc)
-+{
-+ /*
-+ * declared as u16 in order to manage overflows
-+ */
-+ u16 newf = f + inc;
-+ if (newf > chan->f_max)
-+ newf -= chan->f_num;
-+
-+ return newf;
-+}
-+
-+static inline u16 hfc_fifo_used_rx(struct hfc_chan_simplex *chan)
-+{
-+ return (*Z1_F2(chan) - *Z2_F2(chan) +
-+ chan->fifo_size) % chan->fifo_size;
-+}
-+
-+static inline u16 hfc_fifo_get_frame_size(struct hfc_chan_simplex *chan)
-+{
-+ /*
-+ * This +1 is needed because in frame mode the available bytes are Z2-Z1+1
-+ * while in transparent mode I wouldn't consider the byte pointed by Z2 to
-+ * be available, otherwise, the FIFO would always contain one byte, even
-+ * when Z1==Z2
-+ */
-+
-+ return hfc_fifo_used_rx(chan) + 1;
-+}
-+
-+static inline u8 hfc_fifo_u8(struct hfc_chan_simplex *chan, u16 z)
-+{
-+ return *((u8 *)(chan->z_base + z));
-+}
-+
-+static inline u16 hfc_fifo_used_tx(struct hfc_chan_simplex *chan)
-+{
-+ return (*Z1_F1(chan) - *Z2_F1(chan) +
-+ chan->fifo_size) % chan->fifo_size;
-+}
-+
-+static inline u16 hfc_fifo_free_rx(struct hfc_chan_simplex *chan)
-+{
-+ u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
-+
-+ if (free_bytes > 0)
-+ return free_bytes;
-+ else
-+ return free_bytes + chan->fifo_size;
-+}
-+
-+static inline u16 hfc_fifo_free_tx(struct hfc_chan_simplex *chan)
-+{
-+ u16 free_bytes = *Z2_F1(chan) - *Z1_F1(chan);
-+
-+ if (free_bytes > 0)
-+ return free_bytes;
-+ else
-+ return free_bytes + chan->fifo_size;
-+}
-+
-+static inline int hfc_fifo_has_frames(struct hfc_chan_simplex *chan)
-+{
-+ return *chan->f1 != *chan->f2;
-+}
-+
-+static inline u8 hfc_fifo_used_frames(struct hfc_chan_simplex *chan)
-+{
-+ return (*chan->f1 - *chan->f2 + chan->f_num) % chan->f_num;
-+}
-+
-+static inline u8 hfc_fifo_free_frames(struct hfc_chan_simplex *chan)
-+{
-+ return (*chan->f2 - *chan->f1 + chan->f_num) % chan->f_num;
-+}
-+
-+int hfc_fifo_get(struct hfc_chan_simplex *chan, void *data, int size);
-+void hfc_fifo_put(struct hfc_chan_simplex *chan, void *data, int size);
-+void hfc_fifo_drop(struct hfc_chan_simplex *chan, int size);
-+int hfc_fifo_get_frame(struct hfc_chan_simplex *chan, void *data, int max_size);
-+void hfc_fifo_drop_frame(struct hfc_chan_simplex *chan);
-+void hfc_fifo_put_frame(struct hfc_chan_simplex *chan, void *data, int size);
-+void hfc_clear_fifo_rx(struct hfc_chan_simplex *chan);
-+void hfc_clear_fifo_tx(struct hfc_chan_simplex *chan);
-+
-+#endif
-diff -uNr dahdi-linux-2.7.0/drivers/dahdi/zaphfc/Kbuild dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/Kbuild
---- dahdi-linux-2.7.0/drivers/dahdi/zaphfc/Kbuild 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/dahdi/zaphfc/zaphfc.h dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/zaphfc.h
---- dahdi-linux-2.7.0/drivers/dahdi/zaphfc/zaphfc.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/dahdi/zaphfc/zaphfc.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,419 @@
-+/*
-+ * zaphfc.h - Dahdi driver for HFC-S PCI A based ISDN BRI cards
-+ *
-+ * Dahdi port by Jose A. Deniz <odicha@hotmail.com>
-+ *
-+ * Copyright (C) 2009 Jose A. Deniz
-+ * Copyright (C) 2006 headissue GmbH; Jens Wilke
-+ * Copyright (C) 2004 Daniele Orlandi
-+ * Copyright (C) 2002, 2003, 2004, Junghanns.NET GmbH
-+ *
-+ * Jens Wilke <jw_vzaphfc@headissue.com>
-+ *
-+ * Orginal author of this code is
-+ * Daniele "Vihai" Orlandi <daniele@orlandi.com>
-+ *
-+ * Major rewrite of the driver made by
-+ * Klaus-Peter Junghanns <kpj@junghanns.net>
-+ *
-+ * This program is free software and may be modified and
-+ * distributed under the terms of the GNU Public License.
-+ *
-+ */
-+
-+#ifndef _HFC_ZAPHFC_H
-+#define _HFC_ZAPHFC_H
-+
-+#include <asm/io.h>
-+
-+#define hfc_DRIVER_NAME "vzaphfc"
-+#define hfc_DRIVER_PREFIX hfc_DRIVER_NAME ": "
-+#define hfc_DRIVER_DESCR "HFC-S PCI A ISDN"
-+#define hfc_DRIVER_VERSION "1.42"
-+#define hfc_DRIVER_STRING hfc_DRIVER_DESCR " (V" hfc_DRIVER_VERSION ")"
-+
-+#define hfc_MAX_BOARDS 32
-+
-+#ifndef PCI_DMA_32BIT
-+#define PCI_DMA_32BIT 0x00000000ffffffffULL
-+#endif
-+
-+#ifndef PCI_VENDOR_ID_SITECOM
-+#define PCI_VENDOR_ID_SITECOM 0x182D
-+#endif
-+
-+#ifndef PCI_DEVICE_ID_SITECOM_3069
-+#define PCI_DEVICE_ID_SITECOM_3069 0x3069
-+#endif
-+
-+#define hfc_RESET_DELAY 20
-+
-+#define hfc_CLKDEL_TE 0x0f /* CLKDEL in TE mode */
-+#define hfc_CLKDEL_NT 0x6c /* CLKDEL in NT mode */
-+
-+/* PCI memory mapped I/O */
-+
-+#define hfc_PCI_MEM_SIZE 0x0100
-+#define hfc_PCI_MWBA 0x80
-+
-+/* GCI/IOM bus monitor registers */
-+
-+#define hfc_C_I 0x08
-+#define hfc_TRxR 0x0C
-+#define hfc_MON1_D 0x28
-+#define hfc_MON2_D 0x2C
-+
-+
-+/* GCI/IOM bus timeslot registers */
-+
-+#define hfc_B1_SSL 0x80
-+#define hfc_B2_SSL 0x84
-+#define hfc_AUX1_SSL 0x88
-+#define hfc_AUX2_SSL 0x8C
-+#define hfc_B1_RSL 0x90
-+#define hfc_B2_RSL 0x94
-+#define hfc_AUX1_RSL 0x98
-+#define hfc_AUX2_RSL 0x9C
-+
-+/* GCI/IOM bus data registers */
-+
-+#define hfc_B1_D 0xA0
-+#define hfc_B2_D 0xA4
-+#define hfc_AUX1_D 0xA8
-+#define hfc_AUX2_D 0xAC
-+
-+/* GCI/IOM bus configuration registers */
-+
-+#define hfc_MST_EMOD 0xB4
-+#define hfc_MST_MODE 0xB8
-+#define hfc_CONNECT 0xBC
-+
-+
-+/* Interrupt and status registers */
-+
-+#define hfc_FIFO_EN 0x44
-+#define hfc_TRM 0x48
-+#define hfc_B_MODE 0x4C
-+#define hfc_CHIP_ID 0x58
-+#define hfc_CIRM 0x60
-+#define hfc_CTMT 0x64
-+#define hfc_INT_M1 0x68
-+#define hfc_INT_M2 0x6C
-+#define hfc_INT_S1 0x78
-+#define hfc_INT_S2 0x7C
-+#define hfc_STATUS 0x70
-+
-+/* S/T section registers */
-+
-+#define hfc_STATES 0xC0
-+#define hfc_SCTRL 0xC4
-+#define hfc_SCTRL_E 0xC8
-+#define hfc_SCTRL_R 0xCC
-+#define hfc_SQ 0xD0
-+#define hfc_CLKDEL 0xDC
-+#define hfc_B1_REC 0xF0
-+#define hfc_B1_SEND 0xF0
-+#define hfc_B2_REC 0xF4
-+#define hfc_B2_SEND 0xF4
-+#define hfc_D_REC 0xF8
-+#define hfc_D_SEND 0xF8
-+#define hfc_E_REC 0xFC
-+
-+/* Bits and values in various HFC PCI registers */
-+
-+/* bits in status register (READ) */
-+#define hfc_STATUS_PCI_PROC 0x02
-+#define hfc_STATUS_NBUSY 0x04
-+#define hfc_STATUS_TIMER_ELAP 0x10
-+#define hfc_STATUS_STATINT 0x20
-+#define hfc_STATUS_FRAMEINT 0x40
-+#define hfc_STATUS_ANYINT 0x80
-+
-+/* bits in CTMT (Write) */
-+#define hfc_CTMT_TRANSB1 0x01
-+#define hfc_CTMT_TRANSB2 0x02
-+#define hfc_CTMT_TIMER_CLEAR 0x80
-+#define hfc_CTMT_TIMER_MASK 0x1C
-+#define hfc_CTMT_TIMER_3_125 (0x01 << 2)
-+#define hfc_CTMT_TIMER_6_25 (0x02 << 2)
-+#define hfc_CTMT_TIMER_12_5 (0x03 << 2)
-+#define hfc_CTMT_TIMER_25 (0x04 << 2)
-+#define hfc_CTMT_TIMER_50 (0x05 << 2)
-+#define hfc_CTMT_TIMER_400 (0x06 << 2)
-+#define hfc_CTMT_TIMER_800 (0x07 << 2)
-+#define hfc_CTMT_AUTO_TIMER 0x20
-+
-+/* bits in CIRM (Write) */
-+#define hfc_CIRM_AUX_MSK 0x07
-+#define hfc_CIRM_RESET 0x08
-+#define hfc_CIRM_B1_REV 0x40
-+#define hfc_CIRM_B2_REV 0x80
-+
-+/* bits in INT_M1 and INT_S1 */
-+#define hfc_INTS_B1TRANS 0x01
-+#define hfc_INTS_B2TRANS 0x02
-+#define hfc_INTS_DTRANS 0x04
-+#define hfc_INTS_B1REC 0x08
-+#define hfc_INTS_B2REC 0x10
-+#define hfc_INTS_DREC 0x20
-+#define hfc_INTS_L1STATE 0x40
-+#define hfc_INTS_TIMER 0x80
-+
-+/* bits in INT_M2 */
-+#define hfc_M2_PROC_TRANS 0x01
-+#define hfc_M2_GCI_I_CHG 0x02
-+#define hfc_M2_GCI_MON_REC 0x04
-+#define hfc_M2_IRQ_ENABLE 0x08
-+#define hfc_M2_PMESEL 0x80
-+
-+/* bits in STATES */
-+#define hfc_STATES_STATE_MASK 0x0F
-+#define hfc_STATES_LOAD_STATE 0x10
-+#define hfc_STATES_ACTIVATE 0x20
-+#define hfc_STATES_DO_ACTION 0x40
-+#define hfc_STATES_NT_G2_G3 0x80
-+
-+/* bits in HFCD_MST_MODE */
-+#define hfc_MST_MODE_MASTER 0x01
-+#define hfc_MST_MODE_SLAVE 0x00
-+/* remaining bits are for codecs control */
-+
-+/* bits in HFCD_SCTRL */
-+#define hfc_SCTRL_B1_ENA 0x01
-+#define hfc_SCTRL_B2_ENA 0x02
-+#define hfc_SCTRL_MODE_TE 0x00
-+#define hfc_SCTRL_MODE_NT 0x04
-+#define hfc_SCTRL_LOW_PRIO 0x08
-+#define hfc_SCTRL_SQ_ENA 0x10
-+#define hfc_SCTRL_TEST 0x20
-+#define hfc_SCTRL_NONE_CAP 0x40
-+#define hfc_SCTRL_PWR_DOWN 0x80
-+
-+/* bits in SCTRL_E */
-+#define hfc_SCTRL_E_AUTO_AWAKE 0x01
-+#define hfc_SCTRL_E_DBIT_1 0x04
-+#define hfc_SCTRL_E_IGNORE_COL 0x08
-+#define hfc_SCTRL_E_CHG_B1_B2 0x80
-+
-+/* bits in SCTRL_R */
-+#define hfc_SCTRL_R_B1_ENA 0x01
-+#define hfc_SCTRL_R_B2_ENA 0x02
-+
-+/* bits in FIFO_EN register */
-+#define hfc_FIFOEN_B1TX 0x01
-+#define hfc_FIFOEN_B1RX 0x02
-+#define hfc_FIFOEN_B2TX 0x04
-+#define hfc_FIFOEN_B2RX 0x08
-+#define hfc_FIFOEN_DTX 0x10
-+#define hfc_FIFOEN_DRX 0x20
-+
-+#define hfc_FIFOEN_B1 (hfc_FIFOEN_B1TX|hfc_FIFOEN_B1RX)
-+#define hfc_FIFOEN_B2 (hfc_FIFOEN_B2TX|hfc_FIFOEN_B2RX)
-+#define hfc_FIFOEN_D (hfc_FIFOEN_DTX|hfc_FIFOEN_DRX)
-+
-+/* bits in the CONNECT register */
-+#define hfc_CONNECT_B1_HFC_from_ST 0x00
-+#define hfc_CONNECT_B1_HFC_from_GCI 0x01
-+#define hfc_CONNECT_B1_ST_from_HFC 0x00
-+#define hfc_CONNECT_B1_ST_from_GCI 0x02
-+#define hfc_CONNECT_B1_GCI_from_HFC 0x00
-+#define hfc_CONNECT_B1_GCI_from_ST 0x04
-+
-+#define hfc_CONNECT_B2_HFC_from_ST 0x00
-+#define hfc_CONNECT_B2_HFC_from_GCI 0x08
-+#define hfc_CONNECT_B2_ST_from_HFC 0x00
-+#define hfc_CONNECT_B2_ST_from_GCI 0x10
-+#define hfc_CONNECT_B2_GCI_from_HFC 0x00
-+#define hfc_CONNECT_B2_GCI_from_ST 0x20
-+
-+/* bits in the TRM register */
-+#define hfc_TRM_TRANS_INT_00 0x00
-+#define hfc_TRM_TRANS_INT_01 0x01
-+#define hfc_TRM_TRANS_INT_10 0x02
-+#define hfc_TRM_TRANS_INT_11 0x04
-+#define hfc_TRM_ECHO 0x20
-+#define hfc_TRM_B1_PLUS_B2 0x40
-+#define hfc_TRM_IOM_TEST_LOOP 0x80
-+
-+/* bits in the __SSL and __RSL registers */
-+#define hfc_SRSL_STIO 0x40
-+#define hfc_SRSL_ENABLE 0x80
-+#define hfc_SRCL_SLOT_MASK 0x1f
-+
-+/* FIFO memory definitions */
-+
-+#define hfc_FIFO_SIZE 0x8000
-+
-+#define hfc_UGLY_FRAMEBUF 0x2000
-+
-+#define hfc_TX_FIFO_PRELOAD (DAHDI_CHUNKSIZE + 2)
-+#define hfc_RX_FIFO_PRELOAD 4
-+
-+/* HDLC STUFF */
-+#define hfc_HDLC_BUF_LEN 32
-+/* arbitrary, just the max # of byts we will send to DAHDI per call */
-+
-+
-+/* NOTE: FIFO pointers are not declared volatile because accesses to the
-+ * FIFOs are inherently safe.
-+ */
-+
-+#ifdef DEBUG
-+extern int debug_level;
-+#endif
-+
-+struct hfc_chan;
-+
-+struct hfc_chan_simplex {
-+ struct hfc_chan_duplex *chan;
-+
-+ u8 zaptel_buffer[DAHDI_CHUNKSIZE];
-+
-+ u8 ugly_framebuf[hfc_UGLY_FRAMEBUF];
-+ int ugly_framebuf_size;
-+ u16 ugly_framebuf_off;
-+
-+ void *z1_base, *z2_base;
-+ void *fifo_base;
-+ void *z_base;
-+ u16 z_min;
-+ u16 z_max;
-+ u16 fifo_size;
-+
-+ u8 *f1, *f2;
-+ u8 f_min;
-+ u8 f_max;
-+ u8 f_num;
-+
-+ unsigned long long frames;
-+ unsigned long long bytes;
-+ unsigned long long fifo_full;
-+ unsigned long long crc;
-+ unsigned long long fifo_underrun;
-+};
-+
-+enum hfc_chan_status {
-+ free,
-+ open_framed,
-+ open_voice,
-+ sniff_aux,
-+ loopback,
-+};
-+
-+struct hfc_chan_duplex {
-+ struct hfc_card *card;
-+
-+ char *name;
-+ int number;
-+
-+ enum hfc_chan_status status;
-+ int open_by_netdev;
-+ int open_by_zaptel;
-+
-+ unsigned short protocol;
-+
-+ spinlock_t lock;
-+
-+ struct hfc_chan_simplex rx;
-+ struct hfc_chan_simplex tx;
-+
-+};
-+
-+typedef struct hfc_card {
-+ int cardnum;
-+ struct pci_dev *pcidev;
-+ struct dahdi_hfc *ztdev;
-+ struct proc_dir_entry *proc_dir;
-+ char proc_dir_name[32];
-+
-+ struct proc_dir_entry *proc_info;
-+ struct proc_dir_entry *proc_fifos;
-+ struct proc_dir_entry *proc_bufs;
-+
-+ unsigned long io_bus_mem;
-+ void __iomem *io_mem;
-+
-+ dma_addr_t fifo_bus_mem;
-+ void *fifo_mem;
-+ void *fifos;
-+
-+ int nt_mode;
-+ int sync_loss_reported;
-+ int late_irqs;
-+
-+ u8 l1_state;
-+ int fifo_suspended;
-+ int ignore_first_timer_interrupt;
-+
-+ struct {
-+ u8 m1;
-+ u8 m2;
-+ u8 fifo_en;
-+ u8 trm;
-+ u8 connect;
-+ u8 sctrl;
-+ u8 sctrl_r;
-+ u8 sctrl_e;
-+ u8 ctmt;
-+ u8 cirm;
-+ } regs;
-+
-+ struct hfc_chan_duplex chans[3];
-+ int echo_enabled;
-+
-+
-+
-+ int debug_event;
-+
-+ spinlock_t lock;
-+ unsigned int irq;
-+ unsigned int iomem;
-+ int ticks;
-+ int clicks;
-+ unsigned char *pci_io;
-+ void *fifomem; /* start of the shared mem */
-+
-+ unsigned int pcibus;
-+ unsigned int pcidevfn;
-+
-+ int drecinframe;
-+
-+ unsigned char cardno;
-+ struct hfc_card *next;
-+
-+} hfc_card;
-+
-+typedef struct dahdi_hfc {
-+ unsigned int usecount;
-+ struct dahdi_device *ddev;
-+ struct dahdi_span span;
-+ struct dahdi_chan chans[3];
-+ struct dahdi_chan *_chans[3];
-+ struct hfc_card *card;
-+
-+ /* pointer to the signalling channel for this span */
-+ struct dahdi_chan *sigchan;
-+ /* nonzero means we're in the middle of sending an HDLC frame */
-+ int sigactive;
-+ /* hdlc_hard_xmit() increments, hdlc_tx_frame() decrements */
-+ atomic_t hdlc_pending;
-+ int frames_out;
-+ int frames_in;
-+} dahdi_hfc;
-+
-+static inline struct dahdi_hfc *dahdi_hfc_from_span(struct dahdi_span *span)
-+{
-+ return container_of(span, struct dahdi_hfc, span);
-+}
-+
-+static inline u8 hfc_inb(struct hfc_card *card, int offset)
-+{
-+ return readb(card->io_mem + offset);
-+}
-+
-+static inline void hfc_outb(struct hfc_card *card, int offset, u8 value)
-+{
-+ writeb(value, card->io_mem + offset);
-+}
-+
-+#endif
-diff -uNr dahdi-linux-2.7.0/drivers/staging/echo/echo.c dahdi-extra-dahdi-linux/drivers/staging/echo/echo.c
---- dahdi-linux-2.7.0/drivers/staging/echo/echo.c 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/echo.c 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,662 @@
-+/*
-+ * SpanDSP - a series of DSP components for telephony
-+ *
-+ * echo.c - A line echo canceller. This code is being developed
-+ * against and partially complies with G168.
-+ *
-+ * Written by Steve Underwood <steveu@coppice.org>
-+ * and David Rowe <david_at_rowetel_dot_com>
-+ *
-+ * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
-+ *
-+ * Based on a bit from here, a bit from there, eye of toad, ear of
-+ * bat, 15 years of failed attempts by David and a few fried brain
-+ * cells.
-+ *
-+ * 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 version 2, as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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.
-+ */
-+
-+/*! \file */
-+
-+/* Implementation Notes
-+ David Rowe
-+ April 2007
-+
-+ This code started life as Steve's NLMS algorithm with a tap
-+ rotation algorithm to handle divergence during double talk. I
-+ added a Geigel Double Talk Detector (DTD) [2] and performed some
-+ G168 tests. However I had trouble meeting the G168 requirements,
-+ especially for double talk - there were always cases where my DTD
-+ failed, for example where near end speech was under the 6dB
-+ threshold required for declaring double talk.
-+
-+ So I tried a two path algorithm [1], which has so far given better
-+ results. The original tap rotation/Geigel algorithm is available
-+ in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit.
-+ It's probably possible to make it work if some one wants to put some
-+ serious work into it.
-+
-+ At present no special treatment is provided for tones, which
-+ generally cause NLMS algorithms to diverge. Initial runs of a
-+ subset of the G168 tests for tones (e.g ./echo_test 6) show the
-+ current algorithm is passing OK, which is kind of surprising. The
-+ full set of tests needs to be performed to confirm this result.
-+
-+ One other interesting change is that I have managed to get the NLMS
-+ code to work with 16 bit coefficients, rather than the original 32
-+ bit coefficents. This reduces the MIPs and storage required.
-+ I evaulated the 16 bit port using g168_tests.sh and listening tests
-+ on 4 real-world samples.
-+
-+ I also attempted the implementation of a block based NLMS update
-+ [2] but although this passes g168_tests.sh it didn't converge well
-+ on the real-world samples. I have no idea why, perhaps a scaling
-+ problem. The block based code is also available in SVN
-+ http://svn.rowetel.com/software/oslec/tags/before_16bit. If this
-+ code can be debugged, it will lead to further reduction in MIPS, as
-+ the block update code maps nicely onto DSP instruction sets (it's a
-+ dot product) compared to the current sample-by-sample update.
-+
-+ Steve also has some nice notes on echo cancellers in echo.h
-+
-+ References:
-+
-+ [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
-+ Path Models", IEEE Transactions on communications, COM-25,
-+ No. 6, June
-+ 1977.
-+ http://www.rowetel.com/images/echo/dual_path_paper.pdf
-+
-+ [2] The classic, very useful paper that tells you how to
-+ actually build a real world echo canceller:
-+ Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
-+ Echo Canceller with a TMS320020,
-+ http://www.rowetel.com/images/echo/spra129.pdf
-+
-+ [3] I have written a series of blog posts on this work, here is
-+ Part 1: http://www.rowetel.com/blog/?p=18
-+
-+ [4] The source code http://svn.rowetel.com/software/oslec/
-+
-+ [5] A nice reference on LMS filters:
-+ http://en.wikipedia.org/wiki/Least_mean_squares_filter
-+
-+ Credits:
-+
-+ Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
-+ Muthukrishnan for their suggestions and email discussions. Thanks
-+ also to those people who collected echo samples for me such as
-+ Mark, Pawel, and Pavel.
-+*/
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+
-+#include "echo.h"
-+
-+#define MIN_TX_POWER_FOR_ADAPTION 64
-+#define MIN_RX_POWER_FOR_ADAPTION 64
-+#define DTD_HANGOVER 600 /* 600 samples, or 75ms */
-+#define DC_LOG2BETA 3 /* log2() of DC filter Beta */
-+
-+
-+/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
-+
-+#ifdef __bfin__
-+static inline void lms_adapt_bg(struct oslec_state *ec, int clean,
-+ int shift)
-+{
-+ int i, j;
-+ int offset1;
-+ int offset2;
-+ int factor;
-+ int exp;
-+ int16_t *phist;
-+ int n;
-+
-+ if (shift > 0)
-+ factor = clean << shift;
-+ else
-+ factor = clean >> -shift;
-+
-+ /* Update the FIR taps */
-+
-+ offset2 = ec->curr_pos;
-+ offset1 = ec->taps - offset2;
-+ phist = &ec->fir_state_bg.history[offset2];
-+
-+ /* st: and en: help us locate the assembler in echo.s */
-+
-+ /* asm("st:"); */
-+ n = ec->taps;
-+ for (i = 0, j = offset2; i < n; i++, j++) {
-+ exp = *phist++ * factor;
-+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
-+ }
-+ /* asm("en:"); */
-+
-+ /* Note the asm for the inner loop above generated by Blackfin gcc
-+ 4.1.1 is pretty good (note even parallel instructions used):
-+
-+ R0 = W [P0++] (X);
-+ R0 *= R2;
-+ R0 = R0 + R3 (NS) ||
-+ R1 = W [P1] (X) ||
-+ nop;
-+ R0 >>>= 15;
-+ R0 = R0 + R1;
-+ W [P1++] = R0;
-+
-+ A block based update algorithm would be much faster but the
-+ above can't be improved on much. Every instruction saved in
-+ the loop above is 2 MIPs/ch! The for loop above is where the
-+ Blackfin spends most of it's time - about 17 MIPs/ch measured
-+ with speedtest.c with 256 taps (32ms). Write-back and
-+ Write-through cache gave about the same performance.
-+ */
-+}
-+
-+/*
-+ IDEAS for further optimisation of lms_adapt_bg():
-+
-+ 1/ The rounding is quite costly. Could we keep as 32 bit coeffs
-+ then make filter pluck the MS 16-bits of the coeffs when filtering?
-+ However this would lower potential optimisation of filter, as I
-+ think the dual-MAC architecture requires packed 16 bit coeffs.
-+
-+ 2/ Block based update would be more efficient, as per comments above,
-+ could use dual MAC architecture.
-+
-+ 3/ Look for same sample Blackfin LMS code, see if we can get dual-MAC
-+ packing.
-+
-+ 4/ Execute the whole e/c in a block of say 20ms rather than sample
-+ by sample. Processing a few samples every ms is inefficient.
-+*/
-+
-+#else
-+static inline void lms_adapt_bg(struct oslec_state *ec, int clean,
-+ int shift)
-+{
-+ int i;
-+
-+ int offset1;
-+ int offset2;
-+ int factor;
-+ int exp;
-+
-+ if (shift > 0)
-+ factor = clean << shift;
-+ else
-+ factor = clean >> -shift;
-+
-+ /* Update the FIR taps */
-+
-+ offset2 = ec->curr_pos;
-+ offset1 = ec->taps - offset2;
-+
-+ for (i = ec->taps - 1; i >= offset1; i--) {
-+ exp = (ec->fir_state_bg.history[i - offset1] * factor);
-+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
-+ }
-+ for (; i >= 0; i--) {
-+ exp = (ec->fir_state_bg.history[i + offset2] * factor);
-+ ec->fir_taps16[1][i] += (int16_t) ((exp + (1 << 14)) >> 15);
-+ }
-+}
-+#endif
-+
-+static inline int top_bit(unsigned int bits)
-+{
-+ if (bits == 0)
-+ return -1;
-+ else
-+ return (int)fls((int32_t)bits)-1;
-+}
-+
-+struct oslec_state *oslec_create(int len, int adaption_mode)
-+{
-+ struct oslec_state *ec;
-+ int i;
-+
-+ ec = kzalloc(sizeof(*ec), GFP_KERNEL);
-+ if (!ec)
-+ return NULL;
-+
-+ ec->taps = len;
-+ ec->log2taps = top_bit(len);
-+ ec->curr_pos = ec->taps - 1;
-+
-+ for (i = 0; i < 2; i++) {
-+ ec->fir_taps16[i] =
-+ kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
-+ if (!ec->fir_taps16[i])
-+ goto error_oom;
-+ }
-+
-+ fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
-+ fir16_create(&ec->fir_state_bg, ec->fir_taps16[1], ec->taps);
-+
-+ for (i = 0; i < 5; i++)
-+ ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
-+
-+ ec->cng_level = 1000;
-+ oslec_adaption_mode(ec, adaption_mode);
-+
-+ ec->snapshot = kcalloc(ec->taps, sizeof(int16_t), GFP_KERNEL);
-+ if (!ec->snapshot)
-+ goto error_oom;
-+
-+ ec->cond_met = 0;
-+ ec->Pstates = 0;
-+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
-+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
-+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
-+ ec->Lbgn = ec->Lbgn_acc = 0;
-+ ec->Lbgn_upper = 200;
-+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
-+
-+ return ec;
-+
-+error_oom:
-+ for (i = 0; i < 2; i++)
-+ kfree(ec->fir_taps16[i]);
-+
-+ kfree(ec);
-+ return NULL;
-+}
-+EXPORT_SYMBOL_GPL(oslec_create);
-+
-+void oslec_free(struct oslec_state *ec)
-+{
-+ int i;
-+
-+ fir16_free(&ec->fir_state);
-+ fir16_free(&ec->fir_state_bg);
-+ for (i = 0; i < 2; i++)
-+ kfree(ec->fir_taps16[i]);
-+ kfree(ec->snapshot);
-+ kfree(ec);
-+}
-+EXPORT_SYMBOL_GPL(oslec_free);
-+
-+void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode)
-+{
-+ ec->adaption_mode = adaption_mode;
-+}
-+EXPORT_SYMBOL_GPL(oslec_adaption_mode);
-+
-+void oslec_flush(struct oslec_state *ec)
-+{
-+ int i;
-+
-+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
-+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
-+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
-+
-+ ec->Lbgn = ec->Lbgn_acc = 0;
-+ ec->Lbgn_upper = 200;
-+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
-+
-+ ec->nonupdate_dwell = 0;
-+
-+ fir16_flush(&ec->fir_state);
-+ fir16_flush(&ec->fir_state_bg);
-+ ec->fir_state.curr_pos = ec->taps - 1;
-+ ec->fir_state_bg.curr_pos = ec->taps - 1;
-+ for (i = 0; i < 2; i++)
-+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
-+
-+ ec->curr_pos = ec->taps - 1;
-+ ec->Pstates = 0;
-+}
-+EXPORT_SYMBOL_GPL(oslec_flush);
-+
-+void oslec_snapshot(struct oslec_state *ec)
-+{
-+ memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps * sizeof(int16_t));
-+}
-+EXPORT_SYMBOL_GPL(oslec_snapshot);
-+
-+/* Dual Path Echo Canceller */
-+
-+int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx)
-+{
-+ int32_t echo_value;
-+ int clean_bg;
-+ int tmp, tmp1;
-+
-+ /*
-+ * Input scaling was found be required to prevent problems when tx
-+ * starts clipping. Another possible way to handle this would be the
-+ * filter coefficent scaling.
-+ */
-+
-+ ec->tx = tx;
-+ ec->rx = rx;
-+ tx >>= 1;
-+ rx >>= 1;
-+
-+ /*
-+ * Filter DC, 3dB point is 160Hz (I think), note 32 bit precision
-+ * required otherwise values do not track down to 0. Zero at DC, Pole
-+ * at (1-Beta) on real axis. Some chip sets (like Si labs) don't
-+ * need this, but something like a $10 X100P card does. Any DC really
-+ * slows down convergence.
-+ *
-+ * Note: removes some low frequency from the signal, this reduces the
-+ * speech quality when listening to samples through headphones but may
-+ * not be obvious through a telephone handset.
-+ *
-+ * Note that the 3dB frequency in radians is approx Beta, e.g. for Beta
-+ * = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
-+ */
-+
-+ if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
-+ tmp = rx << 15;
-+
-+ /*
-+ * Make sure the gain of the HPF is 1.0. This can still
-+ * saturate a little under impulse conditions, and it might
-+ * roll to 32768 and need clipping on sustained peak level
-+ * signals. However, the scale of such clipping is small, and
-+ * the error due to any saturation should not markedly affect
-+ * the downstream processing.
-+ */
-+ tmp -= (tmp >> 4);
-+
-+ ec->rx_1 += -(ec->rx_1 >> DC_LOG2BETA) + tmp - ec->rx_2;
-+
-+ /*
-+ * hard limit filter to prevent clipping. Note that at this
-+ * stage rx should be limited to +/- 16383 due to right shift
-+ * above
-+ */
-+ tmp1 = ec->rx_1 >> 15;
-+ if (tmp1 > 16383)
-+ tmp1 = 16383;
-+ if (tmp1 < -16383)
-+ tmp1 = -16383;
-+ rx = tmp1;
-+ ec->rx_2 = tmp;
-+ }
-+
-+ /* Block average of power in the filter states. Used for
-+ adaption power calculation. */
-+
-+ {
-+ int new, old;
-+
-+ /* efficient "out with the old and in with the new" algorithm so
-+ we don't have to recalculate over the whole block of
-+ samples. */
-+ new = (int)tx * (int)tx;
-+ old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
-+ (int)ec->fir_state.history[ec->fir_state.curr_pos];
-+ ec->Pstates +=
-+ ((new - old) + (1 << (ec->log2taps-1))) >> ec->log2taps;
-+ if (ec->Pstates < 0)
-+ ec->Pstates = 0;
-+ }
-+
-+ /* Calculate short term average levels using simple single pole IIRs */
-+
-+ ec->Ltxacc += abs(tx) - ec->Ltx;
-+ ec->Ltx = (ec->Ltxacc + (1 << 4)) >> 5;
-+ ec->Lrxacc += abs(rx) - ec->Lrx;
-+ ec->Lrx = (ec->Lrxacc + (1 << 4)) >> 5;
-+
-+ /* Foreground filter */
-+
-+ ec->fir_state.coeffs = ec->fir_taps16[0];
-+ echo_value = fir16(&ec->fir_state, tx);
-+ ec->clean = rx - echo_value;
-+ ec->Lcleanacc += abs(ec->clean) - ec->Lclean;
-+ ec->Lclean = (ec->Lcleanacc + (1 << 4)) >> 5;
-+
-+ /* Background filter */
-+
-+ echo_value = fir16(&ec->fir_state_bg, tx);
-+ clean_bg = rx - echo_value;
-+ ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg;
-+ ec->Lclean_bg = (ec->Lclean_bgacc + (1 << 4)) >> 5;
-+
-+ /* Background Filter adaption */
-+
-+ /* Almost always adap bg filter, just simple DT and energy
-+ detection to minimise adaption in cases of strong double talk.
-+ However this is not critical for the dual path algorithm.
-+ */
-+ ec->factor = 0;
-+ ec->shift = 0;
-+ if ((ec->nonupdate_dwell == 0)) {
-+ int P, logP, shift;
-+
-+ /* Determine:
-+
-+ f = Beta * clean_bg_rx/P ------ (1)
-+
-+ where P is the total power in the filter states.
-+
-+ The Boffins have shown that if we obey (1) we converge
-+ quickly and avoid instability.
-+
-+ The correct factor f must be in Q30, as this is the fixed
-+ point format required by the lms_adapt_bg() function,
-+ therefore the scaled version of (1) is:
-+
-+ (2^30) * f = (2^30) * Beta * clean_bg_rx/P
-+ factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
-+
-+ We have chosen Beta = 0.25 by experiment, so:
-+
-+ factor = (2^30) * (2^-2) * clean_bg_rx/P
-+
-+ (30 - 2 - log2(P))
-+ factor = clean_bg_rx 2 ----- (3)
-+
-+ To avoid a divide we approximate log2(P) as top_bit(P),
-+ which returns the position of the highest non-zero bit in
-+ P. This approximation introduces an error as large as a
-+ factor of 2, but the algorithm seems to handle it OK.
-+
-+ Come to think of it a divide may not be a big deal on a
-+ modern DSP, so its probably worth checking out the cycles
-+ for a divide versus a top_bit() implementation.
-+ */
-+
-+ P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates;
-+ logP = top_bit(P) + ec->log2taps;
-+ shift = 30 - 2 - logP;
-+ ec->shift = shift;
-+
-+ lms_adapt_bg(ec, clean_bg, shift);
-+ }
-+
-+ /* very simple DTD to make sure we dont try and adapt with strong
-+ near end speech */
-+
-+ ec->adapt = 0;
-+ if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx))
-+ ec->nonupdate_dwell = DTD_HANGOVER;
-+ if (ec->nonupdate_dwell)
-+ ec->nonupdate_dwell--;
-+
-+ /* Transfer logic */
-+
-+ /* These conditions are from the dual path paper [1], I messed with
-+ them a bit to improve performance. */
-+
-+ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
-+ (ec->nonupdate_dwell == 0) &&
-+ /* (ec->Lclean_bg < 0.875*ec->Lclean) */
-+ (8 * ec->Lclean_bg < 7 * ec->Lclean) &&
-+ /* (ec->Lclean_bg < 0.125*ec->Ltx) */
-+ (8 * ec->Lclean_bg < ec->Ltx)) {
-+ if (ec->cond_met == 6) {
-+ /*
-+ * BG filter has had better results for 6 consecutive
-+ * samples
-+ */
-+ ec->adapt = 1;
-+ memcpy(ec->fir_taps16[0], ec->fir_taps16[1],
-+ ec->taps * sizeof(int16_t));
-+ } else
-+ ec->cond_met++;
-+ } else
-+ ec->cond_met = 0;
-+
-+ /* Non-Linear Processing */
-+
-+ ec->clean_nlp = ec->clean;
-+ if (ec->adaption_mode & ECHO_CAN_USE_NLP) {
-+ /*
-+ * Non-linear processor - a fancy way to say "zap small
-+ * signals, to avoid residual echo due to (uLaw/ALaw)
-+ * non-linearity in the channel.".
-+ */
-+
-+ if ((16 * ec->Lclean < ec->Ltx)) {
-+ /*
-+ * Our e/c has improved echo by at least 24 dB (each
-+ * factor of 2 is 6dB, so 2*2*2*2=16 is the same as
-+ * 6+6+6+6=24dB)
-+ */
-+ if (ec->adaption_mode & ECHO_CAN_USE_CNG) {
-+ ec->cng_level = ec->Lbgn;
-+
-+ /*
-+ * Very elementary comfort noise generation.
-+ * Just random numbers rolled off very vaguely
-+ * Hoth-like. DR: This noise doesn't sound
-+ * quite right to me - I suspect there are some
-+ * overlfow issues in the filtering as it's too
-+ * "crackly".
-+ * TODO: debug this, maybe just play noise at
-+ * high level or look at spectrum.
-+ */
-+
-+ ec->cng_rndnum =
-+ 1664525U * ec->cng_rndnum + 1013904223U;
-+ ec->cng_filter =
-+ ((ec->cng_rndnum & 0xFFFF) - 32768 +
-+ 5 * ec->cng_filter) >> 3;
-+ ec->clean_nlp =
-+ (ec->cng_filter * ec->cng_level * 8) >> 14;
-+
-+ } else if (ec->adaption_mode & ECHO_CAN_USE_CLIP) {
-+ /* This sounds much better than CNG */
-+ if (ec->clean_nlp > ec->Lbgn)
-+ ec->clean_nlp = ec->Lbgn;
-+ if (ec->clean_nlp < -ec->Lbgn)
-+ ec->clean_nlp = -ec->Lbgn;
-+ } else {
-+ /*
-+ * just mute the residual, doesn't sound very
-+ * good, used mainly in G168 tests
-+ */
-+ ec->clean_nlp = 0;
-+ }
-+ } else {
-+ /*
-+ * Background noise estimator. I tried a few
-+ * algorithms here without much luck. This very simple
-+ * one seems to work best, we just average the level
-+ * using a slow (1 sec time const) filter if the
-+ * current level is less than a (experimentally
-+ * derived) constant. This means we dont include high
-+ * level signals like near end speech. When combined
-+ * with CNG or especially CLIP seems to work OK.
-+ */
-+ if (ec->Lclean < 40) {
-+ ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn;
-+ ec->Lbgn = (ec->Lbgn_acc + (1 << 11)) >> 12;
-+ }
-+ }
-+ }
-+
-+ /* Roll around the taps buffer */
-+ if (ec->curr_pos <= 0)
-+ ec->curr_pos = ec->taps;
-+ ec->curr_pos--;
-+
-+ if (ec->adaption_mode & ECHO_CAN_DISABLE)
-+ ec->clean_nlp = rx;
-+
-+ /* Output scaled back up again to match input scaling */
-+
-+ return (int16_t) ec->clean_nlp << 1;
-+}
-+EXPORT_SYMBOL_GPL(oslec_update);
-+
-+/* This function is seperated from the echo canceller is it is usually called
-+ as part of the tx process. See rx HP (DC blocking) filter above, it's
-+ the same design.
-+
-+ Some soft phones send speech signals with a lot of low frequency
-+ energy, e.g. down to 20Hz. This can make the hybrid non-linear
-+ which causes the echo canceller to fall over. This filter can help
-+ by removing any low frequency before it gets to the tx port of the
-+ hybrid.
-+
-+ It can also help by removing and DC in the tx signal. DC is bad
-+ for LMS algorithms.
-+
-+ This is one of the classic DC removal filters, adjusted to provide
-+ sufficient bass rolloff to meet the above requirement to protect hybrids
-+ from things that upset them. The difference between successive samples
-+ produces a lousy HPF, and then a suitably placed pole flattens things out.
-+ The final result is a nicely rolled off bass end. The filtering is
-+ implemented with extended fractional precision, which noise shapes things,
-+ giving very clean DC removal.
-+*/
-+
-+int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx)
-+{
-+ int tmp, tmp1;
-+
-+ if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
-+ tmp = tx << 15;
-+
-+ /*
-+ * Make sure the gain of the HPF is 1.0. The first can still
-+ * saturate a little under impulse conditions, and it might
-+ * roll to 32768 and need clipping on sustained peak level
-+ * signals. However, the scale of such clipping is small, and
-+ * the error due to any saturation should not markedly affect
-+ * the downstream processing.
-+ */
-+ tmp -= (tmp >> 4);
-+
-+ ec->tx_1 += -(ec->tx_1 >> DC_LOG2BETA) + tmp - ec->tx_2;
-+ tmp1 = ec->tx_1 >> 15;
-+ if (tmp1 > 32767)
-+ tmp1 = 32767;
-+ if (tmp1 < -32767)
-+ tmp1 = -32767;
-+ tx = tmp1;
-+ ec->tx_2 = tmp;
-+ }
-+
-+ return tx;
-+}
-+EXPORT_SYMBOL_GPL(oslec_hpf_tx);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Rowe");
-+MODULE_DESCRIPTION("Open Source Line Echo Canceller");
-+MODULE_VERSION("0.3.0");
-diff -uNr dahdi-linux-2.7.0/drivers/staging/echo/echo.h dahdi-extra-dahdi-linux/drivers/staging/echo/echo.h
---- dahdi-linux-2.7.0/drivers/staging/echo/echo.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/echo.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,175 @@
-+/*
-+ * SpanDSP - a series of DSP components for telephony
-+ *
-+ * echo.c - A line echo canceller. This code is being developed
-+ * against and partially complies with G168.
-+ *
-+ * Written by Steve Underwood <steveu@coppice.org>
-+ * and David Rowe <david_at_rowetel_dot_com>
-+ *
-+ * Copyright (C) 2001 Steve Underwood and 2007 David Rowe
-+ *
-+ * 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 version 2, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#ifndef __ECHO_H
-+#define __ECHO_H
-+
-+/*
-+Line echo cancellation for voice
-+
-+What does it do?
-+
-+This module aims to provide G.168-2002 compliant echo cancellation, to remove
-+electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
-+
-+
-+How does it work?
-+
-+The heart of the echo cancellor is FIR filter. This is adapted to match the
-+echo impulse response of the telephone line. It must be long enough to
-+adequately cover the duration of that impulse response. The signal transmitted
-+to the telephone line is passed through the FIR filter. Once the FIR is
-+properly adapted, the resulting output is an estimate of the echo signal
-+received from the line. This is subtracted from the received signal. The result
-+is an estimate of the signal which originated at the far end of the line, free
-+from echos of our own transmitted signal.
-+
-+The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and
-+was introduced in 1960. It is the commonest form of filter adaption used in
-+things like modem line equalisers and line echo cancellers. There it works very
-+well. However, it only works well for signals of constant amplitude. It works
-+very poorly for things like speech echo cancellation, where the signal level
-+varies widely. This is quite easy to fix. If the signal level is normalised -
-+similar to applying AGC - LMS can work as well for a signal of varying
-+amplitude as it does for a modem signal. This normalised least mean squares
-+(NLMS) algorithm is the commonest one used for speech echo cancellation. Many
-+other algorithms exist - e.g. RLS (essentially the same as Kalman filtering),
-+FAP, etc. Some perform significantly better than NLMS. However, factors such
-+as computational complexity and patents favour the use of NLMS.
-+
-+A simple refinement to NLMS can improve its performance with speech. NLMS tends
-+to adapt best to the strongest parts of a signal. If the signal is white noise,
-+the NLMS algorithm works very well. However, speech has more low frequency than
-+high frequency content. Pre-whitening (i.e. filtering the signal to flatten its
-+spectrum) the echo signal improves the adapt rate for speech, and ensures the
-+final residual signal is not heavily biased towards high frequencies. A very
-+low complexity filter is adequate for this, so pre-whitening adds little to the
-+compute requirements of the echo canceller.
-+
-+An FIR filter adapted using pre-whitened NLMS performs well, provided certain
-+conditions are met:
-+
-+ - The transmitted signal has poor self-correlation.
-+ - There is no signal being generated within the environment being
-+ cancelled.
-+
-+The difficulty is that neither of these can be guaranteed.
-+
-+If the adaption is performed while transmitting noise (or something fairly
-+noise like, such as voice) the adaption works very well. If the adaption is
-+performed while transmitting something highly correlative (typically narrow
-+band energy such as signalling tones or DTMF), the adaption can go seriously
-+wrong. The reason is there is only one solution for the adaption on a near
-+random signal - the impulse response of the line. For a repetitive signal,
-+there are any number of solutions which converge the adaption, and nothing
-+guides the adaption to choose the generalised one. Allowing an untrained
-+canceller to converge on this kind of narrowband energy probably a good thing,
-+since at least it cancels the tones. Allowing a well converged canceller to
-+continue converging on such energy is just a way to ruin its generalised
-+adaption. A narrowband detector is needed, so adapation can be suspended at
-+appropriate times.
-+
-+The adaption process is based on trying to eliminate the received signal. When
-+there is any signal from within the environment being cancelled it may upset
-+the adaption process. Similarly, if the signal we are transmitting is small,
-+noise may dominate and disturb the adaption process. If we can ensure that the
-+adaption is only performed when we are transmitting a significant signal level,
-+and the environment is not, things will be OK. Clearly, it is easy to tell when
-+we are sending a significant signal. Telling, if the environment is generating
-+a significant signal, and doing it with sufficient speed that the adaption will
-+not have diverged too much more we stop it, is a little harder.
-+
-+The key problem in detecting when the environment is sourcing significant
-+energy is that we must do this very quickly. Given a reasonably long sample of
-+the received signal, there are a number of strategies which may be used to
-+assess whether that signal contains a strong far end component. However, by the
-+time that assessment is complete the far end signal will have already caused
-+major mis-convergence in the adaption process. An assessment algorithm is
-+needed which produces a fairly accurate result from a very short burst of far
-+end energy.
-+
-+How do I use it?
-+
-+The echo cancellor processes both the transmit and receive streams sample by
-+sample. The processing function is not declared inline. Unfortunately,
-+cancellation requires many operations per sample, so the call overhead is only
-+a minor burden.
-+*/
-+
-+#include "fir.h"
-+#include "oslec.h"
-+
-+/*
-+ G.168 echo canceller descriptor. This defines the working state for a line
-+ echo canceller.
-+*/
-+struct oslec_state {
-+ int16_t tx, rx;
-+ int16_t clean;
-+ int16_t clean_nlp;
-+
-+ int nonupdate_dwell;
-+ int curr_pos;
-+ int taps;
-+ int log2taps;
-+ int adaption_mode;
-+
-+ int cond_met;
-+ int32_t Pstates;
-+ int16_t adapt;
-+ int32_t factor;
-+ int16_t shift;
-+
-+ /* Average levels and averaging filter states */
-+ int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc;
-+ int Ltx, Lrx;
-+ int Lclean;
-+ int Lclean_bg;
-+ int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc;
-+
-+ /* foreground and background filter states */
-+ struct fir16_state_t fir_state;
-+ struct fir16_state_t fir_state_bg;
-+ int16_t *fir_taps16[2];
-+
-+ /* DC blocking filter states */
-+ int tx_1, tx_2, rx_1, rx_2;
-+
-+ /* optional High Pass Filter states */
-+ int32_t xvtx[5], yvtx[5];
-+ int32_t xvrx[5], yvrx[5];
-+
-+ /* Parameters for the optional Hoth noise generator */
-+ int cng_level;
-+ int cng_rndnum;
-+ int cng_filter;
-+
-+ /* snapshot sample of coeffs used for development */
-+ int16_t *snapshot;
-+};
-+
-+#endif /* __ECHO_H */
-diff -uNr dahdi-linux-2.7.0/drivers/staging/echo/fir.h dahdi-extra-dahdi-linux/drivers/staging/echo/fir.h
---- dahdi-linux-2.7.0/drivers/staging/echo/fir.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/fir.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,286 @@
-+/*
-+ * SpanDSP - a series of DSP components for telephony
-+ *
-+ * fir.h - General telephony FIR routines
-+ *
-+ * Written by Steve Underwood <steveu@coppice.org>
-+ *
-+ * Copyright (C) 2002 Steve Underwood
-+ *
-+ * 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 version 2, as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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.
-+ */
-+
-+#if !defined(_FIR_H_)
-+#define _FIR_H_
-+
-+/*
-+ Blackfin NOTES & IDEAS:
-+
-+ A simple dot product function is used to implement the filter. This performs
-+ just one MAC/cycle which is inefficient but was easy to implement as a first
-+ pass. The current Blackfin code also uses an unrolled form of the filter
-+ history to avoid 0 length hardware loop issues. This is wasteful of
-+ memory.
-+
-+ Ideas for improvement:
-+
-+ 1/ Rewrite filter for dual MAC inner loop. The issue here is handling
-+ history sample offsets that are 16 bit aligned - the dual MAC needs
-+ 32 bit aligmnent. There are some good examples in libbfdsp.
-+
-+ 2/ Use the hardware circular buffer facility tohalve memory usage.
-+
-+ 3/ Consider using internal memory.
-+
-+ Using less memory might also improve speed as cache misses will be
-+ reduced. A drop in MIPs and memory approaching 50% should be
-+ possible.
-+
-+ The foreground and background filters currenlty use a total of
-+ about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
-+ can.
-+*/
-+
-+#if defined(USE_MMX) || defined(USE_SSE2)
-+#include "mmx.h"
-+#endif
-+
-+/*
-+ * 16 bit integer FIR descriptor. This defines the working state for a single
-+ * instance of an FIR filter using 16 bit integer coefficients.
-+ */
-+struct fir16_state_t {
-+ int taps;
-+ int curr_pos;
-+ const int16_t *coeffs;
-+ int16_t *history;
-+};
-+
-+/*
-+ * 32 bit integer FIR descriptor. This defines the working state for a single
-+ * instance of an FIR filter using 32 bit integer coefficients, and filtering
-+ * 16 bit integer data.
-+ */
-+struct fir32_state_t {
-+ int taps;
-+ int curr_pos;
-+ const int32_t *coeffs;
-+ int16_t *history;
-+};
-+
-+/*
-+ * Floating point FIR descriptor. This defines the working state for a single
-+ * instance of an FIR filter using floating point coefficients and data.
-+ */
-+struct fir_float_state_t {
-+ int taps;
-+ int curr_pos;
-+ const float *coeffs;
-+ float *history;
-+};
-+
-+static inline const int16_t *fir16_create(struct fir16_state_t *fir,
-+ const int16_t *coeffs, int taps)
-+{
-+ fir->taps = taps;
-+ fir->curr_pos = taps - 1;
-+ fir->coeffs = coeffs;
-+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__)
-+ fir->history = kcalloc(2 * taps, sizeof(int16_t), GFP_KERNEL);
-+#else
-+ fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
-+#endif
-+ return fir->history;
-+}
-+
-+static inline void fir16_flush(struct fir16_state_t *fir)
-+{
-+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__bfin__)
-+ memset(fir->history, 0, 2 * fir->taps * sizeof(int16_t));
-+#else
-+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
-+#endif
-+}
-+
-+static inline void fir16_free(struct fir16_state_t *fir)
-+{
-+ kfree(fir->history);
-+}
-+
-+#ifdef __bfin__
-+static inline int32_t dot_asm(short *x, short *y, int len)
-+{
-+ int dot;
-+
-+ len--;
-+
-+ __asm__("I0 = %1;\n\t"
-+ "I1 = %2;\n\t"
-+ "A0 = 0;\n\t"
-+ "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
-+ "LOOP dot%= LC0 = %3;\n\t"
-+ "LOOP_BEGIN dot%=;\n\t"
-+ "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
-+ "LOOP_END dot%=;\n\t"
-+ "A0 += R0.L*R1.L (IS);\n\t"
-+ "R0 = A0;\n\t"
-+ "%0 = R0;\n\t"
-+ : "=&d"(dot)
-+ : "a"(x), "a"(y), "a"(len)
-+ : "I0", "I1", "A1", "A0", "R0", "R1"
-+ );
-+
-+ return dot;
-+}
-+#endif
-+
-+static inline int16_t fir16(struct fir16_state_t *fir, int16_t sample)
-+{
-+ int32_t y;
-+#if defined(USE_MMX)
-+ int i;
-+ union mmx_t *mmx_coeffs;
-+ union mmx_t *mmx_hist;
-+
-+ fir->history[fir->curr_pos] = sample;
-+ fir->history[fir->curr_pos + fir->taps] = sample;
-+
-+ mmx_coeffs = (union mmx_t *) fir->coeffs;
-+ mmx_hist = (union mmx_t *) &fir->history[fir->curr_pos];
-+ i = fir->taps;
-+ pxor_r2r(mm4, mm4);
-+ /* 8 samples per iteration, so the filter must be a multiple of
-+ 8 long. */
-+ while (i > 0) {
-+ movq_m2r(mmx_coeffs[0], mm0);
-+ movq_m2r(mmx_coeffs[1], mm2);
-+ movq_m2r(mmx_hist[0], mm1);
-+ movq_m2r(mmx_hist[1], mm3);
-+ mmx_coeffs += 2;
-+ mmx_hist += 2;
-+ pmaddwd_r2r(mm1, mm0);
-+ pmaddwd_r2r(mm3, mm2);
-+ paddd_r2r(mm0, mm4);
-+ paddd_r2r(mm2, mm4);
-+ i -= 8;
-+ }
-+ movq_r2r(mm4, mm0);
-+ psrlq_i2r(32, mm0);
-+ paddd_r2r(mm0, mm4);
-+ movd_r2m(mm4, y);
-+ emms();
-+#elif defined(USE_SSE2)
-+ int i;
-+ union xmm_t *xmm_coeffs;
-+ union xmm_t *xmm_hist;
-+
-+ fir->history[fir->curr_pos] = sample;
-+ fir->history[fir->curr_pos + fir->taps] = sample;
-+
-+ xmm_coeffs = (union xmm_t *) fir->coeffs;
-+ xmm_hist = (union xmm_t *) &fir->history[fir->curr_pos];
-+ i = fir->taps;
-+ pxor_r2r(xmm4, xmm4);
-+ /* 16 samples per iteration, so the filter must be a multiple of
-+ 16 long. */
-+ while (i > 0) {
-+ movdqu_m2r(xmm_coeffs[0], xmm0);
-+ movdqu_m2r(xmm_coeffs[1], xmm2);
-+ movdqu_m2r(xmm_hist[0], xmm1);
-+ movdqu_m2r(xmm_hist[1], xmm3);
-+ xmm_coeffs += 2;
-+ xmm_hist += 2;
-+ pmaddwd_r2r(xmm1, xmm0);
-+ pmaddwd_r2r(xmm3, xmm2);
-+ paddd_r2r(xmm0, xmm4);
-+ paddd_r2r(xmm2, xmm4);
-+ i -= 16;
-+ }
-+ movdqa_r2r(xmm4, xmm0);
-+ psrldq_i2r(8, xmm0);
-+ paddd_r2r(xmm0, xmm4);
-+ movdqa_r2r(xmm4, xmm0);
-+ psrldq_i2r(4, xmm0);
-+ paddd_r2r(xmm0, xmm4);
-+ movd_r2m(xmm4, y);
-+#elif defined(__bfin__)
-+ fir->history[fir->curr_pos] = sample;
-+ fir->history[fir->curr_pos + fir->taps] = sample;
-+ y = dot_asm((int16_t *) fir->coeffs, &fir->history[fir->curr_pos],
-+ fir->taps);
-+#else
-+ int i;
-+ int offset1;
-+ int offset2;
-+
-+ fir->history[fir->curr_pos] = sample;
-+
-+ offset2 = fir->curr_pos;
-+ offset1 = fir->taps - offset2;
-+ y = 0;
-+ for (i = fir->taps - 1; i >= offset1; i--)
-+ y += fir->coeffs[i] * fir->history[i - offset1];
-+ for (; i >= 0; i--)
-+ y += fir->coeffs[i] * fir->history[i + offset2];
-+#endif
-+ if (fir->curr_pos <= 0)
-+ fir->curr_pos = fir->taps;
-+ fir->curr_pos--;
-+ return (int16_t) (y >> 15);
-+}
-+
-+static inline const int16_t *fir32_create(struct fir32_state_t *fir,
-+ const int32_t *coeffs, int taps)
-+{
-+ fir->taps = taps;
-+ fir->curr_pos = taps - 1;
-+ fir->coeffs = coeffs;
-+ fir->history = kcalloc(taps, sizeof(int16_t), GFP_KERNEL);
-+ return fir->history;
-+}
-+
-+static inline void fir32_flush(struct fir32_state_t *fir)
-+{
-+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
-+}
-+
-+static inline void fir32_free(struct fir32_state_t *fir)
-+{
-+ kfree(fir->history);
-+}
-+
-+static inline int16_t fir32(struct fir32_state_t *fir, int16_t sample)
-+{
-+ int i;
-+ int32_t y;
-+ int offset1;
-+ int offset2;
-+
-+ fir->history[fir->curr_pos] = sample;
-+ offset2 = fir->curr_pos;
-+ offset1 = fir->taps - offset2;
-+ y = 0;
-+ for (i = fir->taps - 1; i >= offset1; i--)
-+ y += fir->coeffs[i] * fir->history[i - offset1];
-+ for (; i >= 0; i--)
-+ y += fir->coeffs[i] * fir->history[i + offset2];
-+ if (fir->curr_pos <= 0)
-+ fir->curr_pos = fir->taps;
-+ fir->curr_pos--;
-+ return (int16_t) (y >> 15);
-+}
-+
-+#endif
-diff -uNr dahdi-linux-2.7.0/drivers/staging/echo/Kbuild dahdi-extra-dahdi-linux/drivers/staging/echo/Kbuild
---- dahdi-linux-2.7.0/drivers/staging/echo/Kbuild 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/Kbuild 2013-06-04 15:18:43.000000000 +0100
-@@ -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 -uNr dahdi-linux-2.7.0/drivers/staging/echo/mmx.h dahdi-extra-dahdi-linux/drivers/staging/echo/mmx.h
---- dahdi-linux-2.7.0/drivers/staging/echo/mmx.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/mmx.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,288 @@
-+/*
-+ * mmx.h
-+ * Copyright (C) 1997-2001 H. Dietz and R. Fisher
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg 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
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+#ifndef AVCODEC_I386MMX_H
-+#define AVCODEC_I386MMX_H
-+
-+/*
-+ * The type of an value that fits in an MMX register (note that long
-+ * long constant values MUST be suffixed by LL and unsigned long long
-+ * values by ULL, lest they be truncated by the compiler)
-+ */
-+
-+union mmx_t {
-+ long long q; /* Quadword (64-bit) value */
-+ unsigned long long uq; /* Unsigned Quadword */
-+ int d[2]; /* 2 Doubleword (32-bit) values */
-+ unsigned int ud[2]; /* 2 Unsigned Doubleword */
-+ short w[4]; /* 4 Word (16-bit) values */
-+ unsigned short uw[4]; /* 4 Unsigned Word */
-+ char b[8]; /* 8 Byte (8-bit) values */
-+ unsigned char ub[8]; /* 8 Unsigned Byte */
-+ float s[2]; /* Single-precision (32-bit) value */
-+}; /* On an 8-byte (64-bit) boundary */
-+
-+/* SSE registers */
-+union xmm_t {
-+ char b[16];
-+};
-+
-+
-+#define mmx_i2r(op, imm, reg) \
-+ __asm__ __volatile__ (#op " %0, %%" #reg \
-+ : /* nothing */ \
-+ : "i" (imm))
-+
-+#define mmx_m2r(op, mem, reg) \
-+ __asm__ __volatile__ (#op " %0, %%" #reg \
-+ : /* nothing */ \
-+ : "m" (mem))
-+
-+#define mmx_r2m(op, reg, mem) \
-+ __asm__ __volatile__ (#op " %%" #reg ", %0" \
-+ : "=m" (mem) \
-+ : /* nothing */)
-+
-+#define mmx_r2r(op, regs, regd) \
-+ __asm__ __volatile__ (#op " %" #regs ", %" #regd)
-+
-+
-+#define emms() __asm__ __volatile__ ("emms")
-+
-+#define movd_m2r(var, reg) mmx_m2r(movd, var, reg)
-+#define movd_r2m(reg, var) mmx_r2m(movd, reg, var)
-+#define movd_r2r(regs, regd) mmx_r2r(movd, regs, regd)
-+
-+#define movq_m2r(var, reg) mmx_m2r(movq, var, reg)
-+#define movq_r2m(reg, var) mmx_r2m(movq, reg, var)
-+#define movq_r2r(regs, regd) mmx_r2r(movq, regs, regd)
-+
-+#define packssdw_m2r(var, reg) mmx_m2r(packssdw, var, reg)
-+#define packssdw_r2r(regs, regd) mmx_r2r(packssdw, regs, regd)
-+#define packsswb_m2r(var, reg) mmx_m2r(packsswb, var, reg)
-+#define packsswb_r2r(regs, regd) mmx_r2r(packsswb, regs, regd)
-+
-+#define packuswb_m2r(var, reg) mmx_m2r(packuswb, var, reg)
-+#define packuswb_r2r(regs, regd) mmx_r2r(packuswb, regs, regd)
-+
-+#define paddb_m2r(var, reg) mmx_m2r(paddb, var, reg)
-+#define paddb_r2r(regs, regd) mmx_r2r(paddb, regs, regd)
-+#define paddd_m2r(var, reg) mmx_m2r(paddd, var, reg)
-+#define paddd_r2r(regs, regd) mmx_r2r(paddd, regs, regd)
-+#define paddw_m2r(var, reg) mmx_m2r(paddw, var, reg)
-+#define paddw_r2r(regs, regd) mmx_r2r(paddw, regs, regd)
-+
-+#define paddsb_m2r(var, reg) mmx_m2r(paddsb, var, reg)
-+#define paddsb_r2r(regs, regd) mmx_r2r(paddsb, regs, regd)
-+#define paddsw_m2r(var, reg) mmx_m2r(paddsw, var, reg)
-+#define paddsw_r2r(regs, regd) mmx_r2r(paddsw, regs, regd)
-+
-+#define paddusb_m2r(var, reg) mmx_m2r(paddusb, var, reg)
-+#define paddusb_r2r(regs, regd) mmx_r2r(paddusb, regs, regd)
-+#define paddusw_m2r(var, reg) mmx_m2r(paddusw, var, reg)
-+#define paddusw_r2r(regs, regd) mmx_r2r(paddusw, regs, regd)
-+
-+#define pand_m2r(var, reg) mmx_m2r(pand, var, reg)
-+#define pand_r2r(regs, regd) mmx_r2r(pand, regs, regd)
-+
-+#define pandn_m2r(var, reg) mmx_m2r(pandn, var, reg)
-+#define pandn_r2r(regs, regd) mmx_r2r(pandn, regs, regd)
-+
-+#define pcmpeqb_m2r(var, reg) mmx_m2r(pcmpeqb, var, reg)
-+#define pcmpeqb_r2r(regs, regd) mmx_r2r(pcmpeqb, regs, regd)
-+#define pcmpeqd_m2r(var, reg) mmx_m2r(pcmpeqd, var, reg)
-+#define pcmpeqd_r2r(regs, regd) mmx_r2r(pcmpeqd, regs, regd)
-+#define pcmpeqw_m2r(var, reg) mmx_m2r(pcmpeqw, var, reg)
-+#define pcmpeqw_r2r(regs, regd) mmx_r2r(pcmpeqw, regs, regd)
-+
-+#define pcmpgtb_m2r(var, reg) mmx_m2r(pcmpgtb, var, reg)
-+#define pcmpgtb_r2r(regs, regd) mmx_r2r(pcmpgtb, regs, regd)
-+#define pcmpgtd_m2r(var, reg) mmx_m2r(pcmpgtd, var, reg)
-+#define pcmpgtd_r2r(regs, regd) mmx_r2r(pcmpgtd, regs, regd)
-+#define pcmpgtw_m2r(var, reg) mmx_m2r(pcmpgtw, var, reg)
-+#define pcmpgtw_r2r(regs, regd) mmx_r2r(pcmpgtw, regs, regd)
-+
-+#define pmaddwd_m2r(var, reg) mmx_m2r(pmaddwd, var, reg)
-+#define pmaddwd_r2r(regs, regd) mmx_r2r(pmaddwd, regs, regd)
-+
-+#define pmulhw_m2r(var, reg) mmx_m2r(pmulhw, var, reg)
-+#define pmulhw_r2r(regs, regd) mmx_r2r(pmulhw, regs, regd)
-+
-+#define pmullw_m2r(var, reg) mmx_m2r(pmullw, var, reg)
-+#define pmullw_r2r(regs, regd) mmx_r2r(pmullw, regs, regd)
-+
-+#define por_m2r(var, reg) mmx_m2r(por, var, reg)
-+#define por_r2r(regs, regd) mmx_r2r(por, regs, regd)
-+
-+#define pslld_i2r(imm, reg) mmx_i2r(pslld, imm, reg)
-+#define pslld_m2r(var, reg) mmx_m2r(pslld, var, reg)
-+#define pslld_r2r(regs, regd) mmx_r2r(pslld, regs, regd)
-+#define psllq_i2r(imm, reg) mmx_i2r(psllq, imm, reg)
-+#define psllq_m2r(var, reg) mmx_m2r(psllq, var, reg)
-+#define psllq_r2r(regs, regd) mmx_r2r(psllq, regs, regd)
-+#define psllw_i2r(imm, reg) mmx_i2r(psllw, imm, reg)
-+#define psllw_m2r(var, reg) mmx_m2r(psllw, var, reg)
-+#define psllw_r2r(regs, regd) mmx_r2r(psllw, regs, regd)
-+
-+#define psrad_i2r(imm, reg) mmx_i2r(psrad, imm, reg)
-+#define psrad_m2r(var, reg) mmx_m2r(psrad, var, reg)
-+#define psrad_r2r(regs, regd) mmx_r2r(psrad, regs, regd)
-+#define psraw_i2r(imm, reg) mmx_i2r(psraw, imm, reg)
-+#define psraw_m2r(var, reg) mmx_m2r(psraw, var, reg)
-+#define psraw_r2r(regs, regd) mmx_r2r(psraw, regs, regd)
-+
-+#define psrld_i2r(imm, reg) mmx_i2r(psrld, imm, reg)
-+#define psrld_m2r(var, reg) mmx_m2r(psrld, var, reg)
-+#define psrld_r2r(regs, regd) mmx_r2r(psrld, regs, regd)
-+#define psrlq_i2r(imm, reg) mmx_i2r(psrlq, imm, reg)
-+#define psrlq_m2r(var, reg) mmx_m2r(psrlq, var, reg)
-+#define psrlq_r2r(regs, regd) mmx_r2r(psrlq, regs, regd)
-+#define psrlw_i2r(imm, reg) mmx_i2r(psrlw, imm, reg)
-+#define psrlw_m2r(var, reg) mmx_m2r(psrlw, var, reg)
-+#define psrlw_r2r(regs, regd) mmx_r2r(psrlw, regs, regd)
-+
-+#define psubb_m2r(var, reg) mmx_m2r(psubb, var, reg)
-+#define psubb_r2r(regs, regd) mmx_r2r(psubb, regs, regd)
-+#define psubd_m2r(var, reg) mmx_m2r(psubd, var, reg)
-+#define psubd_r2r(regs, regd) mmx_r2r(psubd, regs, regd)
-+#define psubw_m2r(var, reg) mmx_m2r(psubw, var, reg)
-+#define psubw_r2r(regs, regd) mmx_r2r(psubw, regs, regd)
-+
-+#define psubsb_m2r(var, reg) mmx_m2r(psubsb, var, reg)
-+#define psubsb_r2r(regs, regd) mmx_r2r(psubsb, regs, regd)
-+#define psubsw_m2r(var, reg) mmx_m2r(psubsw, var, reg)
-+#define psubsw_r2r(regs, regd) mmx_r2r(psubsw, regs, regd)
-+
-+#define psubusb_m2r(var, reg) mmx_m2r(psubusb, var, reg)
-+#define psubusb_r2r(regs, regd) mmx_r2r(psubusb, regs, regd)
-+#define psubusw_m2r(var, reg) mmx_m2r(psubusw, var, reg)
-+#define psubusw_r2r(regs, regd) mmx_r2r(psubusw, regs, regd)
-+
-+#define punpckhbw_m2r(var, reg) mmx_m2r(punpckhbw, var, reg)
-+#define punpckhbw_r2r(regs, regd) mmx_r2r(punpckhbw, regs, regd)
-+#define punpckhdq_m2r(var, reg) mmx_m2r(punpckhdq, var, reg)
-+#define punpckhdq_r2r(regs, regd) mmx_r2r(punpckhdq, regs, regd)
-+#define punpckhwd_m2r(var, reg) mmx_m2r(punpckhwd, var, reg)
-+#define punpckhwd_r2r(regs, regd) mmx_r2r(punpckhwd, regs, regd)
-+
-+#define punpcklbw_m2r(var, reg) mmx_m2r(punpcklbw, var, reg)
-+#define punpcklbw_r2r(regs, regd) mmx_r2r(punpcklbw, regs, regd)
-+#define punpckldq_m2r(var, reg) mmx_m2r(punpckldq, var, reg)
-+#define punpckldq_r2r(regs, regd) mmx_r2r(punpckldq, regs, regd)
-+#define punpcklwd_m2r(var, reg) mmx_m2r(punpcklwd, var, reg)
-+#define punpcklwd_r2r(regs, regd) mmx_r2r(punpcklwd, regs, regd)
-+
-+#define pxor_m2r(var, reg) mmx_m2r(pxor, var, reg)
-+#define pxor_r2r(regs, regd) mmx_r2r(pxor, regs, regd)
-+
-+
-+/* 3DNOW extensions */
-+
-+#define pavgusb_m2r(var, reg) mmx_m2r(pavgusb, var, reg)
-+#define pavgusb_r2r(regs, regd) mmx_r2r(pavgusb, regs, regd)
-+
-+
-+/* AMD MMX extensions - also available in intel SSE */
-+
-+
-+#define mmx_m2ri(op, mem, reg, imm) \
-+ __asm__ __volatile__ (#op " %1, %0, %%" #reg \
-+ : /* nothing */ \
-+ : "m" (mem), "i" (imm))
-+#define mmx_r2ri(op, regs, regd, imm) \
-+ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
-+ : /* nothing */ \
-+ : "i" (imm))
-+
-+#define mmx_fetch(mem, hint) \
-+ __asm__ __volatile__ ("prefetch" #hint " %0" \
-+ : /* nothing */ \
-+ : "m" (mem))
-+
-+
-+#define maskmovq(regs, maskreg) mmx_r2ri(maskmovq, regs, maskreg)
-+
-+#define movntq_r2m(mmreg, var) mmx_r2m(movntq, mmreg, var)
-+
-+#define pavgb_m2r(var, reg) mmx_m2r(pavgb, var, reg)
-+#define pavgb_r2r(regs, regd) mmx_r2r(pavgb, regs, regd)
-+#define pavgw_m2r(var, reg) mmx_m2r(pavgw, var, reg)
-+#define pavgw_r2r(regs, regd) mmx_r2r(pavgw, regs, regd)
-+
-+#define pextrw_r2r(mmreg, reg, imm) mmx_r2ri(pextrw, mmreg, reg, imm)
-+
-+#define pinsrw_r2r(reg, mmreg, imm) mmx_r2ri(pinsrw, reg, mmreg, imm)
-+
-+#define pmaxsw_m2r(var, reg) mmx_m2r(pmaxsw, var, reg)
-+#define pmaxsw_r2r(regs, regd) mmx_r2r(pmaxsw, regs, regd)
-+
-+#define pmaxub_m2r(var, reg) mmx_m2r(pmaxub, var, reg)
-+#define pmaxub_r2r(regs, regd) mmx_r2r(pmaxub, regs, regd)
-+
-+#define pminsw_m2r(var, reg) mmx_m2r(pminsw, var, reg)
-+#define pminsw_r2r(regs, regd) mmx_r2r(pminsw, regs, regd)
-+
-+#define pminub_m2r(var, reg) mmx_m2r(pminub, var, reg)
-+#define pminub_r2r(regs, regd) mmx_r2r(pminub, regs, regd)
-+
-+#define pmovmskb(mmreg, reg) \
-+ __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
-+
-+#define pmulhuw_m2r(var, reg) mmx_m2r(pmulhuw, var, reg)
-+#define pmulhuw_r2r(regs, regd) mmx_r2r(pmulhuw, regs, regd)
-+
-+#define prefetcht0(mem) mmx_fetch(mem, t0)
-+#define prefetcht1(mem) mmx_fetch(mem, t1)
-+#define prefetcht2(mem) mmx_fetch(mem, t2)
-+#define prefetchnta(mem) mmx_fetch(mem, nta)
-+
-+#define psadbw_m2r(var, reg) mmx_m2r(psadbw, var, reg)
-+#define psadbw_r2r(regs, regd) mmx_r2r(psadbw, regs, regd)
-+
-+#define pshufw_m2r(var, reg, imm) mmx_m2ri(pshufw, var, reg, imm)
-+#define pshufw_r2r(regs, regd, imm) mmx_r2ri(pshufw, regs, regd, imm)
-+
-+#define sfence() __asm__ __volatile__ ("sfence\n\t")
-+
-+/* SSE2 */
-+#define pshufhw_m2r(var, reg, imm) mmx_m2ri(pshufhw, var, reg, imm)
-+#define pshufhw_r2r(regs, regd, imm) mmx_r2ri(pshufhw, regs, regd, imm)
-+#define pshuflw_m2r(var, reg, imm) mmx_m2ri(pshuflw, var, reg, imm)
-+#define pshuflw_r2r(regs, regd, imm) mmx_r2ri(pshuflw, regs, regd, imm)
-+
-+#define pshufd_r2r(regs, regd, imm) mmx_r2ri(pshufd, regs, regd, imm)
-+
-+#define movdqa_m2r(var, reg) mmx_m2r(movdqa, var, reg)
-+#define movdqa_r2m(reg, var) mmx_r2m(movdqa, reg, var)
-+#define movdqa_r2r(regs, regd) mmx_r2r(movdqa, regs, regd)
-+#define movdqu_m2r(var, reg) mmx_m2r(movdqu, var, reg)
-+#define movdqu_r2m(reg, var) mmx_r2m(movdqu, reg, var)
-+#define movdqu_r2r(regs, regd) mmx_r2r(movdqu, regs, regd)
-+
-+#define pmullw_r2m(reg, var) mmx_r2m(pmullw, reg, var)
-+
-+#define pslldq_i2r(imm, reg) mmx_i2r(pslldq, imm, reg)
-+#define psrldq_i2r(imm, reg) mmx_i2r(psrldq, imm, reg)
-+
-+#define punpcklqdq_r2r(regs, regd) mmx_r2r(punpcklqdq, regs, regd)
-+#define punpckhqdq_r2r(regs, regd) mmx_r2r(punpckhqdq, regs, regd)
-+
-+
-+#endif /* AVCODEC_I386MMX_H */
-diff -uNr dahdi-linux-2.7.0/drivers/staging/echo/oslec.h dahdi-extra-dahdi-linux/drivers/staging/echo/oslec.h
---- dahdi-linux-2.7.0/drivers/staging/echo/oslec.h 1970-01-01 01:00:00.000000000 +0100
-+++ dahdi-extra-dahdi-linux/drivers/staging/echo/oslec.h 2013-06-04 15:18:43.000000000 +0100
-@@ -0,0 +1,94 @@
-+/*
-+ * OSLEC - A line echo canceller. This code is being developed
-+ * against and partially complies with G168. Using code from SpanDSP
-+ *
-+ * Written by Steve Underwood <steveu@coppice.org>
-+ * and David Rowe <david_at_rowetel_dot_com>
-+ *
-+ * Copyright (C) 2001 Steve Underwood and 2007-2008 David Rowe
-+ *
-+ * 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 version 2, as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ *
-+ */
-+
-+#ifndef __OSLEC_H
-+#define __OSLEC_H
-+
-+/* Mask bits for the adaption mode */
-+#define ECHO_CAN_USE_ADAPTION 0x01
-+#define ECHO_CAN_USE_NLP 0x02
-+#define ECHO_CAN_USE_CNG 0x04
-+#define ECHO_CAN_USE_CLIP 0x08
-+#define ECHO_CAN_USE_TX_HPF 0x10
-+#define ECHO_CAN_USE_RX_HPF 0x20
-+#define ECHO_CAN_DISABLE 0x40
-+
-+/**
-+ * oslec_state: G.168 echo canceller descriptor.
-+ *
-+ * This defines the working state for a line echo canceller.
-+ */
-+struct oslec_state;
-+
-+/**
-+ * oslec_create - Create a voice echo canceller context.
-+ * @len: The length of the canceller, in samples.
-+ * @return: The new canceller context, or NULL if the canceller could not be
-+ * created.
-+ */
-+struct oslec_state *oslec_create(int len, int adaption_mode);
-+
-+/**
-+ * oslec_free - Free a voice echo canceller context.
-+ * @ec: The echo canceller context.
-+ */
-+void oslec_free(struct oslec_state *ec);
-+
-+/**
-+ * oslec_flush - Flush (reinitialise) a voice echo canceller context.
-+ * @ec: The echo canceller context.
-+ */
-+void oslec_flush(struct oslec_state *ec);
-+
-+/**
-+ * oslec_adaption_mode - set the adaption mode of a voice echo canceller context.
-+ * @ec The echo canceller context.
-+ * @adaption_mode: The mode.
-+ */
-+void oslec_adaption_mode(struct oslec_state *ec, int adaption_mode);
-+
-+void oslec_snapshot(struct oslec_state *ec);
-+
-+/**
-+ * oslec_update: Process a sample through a voice echo canceller.
-+ * @ec: The echo canceller context.
-+ * @tx: The transmitted audio sample.
-+ * @rx: The received audio sample.
-+ *
-+ * The return value is the clean (echo cancelled) received sample.
-+ */
-+int16_t oslec_update(struct oslec_state *ec, int16_t tx, int16_t rx);
-+
-+/**
-+ * oslec_hpf_tx: Process to high pass filter the tx signal.
-+ * @ec: The echo canceller context.
-+ * @tx: The transmitted auio sample.
-+ *
-+ * The return value is the HP filtered transmit sample, send this to your D/A.
-+ */
-+int16_t oslec_hpf_tx(struct oslec_state *ec, int16_t tx);
-+
-+#endif /* __OSLEC_H */
diff --git a/system/dahdi-complete/patches/07-dahdi-3.1.0-r1-kernel5.6.patch b/system/dahdi-complete/patches/07-dahdi-3.1.0-r1-kernel5.6.patch
deleted file mode 100644
index 64df8ec485291..0000000000000
--- a/system/dahdi-complete/patches/07-dahdi-3.1.0-r1-kernel5.6.patch
+++ /dev/null
@@ -1,392 +0,0 @@
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/dahdi-base.c dahdi-linux-3.1.0/drivers/dahdi/dahdi-base.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/dahdi-base.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/dahdi-base.c 2020-04-06 14:26:55.512984750 +0200
-@@ -1015,6 +1015,7 @@
- return single_open(file, dahdi_seq_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations dahdi_proc_ops = {
- .owner = THIS_MODULE,
- .open = dahdi_proc_open,
-@@ -1022,6 +1023,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops dahdi_proc_ops = {
-+ .proc_open = dahdi_proc_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #endif
-
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/dahdi_dynamic_ethmf.c dahdi-linux-3.1.0/drivers/dahdi/dahdi_dynamic_ethmf.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/dahdi_dynamic_ethmf.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/dahdi_dynamic_ethmf.c 2020-04-06 15:19:32.543087702 +0200
-@@ -733,12 +733,21 @@
- return single_open(file, ztdethmf_proc_show, NULL);
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations ztdethmf_proc_fops = {
- .open = ztdethmf_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- };
-+#else
-+static const struct proc_ops ztdethmf_proc_fops = {
-+ .proc_open = ztdethmf_proc_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = seq_release,
-+};
-+#endif
- #endif
-
- static int __init ztdethmf_init(void)
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_bri.c dahdi-linux-3.1.0/drivers/dahdi/xpp/card_bri.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_bri.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/card_bri.c 2020-04-06 15:28:49.453211420 +0200
-@@ -153,7 +153,11 @@
- static bool bri_packet_is_valid(xpacket_t *pack);
- static void bri_packet_dump(const char *msg, xpacket_t *pack);
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_bri_info_ops;
-+#else
-+static const struct proc_ops proc_bri_info_ops;
-+#endif
- #endif
- static int bri_spanconfig(struct file *file, struct dahdi_span *span,
- struct dahdi_lineconfig *lc);
-@@ -1740,6 +1744,7 @@
- return single_open(file, proc_bri_info_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_bri_info_ops = {
- .owner = THIS_MODULE,
- .open = proc_bri_info_open,
-@@ -1747,6 +1752,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops proc_bri_info_ops = {
-+ .proc_open = proc_bri_info_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
- #endif
-
- static int bri_xpd_probe(struct device *dev)
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_fxo.c dahdi-linux-3.1.0/drivers/dahdi/xpp/card_fxo.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_fxo.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/card_fxo.c 2020-04-06 15:33:42.113198524 +0200
-@@ -107,10 +107,17 @@
- static bool fxo_packet_is_valid(xpacket_t *pack);
- static void fxo_packet_dump(const char *msg, xpacket_t *pack);
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_fxo_info_ops;
- #ifdef WITH_METERING
- static const struct file_operations proc_xpd_metering_ops;
- #endif
-+#else
-+static const struct proc_ops proc_fxo_info_ops;
-+#ifdef WITH_METERING
-+static const struct proc_ops proc_xpd_metering_ops;
-+#endif
-+#endif
- #endif
- static void dahdi_report_battery(xpd_t *xpd, lineno_t chan);
- static void report_polarity_reversal(xpd_t *xpd, xportno_t portno, char *msg);
-@@ -1484,6 +1491,7 @@
- return single_open(file, proc_fxo_info_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_fxo_info_ops = {
- .owner = THIS_MODULE,
- .open = proc_fxo_info_open,
-@@ -1491,6 +1499,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops proc_fxo_info_ops = {
-+ .proc_open = proc_fxo_info_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #ifdef WITH_METERING
- static int proc_xpd_metering_show(struct seq_file *sfile, void *not_used)
-@@ -1521,6 +1537,7 @@
- return single_open(file, proc_xpd_metering_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_xpd_metering_ops = {
- .owner = THIS_MODULE,
- .open = proc_xpd_metering_open,
-@@ -1528,7 +1545,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
--
-+#else
-+static const struct file_operations proc_xpd_metering_ops = {
-+ .proc_open = proc_xpd_metering_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
- #endif
- #endif
-
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_fxs.c dahdi-linux-3.1.0/drivers/dahdi/xpp/card_fxs.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/card_fxs.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/card_fxs.c 2020-04-06 15:26:55.363172030 +0200
-@@ -160,10 +160,17 @@
- static bool fxs_packet_is_valid(xpacket_t *pack);
- static void fxs_packet_dump(const char *msg, xpacket_t *pack);
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_fxs_info_ops;
- #ifdef WITH_METERING
- static const struct file_operations proc_xpd_metering_ops;
- #endif
-+#else
-+static const struct proc_ops proc_fxs_info_ops;
-+#ifdef WITH_METERING
-+static const struct proc_ops proc_xpd_metering_ops;
-+#endif
-+#endif
- #endif
- static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
-
-@@ -2115,6 +2122,7 @@
- return single_open(file, proc_fxs_info_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_fxs_info_ops = {
- .owner = THIS_MODULE,
- .open = proc_fxs_info_open,
-@@ -2122,6 +2130,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops proc_fxs_info_ops = {
-+ .proc_open = proc_fxs_info_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #ifdef WITH_METERING
- static ssize_t proc_xpd_metering_write(struct file *file,
-@@ -2165,12 +2181,20 @@
- file->private_data = PDE_DATA(inode);
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_xpd_metering_ops = {
- .owner = THIS_MODULE,
- .open = proc_xpd_metering_open,
- .write = proc_xpd_metering_write,
- .release = single_release,
- };
-+#else
-+static const struct poc_ops proc_xpd_metering_ops = {
-+ .proc_open = proc_xpd_metering_open,
-+ .proc_write = proc_xpd_metering_write,
-+ .proc_release = single_release,
-+};
-+#endif
- #endif
- #endif
-
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xbus-core.c dahdi-linux-3.1.0/drivers/dahdi/xpp/xbus-core.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xbus-core.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/xbus-core.c 2020-04-06 15:20:52.413097618 +0200
-@@ -50,7 +50,11 @@
- #ifdef PROTOCOL_DEBUG
- #ifdef CONFIG_PROC_FS
- #define PROC_XBUS_COMMAND "command"
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_xbus_command_ops;
-+#else
-+static const struct proc_ops proc_xbus_command_ops;
-+#endif
- #endif
- #endif
-
-@@ -65,7 +69,11 @@
- "Register devices automatically (1) or not (0). UNUSED.");
-
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xbus_read_proc_ops;
-+#else
-+static const struct proc_ops xbus_read_proc_ops;
-+#endif
- #endif
- static void transport_init(xbus_t *xbus, struct xbus_ops *ops,
- ushort max_send_size,
-@@ -1828,6 +1836,7 @@
- return single_open(file, xbus_proc_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xbus_read_proc_ops = {
- .owner = THIS_MODULE,
- .open = xbus_read_proc_open,
-@@ -1835,6 +1844,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops xbus_read_proc_ops = {
-+ .proc_open = xbus_read_proc_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #ifdef PROTOCOL_DEBUG
- static ssize_t proc_xbus_command_write(struct file *file,
-@@ -1927,11 +1944,18 @@
- return 0;
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations proc_xbus_command_ops = {
- .owner = THIS_MODULE,
- .open = proc_xbus_command_open,
- .write = proc_xbus_command_write,
- };
-+#else
-+static const struct proc_ops proc_xbus_command_ops = {
-+ .proc_open = proc_xbus_command_open,
-+ .proc_write = proc_xbus_command_write,
-+};
-+#endif
- #endif
-
- static int xpp_proc_read_show(struct seq_file *sfile, void *data)
-@@ -1961,6 +1985,7 @@
- return single_open(file, xpp_proc_read_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xpp_proc_read_ops = {
- .owner = THIS_MODULE,
- .open = xpp_proc_read_open,
-@@ -1968,6 +1993,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops xpp_proc_read_ops = {
-+ .proc_open = xpp_proc_read_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #endif
-
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xpp_dahdi.c dahdi-linux-3.1.0/drivers/dahdi/xpp/xpp_dahdi.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xpp_dahdi.c 2019-10-03 16:48:09.000000000 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/xpp_dahdi.c 2020-04-06 15:26:17.603158828 +0200
-@@ -103,7 +103,11 @@
- }
-
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xpd_read_proc_ops;
-+#else
-+static const struct proc_ops xpd_read_proc_ops;
-+#endif
- #endif
-
- /*------------------------- XPD Management -------------------------*/
-@@ -392,6 +396,7 @@
- return single_open(file, xpd_read_proc_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xpd_read_proc_ops = {
- .owner = THIS_MODULE,
- .open = xpd_read_proc_open,
-@@ -399,6 +404,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
-+#else
-+static const struct proc_ops xpd_read_proc_ops = {
-+ .proc_open = xpd_read_proc_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
-
- #endif
-
-diff -rbu dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xpp_usb.c dahdi-linux-3.1.0/drivers/dahdi/xpp/xpp_usb.c
---- dahdi-linux-3.1.0.o/drivers/dahdi/xpp/xpp_usb.c 2020-04-06 14:09:11.512683578 +0200
-+++ dahdi-linux-3.1.0/drivers/dahdi/xpp/xpp_usb.c 2020-04-06 15:23:07.713114350 +0200
-@@ -228,7 +228,11 @@
- const struct usb_device_id *id);
- static void xusb_disconnect(struct usb_interface *interface);
- #ifdef CONFIG_PROC_FS
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xusb_read_proc_ops;
-+#else
-+static const struct proc_ops xusb_read_proc_ops;
-+#endif
- #endif
-
- /*------------------------------------------------------------------*/
-@@ -1108,6 +1112,7 @@
- return single_open(file, xusb_read_proc_show, PDE_DATA(inode));
- }
-
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
- static const struct file_operations xusb_read_proc_ops = {
- .owner = THIS_MODULE,
- .open = xusb_read_proc_open,
-@@ -1115,8 +1120,14 @@
- .llseek = seq_lseek,
- .release = single_release,
- };
--
--
-+#else
-+static const struct proc_ops xusb_read_proc_ops = {
-+ .proc_open = xusb_read_proc_open,
-+ .proc_read = seq_read,
-+ .proc_lseek = seq_lseek,
-+ .proc_release = single_release,
-+};
-+#endif
- #endif
-
- MODULE_DESCRIPTION("XPP USB Transport Driver");
diff --git a/system/dahdi-complete/patches/08-digium-restore-old-hardwareids.patch b/system/dahdi-complete/patches/08-digium-restore-old-hardwareids.patch
deleted file mode 100644
index ec82bef35c44d..0000000000000
--- a/system/dahdi-complete/patches/08-digium-restore-old-hardwareids.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-diff --git a/Makefile b/Makefile
-index fda4c08..fab7a24 100644
---- a/Makefile
-+++ b/Makefile
-@@ -102,6 +102,8 @@ install-modconf:
- /sbin/update-modules ; \
- fi
-
-+install-xpp-firm:
-+ $(MAKE) -C drivers/dahdi/xpp/firmwares install
-
- install-firmware:
- ifeq ($(HOTPLUG_FIRMWARE),yes)
-diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
-index 95ff5bc..ad899f8 100644
---- a/drivers/dahdi/wctdm24xxp/base.c
-+++ b/drivers/dahdi/wctdm24xxp/base.c
-@@ -6052,7 +6052,11 @@ static void __devexit wctdm_remove_one(struct pci_dev *pdev)
-
- static DEFINE_PCI_DEVICE_TABLE(wctdm_pci_tbl) = {
- { 0xd161, 0x2400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm2400 },
-+ { 0xd161, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm800 },
-+ { 0xd161, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex800 },
- { 0xd161, 0x8003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex2400 },
-+ { 0xd161, 0x8005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wctdm410 },
-+ { 0xd161, 0x8006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcaex410 },
- { 0xd161, 0x8007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcha80000 },
- { 0xd161, 0x8008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wchb80000 },
- { 0 }
diff --git a/system/dahdi-complete/patches/09-dahdi-3.1.0-r3-remove-32bit-userspace-on-64bit-support.patch b/system/dahdi-complete/patches/09-dahdi-3.1.0-r3-remove-32bit-userspace-on-64bit-support.patch
deleted file mode 100644
index 4ef27706ceeb5..0000000000000
--- a/system/dahdi-complete/patches/09-dahdi-3.1.0-r3-remove-32bit-userspace-on-64bit-support.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 4df746fe3ffd6678f36b16c9b0750fa552da92e4 Mon Sep 17 00:00:00 2001
-From: Shaun Ruffell <sruffell@sruffell.net>
-Date: Mon, 16 Nov 2020 22:01:21 -0600
-Subject: [PATCH] Remove support for 32-bit userspace with 64-bit kernel
-
-I am not aware of anyone who tests in this configuration, and I'm not
-sure if it currently works. I'll remove any support for the time being
-and can add it back in if someone comes forward needing support for it.
-
-Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
----
- drivers/dahdi/dahdi-base.c | 34 ----------------------------------
- 1 file changed, 34 deletions(-)
-
-diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
-index 4fb06d9..9fb0c79 100644
---- a/drivers/dahdi/dahdi-base.c
-+++ b/drivers/dahdi/dahdi-base.c
-@@ -7019,17 +7019,6 @@ static int dahdi_ioctl(struct inode *inode, struct file *file,
- }
- #endif
-
--#ifdef HAVE_COMPAT_IOCTL
--static long dahdi_ioctl_compat(struct file *file, unsigned int cmd,
-- unsigned long data)
--{
-- if (cmd == DAHDI_SFCONFIG)
-- return -ENOTTY; /* Not supported yet */
--
-- return dahdi_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- /**
- * _get_next_channo - Return the next taken channel number from the span list.
- * @span: The span with which to start the search.
-@@ -10285,9 +10274,6 @@ static const struct file_operations dahdi_fops = {
- .release = dahdi_release,
- #ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_unlocked_ioctl,
--#ifdef HAVE_COMPAT_IOCTL
-- .compat_ioctl = dahdi_ioctl_compat,
--#endif
- #else
- .ioctl = dahdi_ioctl,
- #endif
-@@ -10301,9 +10287,6 @@ static const struct file_operations dahdi_timer_fops = {
- .release = dahdi_timer_release,
- #ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_timer_unlocked_ioctl,
--#ifdef HAVE_COMPAT_IOCTL
-- .compat_ioctl = dahdi_timer_unlocked_ioctl,
--#endif
- #else
- .ioctl = dahdi_timer_ioctl,
- #endif
-@@ -10377,24 +10360,10 @@ static int nodev_ioctl(struct inode *inode, struct file *file,
- }
- #endif
-
--#ifdef HAVE_COMPAT_IOCTL
--static long nodev_ioctl_compat(struct file *file, unsigned int cmd,
-- unsigned long data)
--{
-- if (cmd == DAHDI_SFCONFIG)
-- return -ENOTTY; /* Not supported yet */
--
-- return nodev_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- static const struct file_operations nodev_fops = {
- .owner = THIS_MODULE,
- #ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = nodev_unlocked_ioctl,
--#ifdef HAVE_COMPAT_IOCTL
-- .compat_ioctl = nodev_ioctl_compat,
--#endif
- #else
- .ioctl = nodev_ioctl,
- #endif
-@@ -10409,9 +10378,6 @@ static const struct file_operations dahdi_chan_fops = {
- .release = dahdi_release,
- #ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_unlocked_ioctl,
--#ifdef HAVE_COMPAT_IOCTL
-- .compat_ioctl = dahdi_ioctl_compat,
--#endif
- #else
- .ioctl = dahdi_ioctl,
- #endif
---
-2.26.2
-
diff --git a/system/dahdi-complete/patches/10-dahdi-3.1.0-r3-ioctl-kernel-5.9.patch b/system/dahdi-complete/patches/10-dahdi-3.1.0-r3-ioctl-kernel-5.9.patch
deleted file mode 100644
index 8688d34a10e4b..0000000000000
--- a/system/dahdi-complete/patches/10-dahdi-3.1.0-r3-ioctl-kernel-5.9.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From 6d4c748e0470efac90e7dc4538ff3c5da51f0169 Mon Sep 17 00:00:00 2001
-From: Shaun Ruffell <sruffell@sruffell.net>
-Date: Mon, 16 Nov 2020 22:01:22 -0600
-Subject: [PATCH] Remove checks for HAVE_UNLOCKED_IOCTL for kernel >= 5.9
-
-In upstream commit (4e24566a134ea1674 "fs: remove the HAVE_UNLOCKED_IOCTL and
-HAVE_COMPAT_IOCTL defines") [1] the kernel removed these defines.
-
-All supported kernels include support for the unlocked_ioctl now, so
-DAHDI can also remove these checks.
-
-[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4e24566a134ea167441a1ffa3d439a27c
-
-Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
----
- drivers/dahdi/dahdi-base.c | 44 ---------------------------------
- drivers/dahdi/dahdi_transcode.c | 11 ---------
- 2 files changed, 55 deletions(-)
-
-diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
-index 9fb0c79..bb51e9c 100644
---- a/drivers/dahdi/dahdi-base.c
-+++ b/drivers/dahdi/dahdi-base.c
-@@ -53,10 +53,6 @@
- #include <linux/ktime.h>
- #include <linux/slab.h>
-
--#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL)
--#include <linux/smp_lock.h>
--#endif
--
- #include <linux/ppp_defs.h>
-
- #include <asm/atomic.h>
-@@ -4069,14 +4065,6 @@ dahdi_timer_unlocked_ioctl(struct file *file, unsigned int cmd,
- return 0;
- }
-
--#ifndef HAVE_UNLOCKED_IOCTL
--static int dahdi_timer_ioctl(struct inode *inode, struct file *file,
-- unsigned int cmd, unsigned long data)
--{
-- return dahdi_timer_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- static int dahdi_ioctl_getgains(struct file *file, unsigned long data)
- {
- int res = 0;
-@@ -7011,14 +6999,6 @@ exit:
- return ret;
- }
-
--#ifndef HAVE_UNLOCKED_IOCTL
--static int dahdi_ioctl(struct inode *inode, struct file *file,
-- unsigned int cmd, unsigned long data)
--{
-- return dahdi_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- /**
- * _get_next_channo - Return the next taken channel number from the span list.
- * @span: The span with which to start the search.
-@@ -10272,11 +10252,7 @@ static const struct file_operations dahdi_fops = {
- .owner = THIS_MODULE,
- .open = dahdi_open,
- .release = dahdi_release,
--#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_unlocked_ioctl,
--#else
-- .ioctl = dahdi_ioctl,
--#endif
- .poll = dahdi_poll,
- .read = dahdi_no_read,
- .write = dahdi_no_write,
-@@ -10285,11 +10261,7 @@ static const struct file_operations dahdi_fops = {
- static const struct file_operations dahdi_timer_fops = {
- .owner = THIS_MODULE,
- .release = dahdi_timer_release,
--#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_timer_unlocked_ioctl,
--#else
-- .ioctl = dahdi_timer_ioctl,
--#endif
- .poll = dahdi_timer_poll,
- .read = dahdi_no_read,
- .write = dahdi_no_write,
-@@ -10352,21 +10324,9 @@ nodev_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data)
- return nodev_common("ioctl");
- }
-
--#ifndef HAVE_UNLOCKED_IOCTL
--static int nodev_ioctl(struct inode *inode, struct file *file,
-- unsigned int cmd, unsigned long data)
--{
-- return nodev_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- static const struct file_operations nodev_fops = {
- .owner = THIS_MODULE,
--#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = nodev_unlocked_ioctl,
--#else
-- .ioctl = nodev_ioctl,
--#endif
- .read = nodev_chan_read,
- .write = nodev_chan_write,
- .poll = nodev_chan_poll,
-@@ -10376,11 +10336,7 @@ static const struct file_operations dahdi_chan_fops = {
- .owner = THIS_MODULE,
- .open = dahdi_open,
- .release = dahdi_release,
--#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_unlocked_ioctl,
--#else
-- .ioctl = dahdi_ioctl,
--#endif
- .read = dahdi_chan_read,
- .write = dahdi_chan_write,
- .poll = dahdi_chan_poll,
-diff --git a/drivers/dahdi/dahdi_transcode.c b/drivers/dahdi/dahdi_transcode.c
-index a495dcf..6021aac 100644
---- a/drivers/dahdi/dahdi_transcode.c
-+++ b/drivers/dahdi/dahdi_transcode.c
-@@ -397,13 +397,6 @@ static long dahdi_tc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne
- };
- }
-
--#ifndef HAVE_UNLOCKED_IOCTL
--static int dahdi_tc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
--{
-- return (int)dahdi_tc_unlocked_ioctl(file, cmd, data);
--}
--#endif
--
- static unsigned int dahdi_tc_poll(struct file *file, struct poll_table_struct *wait_table)
- {
- int ret;
-@@ -427,11 +420,7 @@ static struct file_operations __dahdi_transcode_fops = {
- .owner = THIS_MODULE,
- .open = dahdi_tc_open,
- .release = dahdi_tc_release,
--#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = dahdi_tc_unlocked_ioctl,
--#else
-- .ioctl = dahdi_tc_ioctl,
--#endif
- .read = dahdi_tc_read,
- .write = dahdi_tc_write,
- .poll = dahdi_tc_poll,
---
-2.26.2
-
diff --git a/system/dahdi-complete/patches/11-dahdi-3.1.0-r3-clang.patch b/system/dahdi-complete/patches/11-dahdi-3.1.0-r3-clang.patch
deleted file mode 100644
index 8b0cf18ec17ad..0000000000000
--- a/system/dahdi-complete/patches/11-dahdi-3.1.0-r3-clang.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From d55a2e89b74f752bb1b7a06ab57cebcc3f258d56 Mon Sep 17 00:00:00 2001
-From: Jaco Kroon <jaco@iewc.co.za>
-Date: Fri, 8 Jan 2021 14:27:30 +0200
-Subject: [PATCH] Enable building with CC=clang
-
-This requires that the host kernel also be built with CC=clang.
-
-Signed-off-by: Jaco Kroon <jaco@iewc.co.za>
----
- drivers/dahdi/Kbuild | 2 +-
- drivers/dahdi/oct612x/Kbuild | 2 +-
- drivers/dahdi/voicebus/Kbuild | 2 +-
- drivers/dahdi/wcb4xxp/Kbuild | 2 +-
- drivers/dahdi/wct4xxp/Kbuild | 4 ++--
- drivers/dahdi/wctc4xxp/Kbuild | 2 +-
- drivers/dahdi/wctdm24xxp/Kbuild | 2 +-
- 7 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/dahdi/Kbuild b/drivers/dahdi/Kbuild
-index c7144b6..a41021f 100644
---- a/drivers/dahdi/Kbuild
-+++ b/drivers/dahdi/Kbuild
-@@ -59,7 +59,7 @@ obj-m += dahdi_echocan_oslec.o
- obj-m += ../staging/echo/echo.o
- endif
-
--CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(src) -Wno-format-truncation
-+CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(src) $(call cc-disable-warning, format-truncation)
-
- ifndef HOTPLUG_FIRMWARE
- ifneq (,$(filter y m,$(CONFIG_FW_LOADER)))
-diff --git a/drivers/dahdi/oct612x/Kbuild b/drivers/dahdi/oct612x/Kbuild
-index ac53fe7..9ff971c 100644
---- a/drivers/dahdi/oct612x/Kbuild
-+++ b/drivers/dahdi/oct612x/Kbuild
-@@ -27,6 +27,6 @@ octapi_files = octdeviceapi/oct6100api/oct6100_api/oct6100_adpcm_chan.o \
- # TODO: ccflags was added in 2.6.24 in commit f77bf01425b11947eeb3b5b54. This
- # should be changed to a conditional compilation based on the Kernel Version.
- # ccflags-y := -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
--EXTRA_CFLAGS = -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
-+EXTRA_CFLAGS = -I$(src)/.. $(call cc-disable-warning,undef) -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OCT612X) := oct612x.o
- oct612x-objs := $(octapi_files)
-diff --git a/drivers/dahdi/voicebus/Kbuild b/drivers/dahdi/voicebus/Kbuild
-index 3bf9640..4052515 100644
---- a/drivers/dahdi/voicebus/Kbuild
-+++ b/drivers/dahdi/voicebus/Kbuild
-@@ -11,7 +11,7 @@ else
- EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
- endif
-
--EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
-+EXTRA_CFLAGS += -I$(src)/.. $(call cc-disable-warning, undef)
-
- $(obj)/$(FIRM_DIR)/dahdi-fw-vpmoct032.o: $(obj)/voicebus.o
- $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-vpmoct032.o
-diff --git a/drivers/dahdi/wcb4xxp/Kbuild b/drivers/dahdi/wcb4xxp/Kbuild
-index 80606bf..306e986 100644
---- a/drivers/dahdi/wcb4xxp/Kbuild
-+++ b/drivers/dahdi/wcb4xxp/Kbuild
-@@ -1,6 +1,6 @@
- obj-m += wcb4xxp.o
-
--EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
-+EXTRA_CFLAGS += -I$(src)/.. $(call cc-disable-warning, undef)
-
- wcb4xxp-objs := base.o
-
-diff --git a/drivers/dahdi/wct4xxp/Kbuild b/drivers/dahdi/wct4xxp/Kbuild
-index cf01ccf..d4578da 100644
---- a/drivers/dahdi/wct4xxp/Kbuild
-+++ b/drivers/dahdi/wct4xxp/Kbuild
-@@ -2,13 +2,13 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP) += wct4xxp.o
-
- FIRM_DIR := ../firmware
-
--EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
-+EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) $(call cc-disable-warning, undef)
-
- # The OCT612X source files are from a vendor drop and we do not want to edit
- # them to make this warning go away. Therefore, turn off the
- # unused-but-set-variable warning for this driver.
-
--EXTRA_CFLAGS += $(call cc-option, -Wno-unused-but-set-variable)
-+#EXTRA_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
-
- ifeq ($(HOTPLUG_FIRMWARE),yes)
- EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
-diff --git a/drivers/dahdi/wctc4xxp/Kbuild b/drivers/dahdi/wctc4xxp/Kbuild
-index 9f97498..451f380 100644
---- a/drivers/dahdi/wctc4xxp/Kbuild
-+++ b/drivers/dahdi/wctc4xxp/Kbuild
-@@ -2,7 +2,7 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP) += wctc4xxp.o
-
- FIRM_DIR := ../firmware
-
--EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
-+EXTRA_CFLAGS += -I$(src)/.. $(call cc-disable-warning,undef)
-
- ifeq ($(HOTPLUG_FIRMWARE),yes)
- EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
-diff --git a/drivers/dahdi/wctdm24xxp/Kbuild b/drivers/dahdi/wctdm24xxp/Kbuild
-index 22cc71a..98b99a9 100644
---- a/drivers/dahdi/wctdm24xxp/Kbuild
-+++ b/drivers/dahdi/wctdm24xxp/Kbuild
-@@ -1,5 +1,5 @@
- obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP) += wctdm24xxp.o
-
--EXTRA_CFLAGS += -I$(src)/.. -Wno-undef
-+EXTRA_CFLAGS += -I$(src)/.. $(call cc-disable-warning, undef)
-
- wctdm24xxp-objs := base.o xhfc.o
---
-2.26.2
-