diff options
Diffstat (limited to 'system/dahdi-complete')
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(®s, 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, ®s, sizeof(regs))) -+ return -EFAULT; -+ break; -+ case WCTDM_SET_REG: -+ if (copy_from_user(®op, (__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, ®s, 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, ®s)) { -+ 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, -+ ®s.indirect[x])) -+ return -EIO; -+ for (x = 0; x < NUM_REGS; x++) -+ if (!read_reg_fxs(wc, port, x, ®s.direct[x])) -+ return -EIO; -+ } else { -+ memset(®s, 0, sizeof(regs)); -+ for (x = 0; x < NUM_FXO_REGS; x++) { -+ if (!read_reg_fxo(wc, port, x, ®s.direct[x])) -+ return -EIO; -+ } -+ } -+ if (copy_to_user((void __user *)data, ®s, sizeof(regs))) -+ return -EFAULT; -+ break; -+ case WCTDM_SET_REG: -+ if (copy_from_user(®op, (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 - |