diff options
-rw-r--r-- | dahdi-linux-2.10.1-allo.patch | 7300 | ||||
-rw-r--r-- | dahdi-linux-2.10.1-openvox-1.patch | 6228 | ||||
-rw-r--r-- | dahdi-linux-2.10.1-openvox-2.patch | 5851 | ||||
-rw-r--r-- | dahdi-linux-2.10.1-openvox-3.patch | 7272 | ||||
-rw-r--r-- | dahdi-linux-2.10.1-yeastar.patch | 6269 |
5 files changed, 0 insertions, 32920 deletions
diff --git a/dahdi-linux-2.10.1-allo.patch b/dahdi-linux-2.10.1-allo.patch deleted file mode 100644 index 99a1ed2d21f0..000000000000 --- a/dahdi-linux-2.10.1-allo.patch +++ /dev/null @@ -1,7300 +0,0 @@ -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/Kbuild dahdi-linux-2.10.0.1-allo/drivers/dahdi/Kbuild ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kbuild 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/Kbuild 2015-02-10 15:12:17.829888792 +0100 -@@ -14,6 +14,8 @@ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE13XP) += wcte13xp.o - -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ALLO4XXP) += allo4xxp/ -+ - wcte13xp-objs := wcte13xp-base.o wcxb_spi.o wcxb.o wcxb_flash.o - CFLAGS_wcte13xp-base.o += -I$(src)/oct612x -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api - ifeq ($(HOTPLUG_FIRMWARE),yes) -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/Kconfig dahdi-linux-2.10.0.1-allo/drivers/dahdi/Kconfig ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kconfig 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/Kconfig 2015-02-10 15:01:15.886129051 +0100 -@@ -291,4 +291,14 @@ - - If unsure, say Y. - -+config DAHDI_ALLO4XXP -+ tristate "Allo TE410P Quad-T1/E1 PCI" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ To compile this driver as a module, choose M here: the -+ module will be called wcte11xp. -+ -+ If unsure, say Y. -+ - source "drivers/dahdi/xpp/Kconfig" -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/Kbuild dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/Kbuild ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/Kbuild 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/Kbuild 2015-02-10 15:01:15.886129051 +0100 -@@ -0,0 +1,31 @@ -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_ALLO4XXP) += allo4xxp.o -+ -+FIRM_DIR := ../firmware -+ -+EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-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) -+ -+ifeq ($(HOTPLUG_FIRMWARE),yes) -+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE -+endif -+ -+allo4xxp-objs := base.o vpm450m.o -+ -+ifneq ($(HOTPLUG_FIRMWARE),yes) -+allo4xxp-objs += $(FIRM_DIR)/dahdi-fw-oct6114-064.o $(FIRM_DIR)/dahdi-fw-oct6114-128.o $(FIRM_DIR)/dahdi-fw-oct6114-256.o -+$(warning WARNING: You are compiling firmware into allo4xxp.ko which is not available under the terms of the GPL. It may be a violation of the GPL to distribute the resulting image since it combines both GPL and non-GPL work. You should consult a lawyer of your own before distributing such an image.) -+endif -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-064.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-064.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-128.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-128.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-256.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-256.o -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/allo4xxp.h dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/allo4xxp.h ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/allo4xxp.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/allo4xxp.h 2015-02-10 15:01:15.886129051 +0100 -@@ -0,0 +1,144 @@ -+/* -+ * Wildcard T400P FXS Interface Driver for DAHDI Telephony interface -+ * -+ * Written by Mark Spencer <markster@linux-support.net> -+ * -+ * 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/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 -+/* OctalFALC Only */ -+#define FRMR_CMR4 0x41 -+#define FRMR_CMR5 0x42 -+#define FRMR_CMR6 0x43 -+#define FRMR_GPC2 0x8a -+/* End Octal */ -+#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 -+ -+/* CIS - Octal falc bits */ -+#define FRMR_CIS_GIS5 0x10 -+#define FRMR_CIS_GIS6 0x20 -+#define FRMR_CIS_GIS7 0x40 -+#define FRMR_CIS_GIS8 0x80 -+ -+#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]; -+}; -+ -+struct t4_reg { -+ unsigned int reg; -+ unsigned int val; -+}; -+ -+#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) -+#define WCT4_GET_REG _IOW(DAHDI_CODE, 61, struct t4_reg) -+#define WCT4_SET_REG _IOW(DAHDI_CODE, 62, struct t4_reg) -+ -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/base.c dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/base.c ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/base.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/base.c 2015-02-10 15:01:15.889462151 +0100 -@@ -0,0 +1,5677 @@ -+/* -+ * TE410P Quad-T1/E1 PCI Driver version 0.1, 12/16/02 -+ * -+ * Written by Mark Spencer <markster@digium.com> -+ * Based on previous works, designs, and archetectures conceived and -+ * written by Jim Dixon <jim@lambdatel.com>. -+ * Further modified, optimized, and maintained by -+ * Matthew Fredrickson <creslin@digium.com> and -+ * Russ Meyerriecks <rmeyerriecks@digium.com> -+ * -+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony. -+ * Copyright (C) 2001-2012, 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 <linux/crc32.h> -+ -+#include <stdbool.h> -+#include <dahdi/kernel.h> -+ -+#include "allo4xxp.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 -+ -+/* Support first generation cards? */ -+#define SUPPORT_GEN1 -+ -+/* Define to get more attention-grabbing but slightly more I/O using -+ alarm status */ -+#undef 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 -+ -+#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 */ -+ struct cpu_workqueue_struct *cpu_wq; -+ 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_FORCE_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 -+ */ -+/* #define CONFIG_FORCE_EXTENDED_RESET */ -+/* #define CONFIG_NOEXTENDED_RESET */ -+ -+/* -+ * Uncomment the following definition in order to disable Active-State Power -+ * Management on the PCIe bridge for PCIe cards. This has been known to work -+ * around issues where the BIOS enables it on the cards even though the -+ * platform does not support it. -+ * -+ */ -+/* #define CONFIG_WCT4XXP_DISABLE_ASPM */ -+ -+#if defined(CONFIG_FORCE_EXTENDED_RESET) && defined(CONFIG_NOEXTENDED_RESET) -+#error "You cannot define both CONFIG_FORCE_EXTENDED_RESET and " \ -+ "CONFIG_NOEXTENDED_RESET." -+#endif -+ -+int debug = 0; -+static int timingcable = 0; -+static int t1e1override = -1; /* deprecated */ -+static char *default_linemode = "auto"; -+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*/ -+#endif /* VPM_SUPPORT */ -+ -+/* 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; -+static int ignore_rotary; -+ -+#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 FLAG_2NDGEN (1 << 3) -+#define FLAG_2PORT (1 << 4) -+#define FLAG_VPM2GEN (1 << 5) -+#define FLAG_OCTOPT (1 << 6) -+#define FLAG_3RDGEN (1 << 7) -+#define FLAG_BURST (1 << 8) -+#define FLAG_EXPRESS (1 << 9) -+#define FLAG_5THGEN (1 << 10) -+#define FLAG_8PORT (1 << 11) -+#define FLAG_1PORT (1 << 12) -+ -+#define CANARY 0xc0de -+ -+/* names of available HWEC modules */ -+#ifdef VPM_SUPPORT -+#define T4_VPM_PRESENT (1 << 28) -+static const char *vpmoct032_name = "VPMOCT032"; //cem:1port change -+static const char *vpmoct064_name = "VPMOCT064"; -+static const char *vpmoct128_name = "VPMOCT128"; -+static const char *vpmoct256_name = "VPMOCT256"; -+#endif -+ -+struct devtype { -+ char *desc; -+ unsigned int flags; -+}; -+/*ALLO:*/ -+static struct devtype allo1280p2 = { "Allocard 2aCP8e (2nd Gen)", FLAG_8PORT | FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS }; -+static struct devtype allo1240p2 = { "Allocard 2aCP4e (2nd Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS }; -+static struct devtype allo1241p2 = { "Allocard 2aCP4 (2nd Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN }; -+static struct devtype allo1220p2 = { "Allocard 2aCP2e (2nd Gen)", FLAG_2PORT | FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_EXPRESS }; -+static struct devtype allo1210p2 = { "Allocard 2aCP1e (2nd Gen)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_1PORT }; -+ -+ -+struct t4; -+ -+enum linemode {T1, E1, J1}; -+ -+struct spi_state { -+ int wrreg; -+ int rdreg; -+}; -+ -+struct t4_span { -+ struct t4 *owner; -+ u32 *writechunk; /* Double-word aligned write memory */ -+ u32 *readchunk; /* Double-word aligned read memory */ -+ enum linemode linemode; -+ int sync; -+ int alarmtimer; -+ int notclear; -+ unsigned long alarm_time; -+ unsigned long losalarm_time; -+ unsigned long aisalarm_time; -+ unsigned long yelalarm_time; -+ unsigned long alarmcheck_time; -+ 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 -+ /* 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; -+#endif -+#ifdef ENABLE_WORKQUEUES -+ struct work_struct swork; -+#endif -+ struct dahdi_chan *chans[32]; /* Individual channels */ -+ struct dahdi_echocan_state *ec[32]; /* Echocan state for each channel */ -+}; -+ -+struct t4 { -+ /* This structure exists one per card */ -+ struct pci_dev *dev; /* Pointer to PCI device */ -+ unsigned int intcount; -+ int num; /* Which card we are */ -+ int syncsrc; /* active sync source */ -+ struct dahdi_device *ddev; -+ struct t4_span *tspans[8]; /* 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 */ -+ const struct devtype *devtype; -+ unsigned int reset_required:1; /* If reset needed in serial_setup */ -+ unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */ -+ unsigned int t1e1:8; /* T1 / E1 select pins */ -+ int ledreg; /* LED Register */ -+ int ledreg2; /* LED Register2 */ -+ unsigned int gpio; -+ unsigned int gpioctl; -+ int e1recover; /* E1 recovery timer */ -+ spinlock_t reglock; /* lock register access */ -+ int spansstarted; /* number of spans started */ -+ u32 *writechunk; /* Double-word aligned write memory */ -+ u32 *readchunk; /* Double-word aligned read memory */ -+#ifdef ENABLE_WORKQUEUES -+ atomic_t worklist; -+ struct workqueue_struct *workq; -+#endif -+ int last0; /* for detecting double-missed IRQ */ -+ -+ /* DMA related fields */ -+ unsigned int dmactrl; -+ dma_addr_t readdma; -+ dma_addr_t writedma; -+ void __iomem *membase; /* Base address of card */ -+ -+ /* Flags for our bottom half */ -+ unsigned long checkflag; -+ struct tasklet_struct t4_tlet; -+ /* Latency related additions */ -+ unsigned char rxident; -+ unsigned char lastindex; -+ int numbufs; -+ int needed_latency; -+ -+#ifdef VPM_SUPPORT -+ struct vpm450m *vpm; -+#endif -+ struct spi_state st; -+}; -+ -+static inline bool is_pcie(const struct t4 *wc) -+{ -+ return (wc->devtype->flags & FLAG_EXPRESS) > 0; -+} -+ -+static inline bool has_e1_span(const struct t4 *wc) -+{ -+ return (wc->t1e1 > 0); -+} -+ -+static inline bool is_octal(const struct t4 *wc) -+{ -+ return (wc->devtype->flags & FLAG_8PORT) > 0; -+} -+ -+static inline int T4_BASE_SIZE(struct t4 *wc) -+{ -+ if (is_octal(wc)) -+ return DAHDI_MAX_CHUNKSIZE * 32 * 8; -+ else -+ return DAHDI_MAX_CHUNKSIZE * 32 * 4; -+} -+ -+/** -+ * ports_on_framer - The number of ports on the framers. -+ * @wc: Board to check. -+ * -+ * The framer ports could be different the the number of ports on the card -+ * since the dual spans have four ports internally but two ports extenally. -+ * -+ */ -+static inline unsigned int ports_on_framer(const struct t4 *wc) -+{ -+ return (is_octal(wc)) ? 8 : 4; -+} -+ -+#ifdef VPM_SUPPORT -+static void t4_vpm_init(struct t4 *wc); -+ -+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); -+ -+static const struct dahdi_echocan_features vpm_ec_features = { -+ .NLP_automatic = 1, -+ .CED_tx_detect = 1, -+ .CED_rx_detect = 1, -+}; -+ -+static const struct dahdi_echocan_ops vpm_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_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); -+static int t4_reset_counters(struct dahdi_span *span); -+#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_LEDS2 12 -+ -+#define WC_SET_AUTH (1 << 20) -+#define WC_GET_AUTH (1 << 12) -+ -+#define WC_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */ -+#define WC_LCS (1 << 11) -+#define WC_LCS2 (1 << 12) -+#define WC_LALE (1 << 13) -+#define WC_LFRMR_CS2 (1 << 14) /* Framer's ChipSelect signal 2 */ -+#define WC_LREAD (1 << 15) -+#define WC_LWRITE (1 << 16) -+ -+#define WC_ACTIVATE (1 << 12) -+ -+#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 FMR5 0x21 /* Framer Mode Register 5 */ -+#define FMR5_XLU (1 << 4) /* Transmit loopup code */ -+#define FMR5_XLD (1 << 5) /* Transmit loopdown code */ -+#define FMR5_EIBR (1 << 6) /* Internal Bit Robbing Access */ -+#define DEC_T 0x60 /* Diable Error Counter */ -+#define IERR_T 0x1B /* Single Bit Defect Insertion Register */ -+#define IBV (1 << 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]; -+ -+struct t8_firm_header { -+ u8 header[6]; -+ __le32 chksum; -+ u8 pad[18]; -+ __le32 version; -+} __packed; -+ -+#define MAX_TDM_CHAN 32 -+#define MAX_DTMF_DET 16 -+ -+#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF) -+#define HDLC_IMR1_MASK (FRMR_IMR1_XDU | FRMR_IMR1_XPR) -+ -+static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr) -+{ -+ unsigned int res = readl(wc->membase + (addr * sizeof(u32))); -+ return res; -+} -+ -+static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value) -+{ -+#ifdef DEBUG -+ unsigned int tmp; -+#endif -+ writel(value, wc->membase + (addr * sizeof(u32))); -+#ifdef DEBUG -+ tmp = __t4_pci_in(wc, WC_VERSION); -+ if ((tmp & 0xffff0000) != 0xc01a0000) -+ dev_notice(&wc->dev->dev, -+ "Version Synchronization Error!\n"); -+#else -+ __t4_pci_in(wc, WC_VERSION); -+#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) -+{ -+ if (span <= 3) { -+ 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); -+ } else { -+ int oldreg = wc->ledreg2; -+ -+ span &= 3; -+ wc->ledreg2 &= ~(0x3 << (span << 1)); -+ wc->ledreg2 |= (color << (span << 1)); -+ if (oldreg != wc->ledreg2) -+ __t4_pci_out(wc, WC_LEDS2, wc->ledreg2); -+ } -+} -+ -+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 unsigned int __t4_framer_in(const struct t4 *wc, int unit, -+ const unsigned int addr) -+{ -+ unsigned int ret; -+ register u32 val; -+ void __iomem *const wc_laddr = wc->membase + (WC_LADDR*sizeof(u32)); -+ void __iomem *const wc_version = wc->membase + (WC_VERSION*sizeof(u32)); -+ void __iomem *const wc_ldata = wc->membase + (WC_LDATA*sizeof(u32)); -+ int haddr = (((unit & 4) ? 0 : WC_LFRMR_CS2)); -+ unit &= 0x3; -+ -+ val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; -+ writel(val, wc_laddr); -+ readl(wc_version); -+ writel(val | WC_LFRMR_CS | WC_LREAD, wc_laddr); -+ readl(wc_version); -+ ret = readb(wc_ldata); -+ writel(val, wc_laddr); -+ readl(wc_version); -+ return ret; -+} -+ -+static 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 void __t4_framer_out(const struct t4 *wc, int unit, const u8 addr, -+ const unsigned int value) -+{ -+ register u32 val; -+ void __iomem *const wc_laddr = wc->membase + (WC_LADDR*sizeof(u32)); -+ void __iomem *const wc_version = wc->membase + (WC_VERSION*sizeof(u32)); -+ void __iomem *const wc_ldata = wc->membase + (WC_LDATA*sizeof(u32)); -+ int haddr = (((unit & 4) ? 0 : WC_LFRMR_CS2)); -+ -+ val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; -+ writel(val, wc_laddr); -+ readl(wc_version); -+ writel(value, wc_ldata); -+ readl(wc_version); -+ writel(val | WC_LFRMR_CS | WC_LWRITE, wc_laddr); -+ readl(wc_version); -+ writel(val, wc_laddr); -+ readl(wc_version); -+} -+ -+static 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 __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 (!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)); -+ __t4_pci_out(wc, WC_LADDR, (0)); -+} -+ -+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)); -+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE)); -+ __t4_pci_out(wc, WC_LADDR, (WC_LALE)); -+ 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 (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 (!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 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 void t4_check_vpm(struct t4 *wc) -+{ -+ int channel, tone, start, span; -+ -+ if (vpm450m_checkirq(wc->vpm)) { -+ while(vpm450m_getdtmf(wc->vpm, &channel, &tone, &start)) { -+ span = channel & 0x3; -+ channel >>= 2; -+ if (!has_e1_span(wc)) -+ 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)); -+ } -+ } -+ } -+ } -+} -+ -+#endif /* VPM_SUPPORT */ -+ -+static void hdlc_stop(struct t4 *wc, unsigned int span) -+{ -+ struct t4_span *t = wc->tspans[span]; -+ unsigned char imr0, imr1, mode; -+ unsigned long flags; -+ 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); -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ 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; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* 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); -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* 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 (E1 != ts->linemode) { -+ 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); -+ } -+} -+ -+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 const char *__t4_echocan_name(struct t4 *wc) -+{ -+ if (wc->vpm) { -+ if (wc->numspans == 2) -+ return vpmoct064_name; -+ else if (wc->numspans == 4) -+ return vpmoct128_name; -+ else if (wc->numspans == 1) //cem:1port change -+ return vpmoct032_name; //cem:1port change -+ else if (wc->numspans == 8) -+ return vpmoct256_name; -+ } -+ return NULL; -+} -+ -+static const char *t4_echocan_name(const struct dahdi_chan *chan) -+{ -+ struct t4 *wc = chan->pvt; -+ return __t4_echocan_name(wc); -+} -+ -+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 bool alaw = (chan->span->deflaw == 2); -+ -+ if (!vpmsupport || !wc->vpm) -+ return -ENODEV; -+ -+ if (ecp->param_count > 0) { -+ dev_warn(&wc->dev->dev, "%s echo canceller does not support " -+ "parameters; failing request\n", -+ chan->ec_factory->get_name(chan)); -+ return -EINVAL; -+ } -+ -+ *ec = tspan->ec[chan->chanpos - 1]; -+ (*ec)->ops = &vpm_ec_ops; -+ (*ec)->features = vpm_ec_features; -+ -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ 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_set_alaw_companding(wc->vpm, channel, alaw); -+ vpm450m_setec(wc->vpm, channel, ecp->tap_length); -+ return 0; -+} -+ -+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) -+{ -+ struct t4 *wc = chan->pvt; -+ int channel; -+ -+ if (!wc->vpm) -+ return; -+ -+ memset(ec, 0, sizeof(*ec)); -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ 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->vpm, channel, 0); -+} -+#endif -+ -+static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) -+{ -+ struct t4_regs regs; -+ struct t4_reg reg; -+ int x; -+ struct t4 *wc = chan->pvt; -+#ifdef VPM_SUPPORT -+ int j; -+ int channel; -+ struct t4_span *ts = wc->tspans[chan->span->offset]; -+#endif -+ -+ switch(cmd) { -+ case WCT4_SET_REG: -+ if (copy_from_user(®, (struct t4_reg __user *)data, -+ sizeof(reg))) -+ return -EFAULT; -+ t4_pci_out(wc, reg.reg, reg.val); -+ break; -+ case WCT4_GET_REG: -+ if (copy_from_user(®, (struct t4_reg __user *)data, -+ sizeof(reg))) -+ return -EFAULT; -+ reg.val = t4_pci_in(wc, reg.reg); -+ if (copy_to_user((struct t4_reg __user *)data, -+ ®, sizeof(reg))) -+ return -EFAULT; -+ break; -+ 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((void __user *) 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); -+ -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ channel = channel << 2; -+ channel |= chan->span->offset; -+ vpm450m_setdtmf(wc->vpm, 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); -+ ++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); -+} -+ -+/** -+ * t4_set_framer_bits - Atomically set bits in a framer register. -+ */ -+static void t4_set_framer_bits(struct t4 *wc, unsigned int spanno, -+ unsigned int const addr, u16 bits) -+{ -+ unsigned long flags; -+ unsigned int reg; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reg = __t4_framer_in(wc, spanno, addr); -+ __t4_framer_out(wc, spanno, addr, (reg | bits)); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+} -+ -+static int t4_maint(struct dahdi_span *span, int cmd) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ unsigned int reg; -+ unsigned long flags; -+ -+ if (E1 == ts->linemode) { -+ 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); -+ t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); -+ break; -+ case DAHDI_MAINT_NETWORKLINELOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network line loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); -+ break; -+ case DAHDI_MAINT_NETWORKPAYLOADLOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network payload loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); -+ break; -+ case DAHDI_MAINT_LOOPUP: -+ case DAHDI_MAINT_LOOPDOWN: -+ dev_info(&wc->dev->dev, -+ "Loopup & loopdown not supported in E1 mode\n"); -+ return -ENOSYS; -+ 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"); -+ t4_set_framer_bits(wc, span->offset, FMR0, FMR0_SIM); -+ break; -+ 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); -+ t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); -+ break; -+ case DAHDI_MAINT_NETWORKLINELOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network line loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); -+ break; -+ case DAHDI_MAINT_NETWORKPAYLOADLOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network payload loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); -+ break; -+ case DAHDI_MAINT_LOOPUP: -+ dev_info(&wc->dev->dev, "Transmitting loopup code\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLU); -+ ts->span.maintstat = DAHDI_MAINT_REMOTELOOP; -+ break; -+ case DAHDI_MAINT_LOOPDOWN: -+ dev_info(&wc->dev->dev, "Transmitting loopdown code\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLD); -+ break; -+ 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"); -+ return -ENOSYS; -+ case DAHDI_RESET_COUNTERS: -+ t4_reset_counters(span); -+ break; -+ case DAHDI_MAINT_ALARM_SIM: -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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 -+ */ -+ __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; -+ 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 = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ unsigned int reg; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* 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))); -+ -+ /* Clear loopup/loopdown signals on the line */ -+ reg = __t4_framer_in(wc, span->offset, FMR5); -+ __t4_framer_out(wc, span->offset, FMR5, (reg & ~(FMR5_XLU | FMR5_XLD))); -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ span->mainttimer = 0; -+ -+ return 0; -+} -+ -+static int t4_reset_counters(struct dahdi_span *span) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ memset(&ts->span.count, 0, sizeof(ts->span.count)); -+ return 0; -+} -+ -+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 (E1 == ts->linemode) { -+ 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 = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ -+ tspan = span->offset + 1; -+ if (tspan < 0) { -+ dev_notice(&wc->dev->dev, "T%dXXP: Span '%d' isn't us?\n", -+ wc->numspans, 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 == 8) && -+ (!(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->tspans[4]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[5]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[6]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[7]->span.flags & DAHDI_FLAG_RUNNING))) -+ || -+ ((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 == 1) && //cem:1port change -+ (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING))) //cem:1port change -+ || -+ ((wc->numspans == 2) && -+ (!(wc->tspans[0]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING)))) { -+ /* No longer in use, disable interrupts */ -+ dev_info(&wc->dev->dev, "ALLO%dXXP: Disabling interrupts since " -+ "there are no active spans\n", wc->numspans); -+ 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 (E1 == wc->linemode) { -+ /* 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 = container_of(span, struct t4_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, "ALLO%dXXP: Configuring span %d\n", -+ wc->numspans, span->spanno); -+ -+ if (lc->sync < 0) -+ lc->sync = 0; -+ if (lc->sync > wc->numspans) { -+ dev_warn(&wc->dev->dev, "WARNING: Cannot set priority on span %d to %d. Please set to a number between 1 and %d\n", -+ span->spanno, 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[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; -+ -+ 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_spanconfig(struct file *file, struct dahdi_span *span, -+ struct dahdi_lineconfig *lc) -+{ -+ int ret; -+ struct dahdi_device *const ddev = span->parent; -+ struct dahdi_span *s; -+ -+ ret = _t4_spanconfig(file, span, lc); -+ -+ /* Make sure all the spans have a basic configuration in case they are -+ * not all specified in the configuration files. */ -+ lc->sync = 0; -+ list_for_each_entry(s, &ddev->spans, device_node) { -+ WARN_ON(!s->channels); -+ if (!s->channels) -+ continue; -+ if (!s->chans[0]->sigcap) -+ _t4_spanconfig(file, s, lc); -+ } -+ return ret; -+} -+ -+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, "ALLO%dXXP: Reconfigured " -+ "channel %d (%s) sigtype %d\n", wc->numspans, -+ chan->channo, chan->name, sigtype); -+ else -+ dev_notice(&wc->dev->dev, "ALLO%dXXP: Configured channel" -+ " %d (%s) sigtype %d\n", wc->numspans, -+ 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 int set_span_devicetype(struct t4 *wc) -+{ -+#ifdef VPM_SUPPORT -+ const char *vpmstring = __t4_echocan_name(wc); -+ -+ if (vpmstring) { -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s (%s)", -+ wc->devtype->desc, vpmstring); -+ } else { -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); -+ } -+#else -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); -+#endif -+ -+ if (!wc->ddev->devicetype) -+ return -ENOMEM; -+ return 0; -+} -+ -+/* 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; -+ int basesize = T4_BASE_SIZE(wc) >> 2; -+ -+ if (!has_e1_span(wc)) -+ 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 * (basesize))); -+ ts->readchunk = (void *)(wc->readchunk + (x * 32 * 2) + (which * (basesize))); -+ 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 * (basesize))); -+ mychans->readchunk = (void *)(wc->readchunk + ((x * 32 + y + offset) * 2) + (which * (basesize))); -+ } -+ } -+ } -+} -+ -+static int __t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, -+ bool first_time); -+static int __t4_hardware_init_2(struct t4 *wc, bool first_time); -+ -+static int t4_hardware_stop(struct t4 *wc); -+ -+static void t4_framer_reset(struct t4 *wc) -+{ -+ const bool first_time = false; -+ bool have_vpm = wc->vpm != NULL; -+ if (have_vpm) { -+ release_vpm450m(wc->vpm); -+ wc->vpm = NULL; -+ } -+ t4_hardware_stop(wc); -+ __t4_set_sclk_src(wc, WC_SELF, 0, 0); -+ __t4_hardware_init_1(wc, wc->devtype->flags, first_time); -+ __t4_hardware_init_2(wc, first_time); -+ if (have_vpm) { -+ t4_vpm_init(wc); -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } -+ setup_chunks(wc, 0); -+ wc->lastindex = 0; -+} -+ -+/** -+ * t4_serial_setup - Setup serial parameters and system interface. -+ * @wc: The card to configure. -+ * -+ */ -+static void t4_serial_setup(struct t4 *wc) -+{ -+ unsigned long flags; -+ unsigned int unit; -+ bool reset_required = false; -+ -+ if (debug) { -+ dev_info(&wc->dev->dev, -+ "ALLO%dXXP: Setting up global serial parameters\n", -+ wc->numspans);//cEM: -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reset_required = wc->reset_required > 0; -+ wc->reset_required = 0; -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (reset_required) -+ t4_framer_reset(wc); -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from -+ * channel 0 */ -+ __t4_framer_out(wc, 0, 0x85, 0xe0); -+ if (is_octal(wc)) -+ __t4_framer_out(wc, 0, FRMR_GPC2, 0x00); -+ -+ /* IPC: Interrupt push/pull active low */ -+ __t4_framer_out(wc, 0, 0x08, 0x01); -+ -+ if (is_octal(wc)) { -+ /* Global clocks (16.384 Mhz CLK) */ -+ __t4_framer_out(wc, 0, 0x92, 0x00); /* GCM1 */ -+ __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, 0x01); -+ __t4_framer_out(wc, 0, 0x97, 0x0b); -+ __t4_framer_out(wc, 0, 0x98, 0xdb); -+ __t4_framer_out(wc, 0, 0x99, 0xdf); -+ } else { -+ /* 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); -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ for (unit = 0; unit < ports_on_framer(wc); ++unit) { -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* Configure interrupts */ -+ /* GCR: Interrupt on Activation/Deactivation of each */ -+ __t4_framer_out(wc, unit, FRMR_GCR, 0x00); -+ -+ /* Configure system interface */ -+ if (is_octal(wc)) { -+ /* SIC1: 16.384 Mhz clock/bus, double buffer receive / -+ * transmit, byte interleaved */ -+ __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2 | 0x08); -+ } else { -+ /* SIC1: 8.192 Mhz clock/bus, double buffer receive / -+ * transmit, byte interleaved */ -+ __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2); -+ } -+ /* SIC2: No FFS, no center receive eliastic buffer, phase */ -+ __t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); -+ /* SIC3: Edges for capture */ -+ if (is_octal(wc)) { -+ __t4_framer_out(wc, unit, FRMR_SIC3, 0x04 | (1 << 4)); -+ } else { -+ __t4_framer_out(wc, unit, FRMR_SIC3, 0x04); -+ } -+ /* CMR2: We provide sync and clock for tx and rx. */ -+ __t4_framer_out(wc, unit, FRMR_CMR2, 0x00); -+ -+ if (is_octal(wc)) { -+ /* Set RCLK to 16 MHz */ -+ __t4_framer_out(wc, unit, FRMR_CMR4, 0x5); -+ -+ if (!has_e1_span(wc)) { /* T1/J1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x07); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ if (wc->tspans[unit]->linemode == J1) -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x87); -+ else -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x07); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } else { /* E1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } -+ -+ } else { -+ if (!has_e1_span(wc)) { /* T1/J1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x03); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x84); -+ if (J1 == wc->tspans[unit]->linemode) -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x83); -+ else -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x03); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x84); -+ } else { /* E1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } -+ } -+ -+ /* Configure ports */ -+ -+ /* PC1: SPYR/SPYX input on RPA/XPA */ -+ __t4_framer_out(wc, unit, 0x80, 0x00); -+ -+ /* PC2: RMFB/XSIG output/input on RPB/XPB */ -+ /* PC3: Some unused stuff */ -+ /* PC4: Some more unused stuff */ -+ if (is_octal(wc)) { -+ __t4_framer_out(wc, unit, 0x81, 0xBB); -+ __t4_framer_out(wc, unit, 0x82, 0xf5); -+ __t4_framer_out(wc, unit, 0x83, 0x35); -+ } else if (wc->falc31) { -+ __t4_framer_out(wc, unit, 0x81, 0xBB); -+ __t4_framer_out(wc, unit, 0x82, 0xBB); -+ __t4_framer_out(wc, unit, 0x83, 0xBB); -+ } else { -+ __t4_framer_out(wc, unit, 0x81, 0x22); -+ __t4_framer_out(wc, unit, 0x82, 0x65); -+ __t4_framer_out(wc, unit, 0x83, 0x35); -+ } -+ -+ /* PC5: XMFS active low, SCLKR is input, RCLK is output */ -+ __t4_framer_out(wc, unit, 0x84, 0x01); -+ -+ if (debug & DEBUG_MAIN) { -+ dev_notice(&wc->dev->dev, -+ "Successfully initialized serial bus " -+ "for unit %d\n", unit); -+ } -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ } -+} -+ -+/** -+ * t4_span_assigned - Called when the span is assigned by DAHDI. -+ * @span: Span that has been assigned. -+ * -+ * When this function is called, the span has a valid spanno and all the -+ * channels on the span have valid channel numbers assigned. -+ * -+ * This function is necessary because a device may be registered, and -+ * then user space may then later decide to assign span numbers and the -+ * channel numbers. -+ * -+ */ -+static void t4_span_assigned(struct dahdi_span *span) -+{ -+ struct t4_span *tspan = container_of(span, struct t4_span, span); -+ struct t4 *wc = tspan->owner; -+ struct dahdi_span *pos; -+ unsigned int unassigned_spans = 0; -+ unsigned long flags; -+ -+ /* We use this to make sure all the spans are assigned before -+ * running the serial setup. */ -+ list_for_each_entry(pos, &wc->ddev->spans, device_node) { -+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &pos->flags)) -+ ++unassigned_spans; -+ } -+ -+ if (0 == unassigned_spans) { -+ t4_serial_setup(wc); -+ -+ 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); -+ } -+} -+ -+static void free_wc(struct t4 *wc) -+{ -+ unsigned int x, y; -+ -+ for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) { -+ if (!wc->tspans[x]) -+ continue; -+ for (y = 0; y < ARRAY_SIZE(wc->tspans[x]->chans); y++) { -+ kfree(wc->tspans[x]->chans[y]); -+ kfree(wc->tspans[x]->ec[y]); -+ } -+ kfree(wc->tspans[x]); -+ } -+ -+ kfree(wc->ddev->devicetype); -+ kfree(wc->ddev->location); -+ kfree(wc->ddev->hardware_id); -+ dahdi_free_device(wc->ddev); -+ kfree(wc); -+} -+ -+/** -+ * t4_alloc_channels - Allocate the channels on a span. -+ * @wc: The board we're allocating for. -+ * @ts: The span we're allocating for. -+ * @linemode: Which mode (T1/E1/J1) to use for this span. -+ * -+ * This function must only be called before the span is assigned it's -+ * possible for user processes to have an open reference to the -+ * channels. -+ * -+ */ -+static int t4_alloc_channels(struct t4 *wc, struct t4_span *ts, -+ enum linemode linemode) -+{ -+ int i; -+ -+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &ts->span.flags)) { -+ dev_dbg(&wc->dev->dev, -+ "Cannot allocate channels on a span that is already " -+ "assigned.\n"); -+ return -EINVAL; -+ } -+ -+ /* Cleanup any previously allocated channels. */ -+ for (i = 0; i < ARRAY_SIZE(ts->chans); ++i) { -+ kfree(ts->chans[i]); -+ kfree(ts->ec[i]); -+ ts->chans[i] = NULL; -+ ts->ec[i] = NULL; -+ } -+ -+ ts->linemode = linemode; -+ for (i = 0; i < ((E1 == ts->linemode) ? 31 : 24); i++) { -+ struct dahdi_chan *chan; -+ struct dahdi_echocan_state *ec; -+ -+ chan = kzalloc(sizeof(*chan), GFP_KERNEL); -+ if (!chan) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ ts->chans[i] = chan; -+ -+ ec = kzalloc(sizeof(*ec), GFP_KERNEL); -+ if (!ec) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ ts->ec[i] = ec; -+ } -+ -+ return 0; -+} -+ -+static void t4_init_one_span(struct t4 *wc, struct t4_span *ts) -+{ -+ unsigned long flags; -+ unsigned int reg; -+ int i; -+ if(wc->numspans != 1) { -+ snprintf(ts->span.name, sizeof(ts->span.name) - 1, -+ "ALLO%d/%d/%d", wc->numspans, wc->num, ts->span.offset + 1); -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, -+ "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num, -+ ts->span.offset + 1); -+ } -+ else { -+ snprintf(ts->span.name, sizeof(ts->span.name) - 1, -+ "ALLO4/%d/%d", wc->num, ts->span.offset + 1); //cem:1port change -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1,"T4XXP (PCI) Card %d Span %d", -+ wc->num, ts->span.offset + 1); -+ } -+ switch (ts->linemode) { -+ case T1: -+ ts->span.spantype = SPANTYPE_DIGITAL_T1; -+ break; -+ case E1: -+ ts->span.spantype = SPANTYPE_DIGITAL_E1; -+ break; -+ case J1: -+ ts->span.spantype = SPANTYPE_DIGITAL_J1; -+ break; -+ } -+ -+ /* HDLC Specific init */ -+ ts->sigchan = NULL; -+ ts->sigmode = sigmode; -+ ts->sigactive = 0; -+ -+ if (E1 != ts->linemode) { -+ 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; -+ -+ for (i = 0; i < ts->span.channels; i++) { -+ struct dahdi_chan *const chan = ts->chans[i]; -+ chan->pvt = wc; -+ snprintf(chan->name, sizeof(chan->name) - 1, -+ "%s/%d", ts->span.name, i + 1); -+ t4_chan_set_sigcap(&ts->span, i); -+ chan->chanpos = i + 1; -+ } -+ -+ /* Enable 1sec timer interrupt */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reg = __t4_framer_in(wc, ts->span.offset, FMR1_T); -+ __t4_framer_out(wc, ts->span.offset, FMR1_T, (reg | FMR1_ECM)); -+ -+ /* Enable Errored Second interrupt */ -+ __t4_framer_out(wc, ts->span.offset, ESM, 0); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ t4_reset_counters(&ts->span); -+} -+ -+/** -+ * t4_set_linemode - Allows user space to change the linemode before spans are assigned. -+ * @span: span on which to change the linemode. -+ * @linemode: A value from enumerated spantypes -+ * -+ * This callback is used to override the E1/T1 mode jumper settings and set -+ * the linemode on for each span. Called when the "spantype" attribute -+ * is written in sysfs under the dahdi_device. -+ * -+ */ -+static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ int res = 0; -+ enum linemode mode; -+ const char *old_name; -+ static DEFINE_MUTEX(linemode_lock); -+ unsigned long flags; -+ -+ dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, -+ dahdi_spantype2str(linemode)); -+ -+ if (span->spantype == linemode) -+ return 0; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ wc->reset_required = 1; -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* Do not allow the t1e1 member to be changed by multiple threads. */ -+ mutex_lock(&linemode_lock); -+ old_name = dahdi_spantype2str(span->spantype); -+ switch (linemode) { -+ case SPANTYPE_DIGITAL_T1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to T1 line mode.\n", old_name); -+ mode = T1; -+ wc->t1e1 &= ~(1 << span->offset); -+ break; -+ case SPANTYPE_DIGITAL_E1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to E1 line mode.\n", old_name); -+ mode = E1; -+ wc->t1e1 |= (1 << span->offset); -+ break; -+ case SPANTYPE_DIGITAL_J1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to J1 line mode.\n", old_name); -+ mode = J1; -+ wc->t1e1 &= ~(1 << span->offset); -+ break; -+ default: -+ dev_err(&wc->dev->dev, -+ "Got invalid linemode %d from dahdi\n", linemode); -+ res = -EINVAL; -+ } -+ -+ if (!res) { -+ t4_alloc_channels(wc, ts, mode); -+ t4_init_one_span(wc, ts); -+ dahdi_init_span(span); -+ } -+ -+ mutex_unlock(&linemode_lock); -+ return res; -+} -+ -+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, -+ .assigned = t4_span_assigned, -+ .set_spantype = t4_set_linemode, -+}; -+ -+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, -+ .assigned = t4_span_assigned, -+ .set_spantype = t4_set_linemode, -+#ifdef VPM_SUPPORT -+ .echocan_create = t4_echocan_create, -+ .echocan_name = t4_echocan_name, -+#endif -+}; -+ -+/** -+ * init_spans - Do first initialization on all the spans -+ * @wc: Card to initialize the spans on. -+ * -+ * This function is called *before* the dahdi_device is first registered -+ * with the system. What happens in t4_init_one_span can happen between -+ * when the device is registered and when the spans are assigned via -+ * sysfs (or automatically). -+ * -+ */ -+static void init_spans(struct t4 *wc) -+{ -+ int x, y; -+ int gen2; -+ struct t4_span *ts; -+ unsigned int reg; -+ unsigned long flags; -+ -+ gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN); -+ for (x = 0; x < wc->numspans; x++) { -+ ts = wc->tspans[x]; -+ if(wc->numspans != 1) { -+ sprintf(ts->span.name, "ALLO%d/%d/%d", wc->numspans, wc->num, x + 1); -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, -+ "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num, x+1); -+ } -+ else { -+ sprintf(ts->span.name, "ALLO4/%d/%d", wc->num, x + 1); //cem:1port change -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, -+ "T4XXP (PCI) Card %d Span %d", wc->num, x+1); -+ } -+ switch (ts->linemode) { -+ case T1: -+ ts->span.spantype = SPANTYPE_DIGITAL_T1; -+ break; -+ case E1: -+ ts->span.spantype = SPANTYPE_DIGITAL_E1; -+ break; -+ case J1: -+ ts->span.spantype = SPANTYPE_DIGITAL_J1; -+ break; -+ } -+ -+ /* HDLC Specific init */ -+ ts->sigchan = NULL; -+ ts->sigmode = sigmode; -+ ts->sigactive = 0; -+ -+ if (E1 != ts->linemode) { -+ 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); -+ -+ if (gen2) { -+ ts->span.ops = &t4_gen2_span_ops; -+ } else { -+ ts->span.ops = &t4_gen1_span_ops; -+ } -+ -+ for (y=0;y<wc->tspans[x]->span.channels;y++) { -+ struct dahdi_chan *mychans = ts->chans[y]; -+ sprintf(mychans->name, "ALLO4/%d/%d/%d", wc->num, x + 1, y + 1);//cem:1port change, v002 -+ t4_chan_set_sigcap(&ts->span, x); -+ mychans->pvt = wc; -+ mychans->chanpos = y + 1; -+ } -+ -+ /* Start checking for alarms in 250 ms */ -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(250); -+ -+ /* Enable 1sec timer interrupt */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ t4_reset_counters(&ts->span); -+ -+ } -+ -+ set_span_devicetype(wc); -+ setup_chunks(wc, 0); -+ wc->lastindex = 0; -+} -+ -+static int syncsrc = 0; -+static int syncnum = 0 /* -1 */; -+static int syncspan = 0; -+static DEFINE_SPINLOCK(synclock); -+ -+static void __t4_set_rclk_src(struct t4 *wc, int span) -+{ -+ if (is_octal(wc)) { -+ int cmr5 = 0x00 | (span << 5); -+ int cmr1 = 0x38; /* Clock Mode: RCLK sourced by DCO-R1 -+ by default, Disable Clock-Switching */ -+ -+ __t4_framer_out(wc, 0, 0x44, cmr1); -+ __t4_framer_out(wc, 0, FRMR_CMR5, cmr5); -+ } else { -+ 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); -+} -+ -+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); -+} -+ -+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; /* allo4xxp card number */ -+ int newsyncspan = 0; /* span on given allo4xxp card */ -+ spin_lock_irqsave(&synclock, flags); -+ 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 < cards[x]->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); -+ spin_unlock_irqrestore(&synclock, flags); -+ return 0; -+} -+ -+static void __t4_set_timing_source_auto(struct t4 *wc) -+{ -+ int x, i; -+ 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); -+ } -+ -+ /* Propagate sync selection to dahdi_span struct -+ * this is read by dahdi_tool to display the span's -+ * master/slave sync information */ -+ for (i = 0; i < wc->numspans; i++) { -+ wc->tspans[i]->span.syncsrc = wc->syncsrc + 1; -+ } -+ } -+} -+ -+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; -+ -+ if (is_octal(wc)) -+ fmr1 = 0x9c | 0x02; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */ -+ else -+ 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, FMR5, FMR5_EIBR); /* 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; -+ if (is_octal(wc)) { -+ /* 16 MHz */ -+ fmr1 = 0x44 | 0x02; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ -+ } else { -+ /* 8 MHz */ -+ 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 */ -+ -+ __t4_framer_out(wc, unit, 0x2f, 0x00); -+ __t4_framer_out(wc, unit, 0x30, 0x00); -+ __t4_framer_out(wc, unit, 0x31, 0x00); -+ -+ dev_info(&wc->dev->dev, "ALLO%dXXP: Span %d configured for %s/%s%s\n", -+ wc->numspans, unit + 1, framing, line, crc4); -+} -+ -+/** -+ * t4_check_for_interrupts - Return 0 if the card is generating interrupts. -+ * @wc: The card to check. -+ * -+ * If the card is not generating interrupts, this function will also place all -+ * the spans on the card into red alarm. -+ * -+ */ -+static int t4_check_for_interrupts(struct t4 *wc) -+{ -+ unsigned int starting_intcount = wc->intcount; -+ unsigned long stop_time = jiffies + HZ*2; -+ unsigned long flags; -+ int x; -+ -+ msleep(20); -+ spin_lock_irqsave(&wc->reglock, flags); -+ while (starting_intcount == wc->intcount) { -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ if (time_after(jiffies, stop_time)) { -+ for (x = 0; x < wc->numspans; x++) -+ wc->tspans[x]->span.alarms = DAHDI_ALARM_RED; -+ dev_err(&wc->dev->dev, "Interrupts not detected.\n"); -+ return -EIO; -+ } -+ msleep(100); -+ spin_lock_irqsave(&wc->reglock, flags); -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ return 0; -+} -+ -+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 = container_of(span, struct t4_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, "ALLO%dXXP: Span '%d' isn't us?\n", -+ wc->numspans, 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 (E1 == ts->linemode) -+ __t4_configure_e1(wc, span->offset, span->lineconfig); -+ else -+ __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->devtype->flags & FLAG_5THGEN) -+ __t4_pci_out(wc, 5, (ms_per_irq << 16) | wc->numbufs); -+ else -+ __t4_pci_out(wc, 5, (1 << 16) | 1); -+ /* enable interrupts */ -+ /* Start DMA, enabling DMA interrupts on read only */ -+ wc->dmactrl |= (ts->spanflags & FLAG_2NDGEN) ? 0xc0000000 : 0xc0000003; -+#ifdef VPM_SUPPORT -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+#endif -+ /* Seed interrupt register */ -+ __t4_pci_out(wc, WC_INTR, 0x0c); -+ if (noburst || !(ts->spanflags & FLAG_BURST)) -+ wc->dmactrl |= (1 << 26); -+ else -+ 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); -+ -+ local_irq_save(flags); -+ t4_check_alarms(wc, span->offset); -+ t4_check_sigbits(wc, span->offset); -+ local_irq_restore(flags); -+ if (wc->numspans >= 1) { /*cem:1port change, v002*/ -+ if (wc->tspans[0]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Primary Sync Source\n", -+ span->spanno); -+ } -+ if (wc->tspans[1]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Secondary Sync Source\n", -+ span->spanno); -+ if (wc->numspans >= 4) { -+ if (wc->tspans[2]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Tertiary Sync Source" -+ "\n", span->spanno); -+ if (wc->tspans[3]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Quaternary Sync " -+ "Source\n", span->spanno); -+ } -+ if (wc->numspans == 8) { -+ if (wc->tspans[4]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Quinary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[5]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Senary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[6]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Septenary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[7]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Octonary Sync " -+ "Source\n", span->spanno); -+ } -+ -+ if (!alreadyrunning) { -+ if (t4_check_for_interrupts(wc)) -+ return -EIO; -+ } -+ -+ if (debug) -+ dev_info(&wc->dev->dev, "Completed startup!\n"); -+ clear_bit(T4_IGNORE_LATENCY, &wc->checkflag); -+ return 0; -+} -+ -+static int t4_startup(struct file *file, struct dahdi_span *span) -+{ -+ int ret; -+ struct dahdi_device *const ddev = span->parent; -+ struct dahdi_span *s; -+ -+ ret = _t4_startup(file, span); -+ list_for_each_entry(s, &ddev->spans, device_node) { -+ if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags)) { -+ _t4_startup(file, s); -+ } -+ } -+ return ret; -+} -+ -+#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 = wc->tspans[1]->e1check = 0; -+ if (wc->numspans == 4) -+ wc->tspans[2]->e1check = wc->tspans[3]->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) -+{ -+ unsigned int *readchunk; -+ int dbl = 0; -+ int x,y,z; -+ unsigned int tmp; -+ int offset=0; -+ if (!has_e1_span(wc)) -+ 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 (unlikely(dbl && (debug & DEBUG_MAIN))) -+ dev_notice(&wc->dev->dev, "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]; -+ if (wc->numspans == 4) { -+ wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; -+ wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; -+ } -+ if (wc->numspans == 2) { /*cem:1port change, v002*/ -+ wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; -+ } -+ wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24; -+ } -+ if (has_e1_span(wc)) { -+ if (wc->e1recover > 0) -+ wc->e1recover--; -+ tmp = readchunk[0]; -+ if (wc->numspans == 4) { -+ e1_check(wc, 3, (tmp & 0x7f)); -+ e1_check(wc, 2, (tmp & 0x7f00) >> 8); -+ } -+ if (wc->numspans >=2) //cem:1port change -+ e1_check(wc, 1, (tmp & 0x7f0000) >> 16); -+ e1_check(wc, 0, (tmp & 0x7f000000) >> 24); -+ for (z=24;z<31;z++) { -+ /* Only E1 channels now */ -+ tmp = readchunk[z+1]; -+ if (wc->numspans == 4) { -+ if (wc->tspans[3]->span.channels > 24) -+ wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; -+ if (wc->tspans[2]->span.channels > 24) -+ wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; -+ } -+ if (wc->numspans == 2) {/*cem:1port change, v002*/ -+ if (wc->tspans[1]->span.channels > 24) -+ wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; -+ } -+ 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 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 -+ _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) -+{ -+ u32 *writechunk; -+ int x, y, z; -+ unsigned int tmp; -+ int offset = 0; -+ if (!has_e1_span(wc)) -+ 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[3]->span.chans[z]->writechunk[x]) | -+ (wc->tspans[2]->span.chans[z]->writechunk[x] << 8) | -+ (wc->tspans[1]->span.chans[z]->writechunk[x] << 16) | -+ (wc->tspans[0]->span.chans[z]->writechunk[x] << 24); -+ writechunk[z+offset] = tmp; -+ } -+ if (has_e1_span(wc)) { -+ for (z=24;z<31;z++) { -+ /* Only E1 channels now */ -+ tmp = 0; -+ if (wc->numspans == 4) { -+ if (wc->tspans[3]->span.channels > 24) -+ tmp |= wc->tspans[3]->span.chans[z]->writechunk[x]; -+ if (wc->tspans[2]->span.channels > 24) -+ tmp |= (wc->tspans[2]->span.chans[z]->writechunk[x] << 8); -+ } -+ if (wc->numspans == 2) { /*cem:1port change, v002*/ -+ if (wc->tspans[1]->span.channels > 24) -+ tmp |= (wc->tspans[1]->span.chans[z]->writechunk[x] << 16); -+ } -+ 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_dahdi_rbsbits(struct dahdi_chan *const chan, int rxs) -+{ -+ if ((debug & DEBUG_RBS) && printk_ratelimit()) { -+ const struct t4_span *tspan = container_of(chan->span, -+ struct t4_span, -+ span); -+ const struct t4 *const wc = tspan->owner; -+ dev_notice(&wc->dev->dev, "Detected sigbits change on " \ -+ "channel %s to %04x\n", chan->name, rxs); -+ } -+ dahdi_rbsbits(chan, rxs); -+} -+ -+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 (E1 == ts->linemode) { -+ 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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) { -+ t4_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) { -+ t4_dahdi_rbsbits(ts->span.chans[i], rxs); -+ } -+ } -+ } -+ } -+} -+ -+/* Must be called from within hardirq context. */ -+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]; -+ -+ if (time_before(jiffies, ts->alarmcheck_time)) -+ return; -+ -+ if (!(ts->span.flags & DAHDI_FLAG_RUNNING)) -+ return; -+ -+ spin_lock(&wc->reglock); -+ -+ 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 (E1 == ts->linemode) { -+ 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, -+ "Lost crc4-multiframe alignment\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, -+ "Obtained crc4-multiframe alignment\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)) { -+ dev_notice(&wc->dev->dev, -+ "span %d: Loopup detected,"\ -+ " enabling remote loop\n", -+ span+1); -+ __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)) { -+ dev_notice(&wc->dev->dev, -+ "span %d: Loopdown detected,"\ -+ " disabling remote loop\n", -+ span+1); -+ __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) || -+ dahdi_have_netdev(ts->span.chans[x])) -+ j++; -+ if (!j) -+ alarms |= DAHDI_ALARM_NOTOPEN; -+ } -+ -+ /* Loss of Frame Alignment */ -+ if (c & 0x20) { -+ if (!ts->alarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce LOF/LFA */ -+ dev_info(&wc->dev->dev, "allo%dxxp: LOF/LFA " -+ "detected on span %d but debouncing " -+ "for %d ms\n", wc->numspans, span + 1, -+ alarmdebounce); -+ } -+ ts->alarm_time = jiffies + -+ msecs_to_jiffies(alarmdebounce); -+ } else if (time_after(jiffies, ts->alarm_time)) { -+ /* Disable Slip Interrupts */ -+ e = __t4_framer_in(wc, span, 0x17); -+ __t4_framer_out(wc, span, 0x17, (e|0x03)); -+ -+ alarms |= DAHDI_ALARM_RED; -+ } -+ } else { -+ ts->alarm_time = 0; -+ } -+ -+ /* Loss of Signal */ -+ if (c & 0x80) { -+ if (!ts->losalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce LOS */ -+ dev_info(&wc->dev->dev, "allo%dxxp: LOS " -+ "detected on span %d but debouncing " -+ "for %d ms\n", wc->numspans, -+ span + 1, losalarmdebounce); -+ } -+ ts->losalarm_time = jiffies + -+ msecs_to_jiffies(losalarmdebounce); -+ } else if (time_after(jiffies, ts->losalarm_time)) { -+ /* Disable Slip Interrupts */ -+ e = __t4_framer_in(wc, span, 0x17); -+ __t4_framer_out(wc, span, 0x17, (e|0x03)); -+ -+ alarms |= DAHDI_ALARM_RED; -+ } -+ } else { -+ ts->losalarm_time = 0; -+ } -+ -+ /* Alarm Indication Signal */ -+ if (c & 0x40) { -+ if (!ts->aisalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce AIS */ -+ dev_info(&wc->dev->dev, "allo%dxxp: AIS " -+ "detected on span %d but debouncing " -+ "for %d ms\n", wc->numspans, -+ span + 1, aisalarmdebounce); -+ } -+ ts->aisalarm_time = jiffies + -+ msecs_to_jiffies(aisalarmdebounce); -+ } else if (time_after(jiffies, ts->aisalarm_time)) { -+ alarms |= DAHDI_ALARM_BLUE; -+ } -+ } else { -+ ts->aisalarm_time = 0; -+ } -+ -+ /* 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"); -+ } -+ } -+ -+ 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->yelalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce AIS */ -+ dev_info(&wc->dev->dev, "allo%dxxp: yellow " -+ "(RAI) detected on span %d but " -+ "debouncing for %d ms\n", -+ wc->numspans, span + 1, -+ yelalarmdebounce); -+ } -+ ts->yelalarm_time = jiffies + -+ msecs_to_jiffies(yelalarmdebounce); -+ } else if (time_after(jiffies, ts->yelalarm_time)) { -+ alarms |= DAHDI_ALARM_YELLOW; -+ } -+ } else { -+ ts->yelalarm_time = 0; -+ } -+ -+ if (alarms) -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(100); -+ else -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(50); -+ -+ if (ts->span.mainttimer || ts->span.maintstat) -+ alarms |= DAHDI_ALARM_LOOPBACK; -+ ts->span.alarms = alarms; -+ -+ spin_unlock(&wc->reglock); -+ 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]; -+ -+ spin_lock(&wc->reglock); -+ if (ts->alarmtimer && (0 == (--ts->alarmtimer))) -+ ts->span.alarms &= ~(DAHDI_ALARM_RECOVER); -+ spin_unlock(&wc->reglock); -+ -+ t4_check_alarms(wc, 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->losalarm_time) { -+#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 >= ARRAY_SIZE(altab)) -+ wc->alarmpos = 0; -+ } -+#else -+ if (wc->blinktimer == 480) -+ wc->blinktimer = 0; -+#endif -+} -+ -+static inline void t4_framer_interrupt(struct t4 *wc, int span) -+{ -+ /* Check interrupts for a given span */ -+ unsigned char gis, isr0, isr1, isr2, isr3, isr4; -+ int readsize = -1; -+ struct t4_span *ts = wc->tspans[span]; -+ struct dahdi_chan *sigchan; -+ unsigned long flags; -+ -+ -+ /* 1st gen cards isn't used interrupts */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ } -+ -+ /* 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); -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* Collect errored second counter once per second */ -+ if (isr3 & ISR3_ES) { -+ ts->span.count.errsec += 1; -+ } -+ -+ if (isr0) -+ t4_check_sigbits(wc, span); -+ -+ if (E1 == ts->linemode) { -+ /* 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, "ALLO%d10P: RECEIVE " -+ "slip NEGATIVE on span %d\n", -+ wc->numspans, span + 1); -+ if (isr3 & 0x01) -+ dev_notice(&wc->dev->dev, "ALLO%d10P: RECEIVE " -+ "slip POSITIVE on span %d\n", -+ wc->numspans, span + 1); -+ if (isr4 & 0x80) -+ dev_notice(&wc->dev->dev, "ALLO%dXXP: TRANSMIT " -+ "slip POSITIVE on span %d\n", -+ wc->numspans, span + 1); -+ if (isr4 & 0x40) -+ dev_notice(&wc->dev->dev, "ALLO%d10P: TRANSMIT " -+ "slip NEGATIVE on span %d\n", -+ wc->numspans, 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]; -+ unsigned char rsis_reg = t4_framer_in(wc, span, FRMR_RSIS); -+ -+ ++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); -+ } -+ } 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; -+ -+ /* 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 (status & 0x3) { -+ t4_receiveprep(wc, status); -+ t4_transmitprep(wc, status); -+ } -+ -+ 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); -+} -+ -+DAHDI_IRQ_HANDLER(t4_interrupt) -+{ -+ irqreturn_t ret; -+ unsigned long flags; -+ local_irq_save(flags); -+ ret = _t4_interrupt(irq, dev_id); -+ local_irq_restore(flags); -+ return ret; -+} -+#endif -+ -+static int t4_allocate_buffers(struct t4 *wc, int numbufs, -+ void **oldalloc, dma_addr_t *oldwritedma) -+{ -+ void *alloc; -+ dma_addr_t writedma; -+ -+ /* 32 channels, Double-buffer, Read/Write, 4 spans */ -+ alloc = pci_alloc_consistent(wc->dev, numbufs * T4_BASE_SIZE(wc) * 2, -+ &writedma); -+ -+ if (!alloc) { -+ dev_notice(&wc->dev->dev, "allo%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(wc) * numbufs) / 4; -+ -+ /* Same thing but in bytes... */ -+ wc->readdma = wc->writedma + (T4_BASE_SIZE(wc) * numbufs); -+ -+ wc->numbufs = numbufs; -+ -+ /* Initialize Write/Buffers to all blank data */ -+ memset(wc->writechunk, 0x00, T4_BASE_SIZE(wc) * numbufs); -+ memset(wc->readchunk, 0xff, T4_BASE_SIZE(wc) * numbufs); -+ -+ if (debug) { -+ dev_notice(&wc->dev->dev, "DMA memory base of size %d at " \ -+ "%p. Read: %p and Write %p\n", -+ numbufs * T4_BASE_SIZE(wc) * 2, wc->writechunk, -+ wc->readchunk, wc->writechunk); -+ } -+ -+ return 0; -+} -+ -+static void t4_increase_latency(struct t4 *wc, int newlatency) -+{ -+ unsigned long flags; -+ void *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(wc) * oldbufs * 2, -+ 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)) { -+ /* 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_vpm(wc); -+ } -+ } -+#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->devtype->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) { -+ dev_info(&wc->dev->dev, "Need to increase " -+ "latency. Estimated latency should " -+ "be %d\n", needed_latency); -+ 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; -+ } -+ -+#ifdef DEBUG -+ if (unlikely((wc->intcount < 20))) -+ dev_dbg(&wc->dev->dev, "2G: Got interrupt, status = %08x, " -+ "CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS)); -+#endif -+ -+ 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); -+ if (wc->numspans >= 2) { //cem:1port change -+ if (wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING) -+ t4_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) -+ t4_queue_work(wc->workq, &wc->tspans[2]->swork, 2 % cpus); -+ else -+ atomic_dec(&wc->worklist); -+ if (wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING) -+ t4_queue_work(wc->workq, &wc->tspans[3]->swork, 3 % cpus); -+ else -+ atomic_dec(&wc->worklist); -+ } -+#else -+ unsigned int reg5 = __t4_pci_in(wc, 5); -+ -+#ifdef DEBUG -+ if (wc->intcount < 20) -+ dev_info(&wc->dev->dev, "Reg 5 is %08x\n", reg5); -+#endif -+ -+ if (wc->devtype->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 (is_octal(wc)) { -+ if (cis & FRMR_CIS_GIS5) -+ t4_framer_interrupt(wc, 4); -+ if (cis & FRMR_CIS_GIS6) -+ t4_framer_interrupt(wc, 5); -+ if (cis & FRMR_CIS_GIS7) -+ t4_framer_interrupt(wc, 6); -+ if (cis & FRMR_CIS_GIS8) -+ t4_framer_interrupt(wc, 7); -+ } -+ } -+ -+#ifdef VPM_SUPPORT -+ if (wc->vpm && vpmdtmfsupport) { -+ /* 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); -+ } -+#endif -+ -+ 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); -+} -+ -+DAHDI_IRQ_HANDLER(t4_interrupt_gen2) -+{ -+ irqreturn_t ret; -+ unsigned long flags; -+ local_irq_save(flags); -+ ret = _t4_interrupt_gen2(irq, dev_id); -+ local_irq_restore(flags); -+ return ret; -+} -+ -+#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) ? T4_VPM_PRESENT : 0); -+#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_init(struct t4 *wc) -+{ -+ int laws[8] = { 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; //cem:1port change -+ extern void _binary_dahdi_fw_oct6114_064_bin_size; -+ extern void _binary_dahdi_fw_oct6114_128_bin_size; -+ extern void _binary_dahdi_fw_oct6114_256_bin_size; -+ extern u8 _binary_dahdi_fw_oct6114_032_bin_start[]; //cem:1port change -+ extern u8 _binary_dahdi_fw_oct6114_064_bin_start[]; -+ extern u8 _binary_dahdi_fw_oct6114_128_bin_start[]; -+ extern u8 _binary_dahdi_fw_oct6114_256_bin_start[]; -+#else -+ static const char oct032_firmware[] = "dahdi-fw-oct6114-032.bin"; //cem:1port change -+ static const char oct064_firmware[] = "dahdi-fw-oct6114-064.bin"; -+ static const char oct128_firmware[] = "dahdi-fw-oct6114-128.bin"; -+ static const char oct256_firmware[] = "dahdi-fw-oct6114-256.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); -+ __t4_raw_oct_in(wc, 0x0004); -+ __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; -+ } -+ -+ vpm_capacity = get_vpm450m_capacity(&wc->dev->dev); -+ if (vpm_capacity != wc->numspans * 32) { -+ dev_info(&wc->dev->dev, "Disabling VPMOCT%03d. ALLO%dXXP"\ -+ " requires a VPMOCT%03d", vpm_capacity, -+ wc->numspans, wc->numspans*32); -+ return; -+ } -+ -+ switch (vpm_capacity) { -+ case 32:/*cem:1port change, v002*/ -+#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; -+ case 256: -+#if defined(HOTPLUG_FIRMWARE) -+ if ((request_firmware(&firmware, oct256_firmware, &wc->dev->dev) != 0) || -+ !firmware) { -+ dev_notice(&wc->dev->dev, "VPM450: firmware %s not " -+ "available from userspace\n", oct256_firmware); -+ return; -+ } -+#else -+ embedded_firmware.data = _binary_dahdi_fw_oct6114_256_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_256_bin_size; -+#endif -+ break; -+ default: -+ dev_notice(&wc->dev->dev, "Unsupported channel capacity found " -+ "on VPM module (%d).\n", vpm_capacity); -+ return; -+ } -+ -+ wc->vpm = init_vpm450m(&wc->dev->dev, laws, wc->numspans, firmware); -+ if (!wc->vpm) { -+ 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_info(&wc->dev->dev, "VPM450: hardware DTMF disabled.\n"); -+ vpmdtmfsupport = 0; -+ } -+ -+ dev_info(&wc->dev->dev, "VPM450: Present and operational servicing %d " -+ "span(s)\n", wc->numspans); -+ -+} -+#endif /* VPM_SUPPORT */ -+ -+static void t4_tsi_reset(struct t4 *wc) -+{ -+ int x; -+ if (is_octal(wc)) { -+ for (x = 0; x < 256; x++) { -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= (0x00004000 | ((x & 0x7f) << 7) | ((x >> 7) << 15)); -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } -+ wc->dmactrl &= ~0x0001ffff; -+ } else { -+ 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 (!has_e1_span(wc)) { -+ fromts += 4; -+ tots += 4; -+ } -+ spin_lock_irqsave(&wc->reglock, flags); -+ if (is_octal(wc)) { -+ int fromts_b = fromts & 0x7f; -+ int fromts_t = fromts >> 7; -+ int tots_b = tots & 0x7f; -+ int tots_t = tots >> 7; -+ -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= ((fromts_t << 16) | (tots_t << 15) | 0x00004000 | (tots_b << 7) | (fromts_b)); -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ wc->dmactrl &= ~0x0001ffff; -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } else { -+ 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 (!has_e1_span(wc)) -+ tots += 4; -+ spin_lock_irqsave(&wc->reglock, flags); -+ if (is_octal(wc)) { -+ int tots_b = tots & 0x7f; -+ int tots_t = tots >> 7; -+ -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= ((tots_t << 15) | 0x00004000 | (tots_b << 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 &= ~0x0001ffff; -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } else { -+ 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); -+} -+ -+#ifndef CONFIG_NOEXTENDED_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 -+ -+#define SPI_CS (0) -+#define SPI_CLK (1) -+#define SPI_IO0 (2) -+#define SPI_IO1 (3) -+#define SPI_IO3 (4) -+#define SPI_IO2 (5) -+#define SPI_IN (0) -+#define SPI_OUT (1) -+#define ESPI_REG 13 -+ -+static void t8_clear_bit(struct t4 *wc, int whichb) -+{ -+ wc->st.wrreg &= ~(1 << whichb); -+} -+ -+static void t8_set_bit(struct t4 *wc, int whichb, int val) -+{ -+ t8_clear_bit(wc, whichb); -+ wc->st.wrreg |= (val << whichb); -+} -+ -+static int t8_get_bit(struct t4 *wc, int whichb) -+{ -+ return (wc->st.rdreg >> whichb) & 1; -+} -+ -+static void set_iodir(struct t4 *wc, int whichb, int dir) -+{ -+ whichb += 16; -+ t8_clear_bit(wc, whichb); -+ t8_set_bit(wc, whichb, dir); -+} -+ -+static void write_hwreg(struct t4 *wc) -+{ -+ t4_pci_out(wc, ESPI_REG, wc->st.wrreg); -+} -+ -+static void read_hwreg(struct t4 *wc) -+{ -+ wc->st.rdreg = t4_pci_in(wc, ESPI_REG); -+} -+ -+static void set_cs(struct t4 *wc, int state) -+{ -+ t8_set_bit(wc, SPI_CS, state); -+ write_hwreg(wc); -+} -+ -+static void set_clk(struct t4 *wc, int clk) -+{ -+ t8_set_bit(wc, SPI_CLK, clk); -+ write_hwreg(wc); -+} -+ -+static void clk_bit_out(struct t4 *wc, int val) -+{ -+ t8_set_bit(wc, SPI_IO0, val & 1); -+ set_clk(wc, 0); -+ set_clk(wc, 1); -+} -+ -+static void shift_out(struct t4 *wc, int val) -+{ -+ int i; -+ for (i = 7; i >= 0; i--) -+ clk_bit_out(wc, (val >> i) & 1); -+} -+ -+static int clk_bit_in(struct t4 *wc) -+{ -+ int ret; -+ set_clk(wc, 0); -+ read_hwreg(wc); -+ ret = t8_get_bit(wc, SPI_IO1); -+ set_clk(wc, 1); -+ return ret; -+} -+ -+static int shift_in(struct t4 *wc) -+{ -+ int ret = 0; -+ int i; -+ int bit; -+ -+ for (i = 7; i >= 0; i--) { -+ bit = clk_bit_in(wc); -+ ret |= ((bit & 1) << i); -+ } -+ return ret; -+} -+ -+static void write_enable(struct t4 *wc) -+{ -+ int cmd = 0x06; -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ set_cs(wc, 1); -+} -+ -+static int read_sr1(struct t4 *wc) -+{ -+ int cmd = 0x05; -+ int ret; -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ ret = shift_in(wc); -+ set_cs(wc, 1); -+ return ret; -+} -+ -+static void clear_busy(struct t4 *wc) -+{ -+ static const int SR1_BUSY = (1 << 0); -+ unsigned long stop; -+ -+ stop = jiffies + 2*HZ; -+ while (read_sr1(wc) & SR1_BUSY) { -+ if (time_after(jiffies, stop)) { -+ if (printk_ratelimit()) { -+ dev_err(&wc->dev->dev, -+ "Lockup in %s\n", __func__); -+ } -+ break; -+ } -+ cond_resched(); -+ } -+} -+ -+static void sector_erase(struct t4 *wc, uint32_t addr) -+{ -+ int cmd = 0x20; -+ write_enable(wc); -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ shift_out(wc, (addr >> 16) & 0xff); -+ shift_out(wc, (addr >> 8) & 0xff); -+ shift_out(wc, (addr >> 0) & 0xff); -+ set_cs(wc, 1); -+ clear_busy(wc); -+} -+ -+static void erase_half(struct t4 *wc) -+{ -+ uint32_t addr = 0x00010000; -+ uint32_t primary_firmware = 0x00250000; -+ uint32_t i; -+ -+ if(wc->devtype->flags & FLAG_2PORT | wc->devtype->flags & FLAG_1PORT) -+ primary_firmware = 0x000E0000; -+ dev_info(&wc->dev->dev, "Erasing fpag primary firmware from Address:%x\n",primary_firmware); -+ -+ for (i = addr; i < (addr + primary_firmware); i += 4096) -+ sector_erase(wc, i); -+} -+ -+ -+#define T8_FLASH_PAGE_SIZE 256UL -+ -+static void t8_update_firmware_page(struct t4 *wc, u32 address, -+ const u8 *page_data, size_t size) -+{ -+ int i; -+ -+ write_enable(wc); -+ set_cs(wc, 0); -+ shift_out(wc, 0x02); -+ shift_out(wc, (address >> 16) & 0xff); -+ shift_out(wc, (address >> 8) & 0xff); -+ shift_out(wc, (address >> 0) & 0xff); -+ -+ for (i = 0; i < size; ++i) -+ shift_out(wc, page_data[i]); -+ -+ set_cs(wc, 1); -+ clear_busy(wc); -+} -+ -+static int t8_update_firmware(struct t4 *wc, const struct firmware *fw, -+ const char *t8_firmware) -+{ -+ int res; -+ size_t offset = 0; -+ const u32 BASE_ADDRESS = 0x00010000; -+ const u8 *data, *end; -+ size_t size = 0; -+ -+ /* Erase flash */ -+ erase_half(wc); -+ -+ dev_info(&wc->dev->dev, -+ "Uploading %s. This can take up to 30 seconds.\n", t8_firmware); -+ -+ data = &fw->data[sizeof(struct t8_firm_header)]; -+ end = &fw->data[fw->size]; -+ -+ while (data < end) { -+ /* Calculate the tail end of data that's shorter than a page */ -+ size = min(T8_FLASH_PAGE_SIZE, (unsigned long)(end - data)); -+ -+ t8_update_firmware_page(wc, BASE_ADDRESS + offset, -+ data, size); -+ data += T8_FLASH_PAGE_SIZE; -+ offset += T8_FLASH_PAGE_SIZE; -+ -+ cond_resched(); -+ } -+ -+ /* Reset te820 fpga after loading firmware */ -+#if 0 -+ dev_info(&wc->dev->dev, "Firmware load complete. Reseting device.\n"); -+/*allo:*/ -+ res = pci_save_state(wc->dev); -+ if (res) -+ goto error_exit; -+ /* Set the fpga reset bits and clobber the remainder of the -+ * register, device will be reset anyway */ -+ t4_pci_out(wc, WC_LEDS, 0xe0000000); -+ msleep(1000); -+ -+ pci_restore_state(wc->dev); -+#endif -+ -+ /* Signal the driver to restart initialization. -+ * This will back out all initialization so far and -+ * restart the driver load process */ -+ return -EAGAIN; -+ -+error_exit: -+ return res; -+} -+ -+static char read_flash_byte(struct t4 *wc, unsigned int addr) -+{ -+ int cmd = 0x03; -+ char data; -+ -+ set_cs(wc, 0); -+ -+ shift_out(wc, cmd); -+ -+ shift_out(wc, (addr >> 16) & 0xff); -+ shift_out(wc, (addr >> 8) & 0xff); -+ shift_out(wc, (addr >> 0) & 0xff); -+ -+ data = shift_in(wc) & 0xff; -+ -+ set_cs(wc, 1); -+ -+ return data; -+} -+ -+/** -+ * t8_read_serial - Returns the serial number of the board. -+ * @wc: The board whos serial number we are reading. -+ * -+ * The buffer returned is dynamically allocated and must be kfree'd by the -+ * caller. If memory could not be allocated, NULL is returned. -+ * -+ * Must be called in process context. -+ * -+ */ -+static char *t8_read_serial(struct t4 *wc) -+{ -+ int i; -+ static const int MAX_SERIAL = 16; -+ static const u32 base_addr = 0x00000000; -+ unsigned char c; -+ unsigned char *serial = kzalloc(MAX_SERIAL + 1, GFP_KERNEL); -+ -+ if (!serial) -+ return NULL; -+ -+ for (i = 0; i < MAX_SERIAL; ++i) { -+ c = read_flash_byte(wc, base_addr+i); -+ if ((c >= 'a' && c <= 'z') || -+ (c >= 'A' && c <= 'Z') || -+ (c >= '0' && c <= '9')) -+ serial[i] = c; -+ else -+ break; -+ -+ } -+ -+ if (!i) { -+ kfree(serial); -+ serial = NULL; -+ } -+ -+ return serial; -+} -+ -+ -+static void setup_spi(struct t4 *wc) -+{ -+ wc->st.rdreg = wc->st.wrreg = 0; -+ -+ set_iodir(wc, SPI_IO0, SPI_OUT); -+ set_iodir(wc, SPI_IO1, SPI_IN); -+ set_iodir(wc, SPI_CS, SPI_OUT); -+ set_iodir(wc, SPI_CLK, SPI_OUT); -+ -+ t8_set_bit(wc, SPI_CS, 1); -+ t8_set_bit(wc, SPI_CLK, 1); -+ -+ write_hwreg(wc); -+} -+ -+static int t8_check_firmware(struct t4 *wc, unsigned int version) -+{ -+ int res = 0; -+ u32 crc; -+ const struct t8_firm_header *header; -+ const struct firmware *fw; -+ static const char *t8_firmware; -+ static char t8_firm[128] = "allo-dahdi-fw-2aCP4.bin"; -+ -+ if (is_octal(wc)){ -+ strcpy(t8_firm,"allo-dahdi-fw-2aCP8e.bin"); -+ } -+ else if(wc->devtype->flags & FLAG_2PORT){ -+ strcpy(t8_firm, "allo-dahdi-fw-2aCP2e.bin"); -+ } -+ else if(wc->devtype->flags & FLAG_1PORT){ -+ strcpy(t8_firm, "allo-dahdi-fw-2aCP1e.bin"); -+ } -+ else if (wc->devtype->flags & FLAG_EXPRESS){ -+ strcpy(t8_firm,"allo-dahdi-fw-2aCP4e.bin"); -+ } -+ -+ -+ t8_firmware = (const char *)t8_firm; -+ -+ res = request_firmware(&fw, t8_firmware, &wc->dev->dev); -+ if (res) { -+ dev_info(&wc->dev->dev, "firmware %s not " -+ "available from userspace\n", t8_firmware); -+ goto cleanup; -+ } -+ -+ header = (const struct t8_firm_header *)fw->data; -+ -+/* Check the crc before anything else */ -+ crc = crc32(~0, &fw->data[10], fw->size - 10) ^ ~0; -+ if (memcmp("CEMBLR", header->header, sizeof(header->header)) || -+ (le32_to_cpu(header->chksum) != crc)) { -+ dev_info(&wc->dev->dev, -+ "%s is invalid. Please reinstall.:%08X %08X\n", t8_firmware, le32_to_cpu(header->chksum), crc); -+ goto cleanup; -+ } -+ -+ /* Spi struct must be setup before any access to flash memory */ -+ setup_spi(wc); -+ -+ /* Check the two firmware versions */ -+ if (le32_to_cpu(header->version) == version) -+ goto cleanup; -+ -+ dev_info(&wc->dev->dev, "%s Version: %08x available for flash\n", -+ t8_firmware, header->version); -+ -+ res = t8_update_firmware(wc, fw, t8_firmware); -+ if (res && res != -EAGAIN) { -+ dev_info(&wc->dev->dev, "Failed to load firmware %s\n", -+ t8_firmware); -+ } -+/*allo:*/ -+#if 1 -+ release_firmware(fw); -+ return 0; -+#endif -+cleanup: -+ release_firmware(fw); -+ return res; -+} -+ -+static int -+__t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, bool first_time) -+{ -+ unsigned int version; -+ int res; -+ -+ version = t4_pci_in(wc, WC_VERSION); -+ if (is_octal(wc) && first_time) { -+ dev_info(&wc->dev->dev, "Firmware Version: %01x.%02x\n", -+ (version & 0xf00) >> 8, -+ version & 0xff); -+ } else if (first_time) { -+ dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version); -+ } -+ if (debug) { -+ 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 -+ } -+ -+ /* Check the field updatable firmware for the wcte820 */ -+ res = t8_check_firmware(wc, version); -+ if (res) -+ return res; -+ wc->ddev->hardware_id = t8_read_serial(wc); -+ -+#if defined(CONFIG_FORCE_EXTENDED_RESET) -+ t4_extended_reset(wc); -+#elif !defined(CONFIG_NOEXTENDED_RESET) -+ if (wc->devtype->flags & FLAG_EXPRESS) -+ 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 (first_time) { -+ if (!strcasecmp("auto", default_linemode)) { -+ if (-1 == t1e1override) { -+ wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & -+ 0x0f00) >> 8); -+ wc->t1e1 &= 0xf; -+ if (is_octal(wc)) { -+ wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) & -+ 0x0f00) >> 4; -+ } -+ } else { -+ dev_warn(&wc->dev->dev, -+ "'t1e1override' is deprecated. Please use 'default_linemode'.\n"); -+ wc->t1e1 = t1e1override & 0xf; -+ } -+ } else if (!strcasecmp("t1", default_linemode)) { -+ wc->t1e1 = 0; -+ } else if (!strcasecmp("e1", default_linemode)) { -+ wc->t1e1 = 0xff; -+ } else if (!strcasecmp("j1", default_linemode)) { -+ wc->t1e1 = 0; -+ j1mode = 1; -+ } else { -+ dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n", -+ default_linemode); -+ wc->t1e1 = 0; -+ } -+ } -+ -+ wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28; -+ order_index[wc->order]++; -+ -+ /* TE820 Auth Check */ -+ if (is_octal(wc)) { -+ unsigned long stop = jiffies + HZ; -+ uint32_t donebit; -+ -+ t4_pci_out(wc, WC_LEDS2, WC_SET_AUTH); -+ donebit = t4_pci_in(wc, WC_LEDS2); -+ while (!(donebit & WC_GET_AUTH)) { -+ if (time_after(jiffies, stop)) { -+ /* Encryption check failed, stop operation */ -+ dev_info(&wc->dev->dev, -+ "Failed encryption check. " -+ "Unloading driver.\n"); -+ return -EIO; -+ } -+ msleep(20); -+ donebit = t4_pci_in(wc, WC_LEDS2); -+ } -+ } -+ -+ return 0; -+} -+ -+static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags) -+{ -+ return __t4_hardware_init_1(wc, cardflags, true); -+} -+ -+static int __t4_hardware_init_2(struct t4 *wc, bool first_time) -+{ -+ int x; -+ unsigned int regval; -+ unsigned long flags; -+ -+ if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) { -+ wc->tspans[0]->spanflags |= FLAG_OCTOPT; -+ } -+ /* Setup LEDS, take out of reset */ -+ t4_pci_out(wc, WC_LEDS, 0x000000ff); -+ udelay(100); -+ t4_activate(wc); -+ udelay(100); -+ -+ /* In order to find out the QFALC framer version, we have to -+ * temporarily turn off compat mode and take a peak at VSTR. We turn -+ * compat back on when we are done. -+ * -+ */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ regval = __t4_framer_in(wc, 0, 0xd6); -+ if (is_octal(wc)) -+ regval |= (1 << 4); /* SSI16 - For 16 MHz multiplex mode with comp = 1 */ -+ else -+ regval |= (1 << 5); /* set COMP_DIS*/ -+ -+ __t4_framer_out(wc, 0, 0xd6, regval); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (!is_octal(wc)) { -+ regval = t4_framer_in(wc, 0, 0x4a); -+ if (first_time && regval == 0x05) { -+ dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or " -+ "earlier\n"); -+ } else if (regval == 0x20) { -+ if (first_time) -+ dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n"); -+ wc->falc31 = 1; -+ } else if (first_time) { -+ dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " -+ "(VSTR = 0x%02x)\n", regval); -+ } -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (debug) { -+ 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)); -+ } -+ } -+ -+ 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)); -+ -+ return 0; -+} -+ -+static int t4_hardware_init_2(struct t4 *wc) -+{ -+ return __t4_hardware_init_2(wc, true); -+} -+ -+static int __devinit t4_launch(struct t4 *wc) -+{ -+ int x; -+ int res; -+ -+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) -+ return 0; -+ -+ if (debug) { -+ dev_info(&wc->dev->dev, -+ "ALLO%dXXP: Launching card: %d\n", wc->numspans, -+ wc->order); -+ } -+ -+ wc->ddev->manufacturer = "Allo"; -+ if (!ignore_rotary && (1 == order_index[wc->order])) { -+ wc->ddev->location = kasprintf(GFP_KERNEL, -+ "Board ID Switch %d", wc->order); -+ } else { -+ bool express = ((wc->tspans[0]->spanflags & FLAG_EXPRESS) > 0); -+ wc->ddev->location = kasprintf(GFP_KERNEL, -+ "PCI%s Bus %02d Slot %02d", -+ (express) ? " Express" : "", -+ wc->dev->bus->number, -+ PCI_SLOT(wc->dev->devfn) + 1); -+ } -+ -+ if (!wc->ddev->location) -+ return -ENOMEM; -+ -+ for (x = 0; x < wc->numspans; ++x) { -+ list_add_tail(&wc->tspans[x]->span.device_node, -+ &wc->ddev->spans); -+ } -+ -+ tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc); -+ -+ res = dahdi_register_device(wc->ddev, &wc->dev->dev); -+ if (res) { -+ dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n"); -+ return res; -+ } -+ -+ return 0; -+} -+ -+/** -+ * allo4xxp_sort_cards - Sort the cards in card array by rotary switch settings. -+ * -+ */ -+static void allo4xxp_sort_cards(void) -+{ -+ int x; -+ -+ /* 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; -+ } -+ } -+} -+ -+static int __devinit -+t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ struct t4 *wc; -+ unsigned int x; -+ int init_latency; -+ -+ if (pci_enable_device(pdev)) { -+ return -EIO; -+ } -+ -+ wc = kzalloc(sizeof(*wc), GFP_KERNEL); -+ if (!wc) -+ return -ENOMEM; -+ -+ wc->ddev = dahdi_create_device(); -+ if (!wc->ddev) { -+ kfree(wc); -+ return -ENOMEM; -+ } -+ -+ spin_lock_init(&wc->reglock); -+ wc->devtype = (const struct devtype *)(ent->driver_data); -+ -+#ifdef CONFIG_WCT4XXP_DISABLE_ASPM -+ if (is_pcie(wc)) { -+ pci_disable_link_state(pdev->bus->self, PCIE_LINK_STATE_L0S | -+ PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); -+ }; -+#endif -+ -+ if (is_octal(wc)) -+ wc->numspans = 8; -+ else if (wc->devtype->flags & FLAG_2PORT) -+ wc->numspans = 2; -+ else if (wc->devtype->flags & FLAG_1PORT)/*cem:1port change, v002*/ -+ wc->numspans = 1; -+ else -+ wc->numspans = 4; -+ -+ wc->membase = pci_iomap(pdev, 0, 0); -+ /* This rids of the Double missed interrupt message after loading */ -+ wc->last0 = 1; -+ if (pci_request_regions(pdev, wc->devtype->desc)) -+ dev_info(&pdev->dev, "allo%dxxp: Unable to request regions\n", -+ wc->numspans); -+ -+ if (debug) -+ dev_info(&pdev->dev, "Found ALLO%dXXP\n", wc->numspans); -+ -+ wc->dev = pdev; -+ -+ /* Enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Keep track of which device we are */ -+ pci_set_drvdata(pdev, wc); -+ -+ if (wc->devtype->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; -+ } -+/*ALLO:*/ -+ dev_info(&wc->dev->dev, "2nd gen card with initial latency of " -+ "%d and %d ms per IRQ\n", init_latency, ms_per_irq); -+ } else { -+ if (wc->devtype->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 */ -+ res = t4_hardware_init_1(wc, wc->devtype->flags); -+ if (res) { -+ /* If this function returns -EAGAIN, we expect -+ * to attempt another driver load. Clean everything -+ * up first */ -+ pci_iounmap(wc->dev, wc->membase); -+ pci_release_regions(wc->dev); -+ pci_free_consistent(wc->dev, T4_BASE_SIZE(wc) * wc->numbufs * 2, -+ wc->writechunk, wc->writedma); -+ pci_set_drvdata(wc->dev, NULL); -+ free_wc(wc); -+ return res; -+ } -+ -+ 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->devtype->flags & FLAG_2NDGEN) { -+ char tmp[20]; -+ -+ sprintf(tmp, "te%dxxp[%d]", wc->numspans, wc->num); -+ wc->workq = create_workqueue(tmp); -+ } -+#endif -+ -+ /* Allocate pieces we need here */ -+ for (x = 0; x < ports_on_framer(wc); x++) { -+ struct t4_span *ts; -+ enum linemode linemode; -+ -+ ts = kzalloc(sizeof(*ts), GFP_KERNEL); -+ if (!ts) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ wc->tspans[x] = ts; -+ -+#ifdef ENABLE_WORKQUEUES -+ INIT_WORK(&ts->swork, workq_handlespan, ts); -+#endif -+ ts->spanflags |= wc->devtype->flags; -+ linemode = (wc->t1e1 & (1 << x)) ? E1 : ((j1mode) ? J1 : T1); -+ t4_alloc_channels(wc, wc->tspans[x], linemode); -+ } -+ -+ /* Continue hardware intiialization */ -+ t4_hardware_init_2(wc); -+ -+#ifdef SUPPORT_GEN1 -+ if (request_irq(pdev->irq, (wc->devtype->flags & FLAG_2NDGEN) ? -+ t4_interrupt_gen2 : t4_interrupt, -+ DAHDI_IRQ_SHARED, -+ (wc->numspans == 8) ? "allo8xxp" : -+ (wc->numspans == 2) ? "allo2xxp" : -+ (wc->numspans == 1)? "allo1xxp" : -+ "allo4xxp", -+ wc)) { -+#else -+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) { -+ dev_notice(&wc->dev->dev, "This driver does not " -+ "support 1st gen modules\n"); -+ free_wc(wc); -+ return -ENODEV; -+ } -+ -+ if (request_irq(pdev->irq, t4_interrupt_gen2, -+ DAHDI_IRQ_SHARED, "t4xxp", wc)) { -+#endif -+ dev_notice(&wc->dev->dev, "Unable to request IRQ %d\n", -+ pdev->irq); -+ free_wc(wc); -+ return -EIO; -+ } -+ -+ init_spans(wc); -+ -+ if (!ignore_rotary) -+ allo4xxp_sort_cards(); -+ -+ if (wc->ddev->hardware_id) { -+ dev_info(&wc->dev->dev, -+ "Found a Allocard: %s (SN: %s)\n", wc->devtype->desc, -+ wc->ddev->hardware_id); -+ } else { -+ dev_info(&wc->dev->dev, -+ "Found a Allocard: %s\n", wc->devtype->desc); -+ } -+ -+#ifdef VPM_SUPPORT -+ if (!wc->vpm) { -+ t4_vpm_init(wc); -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ if (wc->vpm) -+ set_span_devicetype(wc); -+ } -+#endif -+ -+ create_sysfs_files(wc); -+ -+ res = 0; -+ if (ignore_rotary) -+ res = t4_launch(wc); -+ -+ return res; -+} -+ -+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); -+ -+ if (debug) { -+ dev_notice(&wc->dev->dev, "Stopped ALLO%dXXP, Turned off DMA\n", -+ wc->numspans); -+ } -+ return 0; -+} -+ -+static int __devinit -+t4_init_one_retry(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ res = t4_init_one(pdev, ent); -+ -+ /* If the driver was reset by a firmware load, -+ * try to load once again */ -+ if (-EAGAIN == res) { -+ res = t4_init_one(pdev, ent); -+ if (-EAGAIN == res) { -+ dev_err(&pdev->dev, "Failed to update firmware.\n"); -+ res = -EIO; -+ } -+ } -+ -+ return res; -+} -+ -+static void _t4_remove_one(struct t4 *wc) -+{ -+ int basesize; -+ -+ if (!wc) -+ return; -+ -+ dahdi_unregister_device(wc->ddev); -+ -+ remove_sysfs_files(wc); -+ -+ /* Stop hardware */ -+ t4_hardware_stop(wc); -+ -+#ifdef VPM_SUPPORT -+ /* Release vpm */ -+ if (wc->vpm) -+ release_vpm450m(wc->vpm); -+ wc->vpm = NULL; -+#endif -+ /* Unregister spans */ -+ -+ basesize = DAHDI_MAX_CHUNKSIZE * 32 * 4; -+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) -+ basesize = basesize * 2; -+ -+#ifdef ENABLE_WORKQUEUES -+ if (wc->workq) { -+ flush_workqueue(wc->workq); -+ destroy_workqueue(wc->workq); -+ } -+#endif -+ -+ free_irq(wc->dev->irq, wc); -+ -+ if (wc->membase) -+ pci_iounmap(wc->dev, wc->membase); -+ -+ pci_release_regions(wc->dev); -+ -+ /* Immediately free resources */ -+ pci_free_consistent(wc->dev, T4_BASE_SIZE(wc) * wc->numbufs * 2, -+ wc->writechunk, wc->writedma); -+ -+ order_index[wc->order]--; -+ -+ cards[wc->num] = NULL; -+ pci_set_drvdata(wc->dev, NULL); -+ free_wc(wc); -+} -+ -+static void __devexit t4_remove_one(struct pci_dev *pdev) -+{ -+ struct t4 *wc = pci_get_drvdata(pdev); -+ if (!wc) -+ return; -+ -+ _t4_remove_one(wc); -+} -+ -+ -+static DEFINE_PCI_DEVICE_TABLE(t4_pci_tbl) = -+{ -+ -+/*ALLO:*/ -+ { 0x1d21, 0x1280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&allo1280p2 }, -+ { 0x1d21, 0x1240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&allo1240p2 }, -+ { 0x1d21, 0x1241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&allo1241p2 }, -+ { 0x1d21, 0x1220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&allo1220p2 }, -+ { 0x1d21, 0x1210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&allo1210p2 }, -+ { 0, } -+}; -+ -+static void _t4_shutdown(struct pci_dev *pdev) -+{ -+ struct t4 *wc = pci_get_drvdata(pdev); -+ t4_hardware_stop(wc); -+} -+ -+static int t4_suspend(struct pci_dev *pdev, pm_message_t state) -+{ -+ return -ENOSYS; -+} -+ -+static struct pci_driver t4_driver = { -+ .name = "allo4xxp", -+ .probe = t4_init_one_retry, -+ .remove = __devexit_p(t4_remove_one), -+ .shutdown = _t4_shutdown, -+ .suspend = t4_suspend, -+ .id_table = t4_pci_tbl, -+}; -+ -+static int __init t4_init(void) -+{ -+ int i; -+ int res; -+ -+ if (-1 != t1e1override) { -+ pr_info("'t1e1override' module parameter is deprecated. " -+ "Please use 'default_linemode' instead.\n"); -+ } -+ -+ res = dahdi_pci_module(&t4_driver); -+ if (res) -+ return -ENODEV; -+ -+ /* If we're ignoring the rotary switch settings, then we've already -+ * registered in the context of .probe */ -+ if (!ignore_rotary) { -+ -+ /* 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 "allo4xxp: Ident of first card is not zero (%d)\n", -+ cards[0]->order); -+ } -+ -+ for (i = 0; cards[i]; i++) { -+ /* warn the user of duplicate ident values it is -+ * probably unintended */ -+ if (debug && res < 15 && cards[i+1] && -+ cards[res]->order == cards[i+1]->order) { -+ printk(KERN_NOTICE "allo4xxp: Duplicate ident " -+ "value found (%d)\n", cards[i]->order); -+ } -+ res = t4_launch(cards[i]); -+ if (res) { -+ int j; -+ for (j = 0; j < i; ++j) -+ _t4_remove_one(cards[j]); -+ break; -+ } -+ } -+ } -+ return res; -+} -+ -+static void __exit t4_cleanup(void) -+{ -+ pci_unregister_driver(&t4_driver); -+} -+ -+MODULE_AUTHOR("Allo Incorporated <support@allo.com>"); -+MODULE_DESCRIPTION("Wildcard Dual/Quad/Octal-port Digital Card Driver"); -+MODULE_ALIAS("allo2xxp"); -+MODULE_LICENSE("GPL v2"); -+ -+module_param(debug, int, 0600); -+module_param(noburst, int, 0600); -+module_param(timingcable, int, 0600); -+module_param(t1e1override, int, 0400); -+module_param(default_linemode, charp, S_IRUGO); -+MODULE_PARM_DESC(default_linemode, "\"auto\"(default), \"e1\", \"t1\", " -+ "or \"j1\". \"auto\" will use the value from any hardware " -+ "jumpers."); -+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); -+module_param(ignore_rotary, int, 0400); -+MODULE_PARM_DESC(ignore_rotary, "Set to > 0 to ignore the rotary switch when " \ -+ "registering with DAHDI."); -+ -+#ifdef VPM_SUPPORT -+module_param(vpmsupport, int, 0600); -+module_param(vpmdtmfsupport, int, 0600); -+#endif -+ -+MODULE_DEVICE_TABLE(pci, t4_pci_tbl); -+ -+module_init(t4_init); -+module_exit(t4_cleanup); -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/vpm450m.c dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/vpm450m.c ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/vpm450m.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/vpm450m.c 2015-02-10 15:01:15.889462151 +0100 -@@ -0,0 +1,624 @@ -+/* -+ * Copyright (C) 2005-2012 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. -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/string.h> -+#include <linux/time.h> -+#include <linux/version.h> -+ -+#include <dahdi/kernel.h> -+#include <stdbool.h> -+ -+#include "vpm450m.h" -+#include <oct612x.h> -+ -+static int wct4xxp_oct612x_write(struct oct612x_context *context, -+ u32 address, u16 value) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ oct_set_reg(wc, address, value); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_read(struct oct612x_context *context, u32 address, -+ u16 *value) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ *value = (u16)oct_get_reg(wc, address); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_write_smear(struct oct612x_context *context, -+ u32 address, u16 value, size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ oct_set_reg(wc, address + (i << 1), value); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_write_burst(struct oct612x_context *context, -+ u32 address, const u16 *buffer, -+ size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ oct_set_reg(wc, address + (i << 1), buffer[i]); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_read_burst(struct oct612x_context *context, -+ u32 address, u16 *buffer, size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ buffer[i] = oct_get_reg(wc, address + (i << 1)); -+ return 0; -+} -+ -+static const struct oct612x_ops wct4xxp_oct612x_ops = { -+ .write = wct4xxp_oct612x_write, -+ .read = wct4xxp_oct612x_read, -+ .write_smear = wct4xxp_oct612x_write_smear, -+ .write_burst = wct4xxp_oct612x_write_burst, -+ .read_burst = wct4xxp_oct612x_read_burst, -+}; -+ -+#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; -+ struct oct612x_context context; -+ UINT32 aulEchoChanHndl[256]; -+ int chanflags[256]; -+ int ecmode[256]; -+ int numchans; -+}; -+ -+#define FLAG_DTMF (1 << 0) -+#define FLAG_MUTE (1 << 1) -+#define FLAG_ECHO (1 << 2) -+#define FLAG_ALAW (1 << 3) -+ -+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, -+}; -+ -+void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, int channel, -+ bool alaw) -+{ -+ tOCT6100_CHANNEL_MODIFY *modify; -+ UINT32 ulResult; -+ UINT32 law_to_use = (alaw) ? cOCT6100_PCM_A_LAW : -+ cOCT6100_PCM_U_LAW; -+ -+ if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ /* If we're already in this companding mode, no need to do anything. */ -+ if (alaw == ((vpm450m->chanflags[channel] & FLAG_ALAW) > 0)) -+ return; -+ -+ modify = kzalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); -+ if (!modify) { -+ pr_notice("Unable to allocate memory for setec!\n"); -+ return; -+ } -+ -+ Oct6100ChannelModifyDef(modify); -+ modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel]; -+ modify->fTdmConfigModified = TRUE; -+ modify->TdmConfig.ulSinPcmLaw = law_to_use; -+ modify->TdmConfig.ulRinPcmLaw = law_to_use; -+ modify->TdmConfig.ulSoutPcmLaw = law_to_use; -+ modify->TdmConfig.ulRoutPcmLaw = law_to_use; -+ ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify); -+ if (ulResult != GENERIC_OK) { -+ pr_notice("Failed to apply echo can changes on channel %d %d %08x!\n", -+ vpm450m->aulEchoChanHndl[channel], channel, ulResult); -+ } else { -+ if (debug) { -+ pr_info("Changed companding on channel %d to %s.\n", -+ channel, (alaw) ? "alaw" : "ulaw"); -+ } -+ if (alaw) -+ vpm450m->chanflags[channel] |= FLAG_ALAW; -+ else -+ vpm450m->chanflags[channel] &= ~(FLAG_ALAW); -+ } -+ kfree(modify); -+} -+ -+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 "wct4xxp: 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 %08x!\n", channel, ulResult); -+ } 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; -+ -+ if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ -+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL); -+ if (!modify) { -+ printk(KERN_NOTICE "wct4xxp: 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 (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ -+ 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; -+ -+ Oct6100EventGetToneDef(&tonesearch); -+ tonesearch.pToneEvent = &tonefound; -+ tonesearch.ulMaxToneEvent = 1; -+ 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(struct device *device) -+{ -+ struct oct612x_context context; -+ UINT32 ulResult; -+ -+ tOCT6100_API_GET_CAPACITY_PINS CapacityPins; -+ -+ context.dev = device; -+ context.ops = &wct4xxp_oct612x_ops; -+ -+ Oct6100ApiGetCapacityPinsDef(&CapacityPins); -+ CapacityPins.pProcessContext = &context; -+ 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(struct device *device, int *isalaw, -+ int numspans, const struct firmware *firmware) -+{ -+ tOCT6100_CHIP_OPEN *ChipOpen; -+ tOCT6100_GET_INSTANCE_SIZE InstanceSize; -+ tOCT6100_CHANNEL_OPEN *ChannelOpen; -+ UINT32 ulResult; -+ const unsigned int mask = (8 == numspans) ? 0x7 : 0x3; -+ unsigned int sout_stream, rout_stream; -+ struct vpm450m *vpm450m; -+ int x,y,law; -+ -+ if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL))) -+ return NULL; -+ -+ memset(vpm450m, 0, sizeof(struct vpm450m)); -+ vpm450m->context.dev = device; -+ vpm450m->context.ops = &wct4xxp_oct612x_ops; -+ -+ 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 < ARRAY_SIZE(vpm450m->ecmode); 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 = &vpm450m->context; -+ -+ 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->aulTdmStreamFreqs[0] = cOCT6100_TDM_STREAM_FREQ_8MHZ; -+ ChipOpen->ulMaxFlexibleConfParticipants = 0; -+ ChipOpen->ulMaxConfBridges = 0; -+ ChipOpen->ulMaxRemoteDebugSessions = 0; -+ ChipOpen->fEnableChannelRecording = FALSE; -+ ChipOpen->ulSoftToneEventsBufSize = 64; -+ -+ if (vpm450m->numchans <= 128) { -+ ChipOpen->ulMaxTdmStreams = 4; -+ ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE; -+ } else { -+ ChipOpen->ulMaxTdmStreams = 32; -+ ChipOpen->fEnableFastH100Mode = TRUE; -+ ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_RISING_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; -+ } -+ -+ ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen); -+ if (ulResult != cOCT6100_ERR_OK) { -+ printk(KERN_NOTICE "Failed to open chip, code %08x!\n", ulResult); -+ vfree(vpm450m->pApiInstance); -+ kfree(vpm450m); -+ kfree(ChipOpen); -+ kfree(ChannelOpen); -+ return NULL; -+ } -+ -+ sout_stream = (8 == numspans) ? 29 : 2; -+ rout_stream = (8 == numspans) ? 24 : 3; -+ -+ for (x = 0; x < ((8 == numspans) ? 256 : 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 (( numspans > 2) || ((x & 0x03) <numspans)) { /*allo: 1port support*/ -+ /* span timeslots are interleaved 12341234... -+ * therefore, the lower 2 bits tell us which span this -+ * timeslot/channel -+ */ -+ if (isalaw[x & mask]) { -+ law = cOCT6100_PCM_A_LAW; -+ vpm450m->chanflags[x] |= FLAG_ALAW; -+ } else { -+ law = cOCT6100_PCM_U_LAW; -+ vpm450m->chanflags[x] &= ~(FLAG_ALAW); -+ } -+ 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 = sout_stream; -+ ChannelOpen->TdmConfig.ulSoutTimeslot = x; -+#if 1 -+ ChannelOpen->TdmConfig.ulRoutPcmLaw = law; -+ ChannelOpen->TdmConfig.ulRoutStream = rout_stream; -+ ChannelOpen->TdmConfig.ulRoutTimeslot = x; -+#endif -+ 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 %x!\n", x, ulResult); -+ continue; -+ } -+ for (y = 0; y < ARRAY_SIZE(tones); 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); -+ } -+ } -+ } -+ -+ 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 -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/vpm450m.h dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/vpm450m.h ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/vpm450m.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/vpm450m.h 2015-02-10 15:01:15.889462151 +0100 -@@ -0,0 +1,49 @@ -+/* -+ * 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 t4; -+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(struct device *device, int *isalaw, -+ int numspans, const struct firmware *firmware); -+unsigned int get_vpm450m_capacity(struct device *device); -+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); -+void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, -+ int channel, bool alaw); -+ -+extern int debug; -+ -+#endif -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/wct4xxp-diag.c dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/wct4xxp-diag.c ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/wct4xxp-diag.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/wct4xxp-diag.c 2015-02-10 15:01:15.892795252 +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 "wct4xxp.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: wct4xxp-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 -Nur dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/wct4xxp.h dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/wct4xxp.h ---- dahdi-linux-2.10.0.1/drivers/dahdi/allo4xxp/wct4xxp.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/allo4xxp/wct4xxp.h 2015-02-10 15:01:15.892795252 +0100 -@@ -0,0 +1,144 @@ -+/* -+ * Wildcard T400P FXS Interface Driver for DAHDI Telephony interface -+ * -+ * Written by Mark Spencer <markster@linux-support.net> -+ * -+ * 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/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 -+/* OctalFALC Only */ -+#define FRMR_CMR4 0x41 -+#define FRMR_CMR5 0x42 -+#define FRMR_CMR6 0x43 -+#define FRMR_GPC2 0x8a -+/* End Octal */ -+#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 -+ -+/* CIS - Octal falc bits */ -+#define FRMR_CIS_GIS5 0x10 -+#define FRMR_CIS_GIS6 0x20 -+#define FRMR_CIS_GIS7 0x40 -+#define FRMR_CIS_GIS8 0x80 -+ -+#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]; -+}; -+ -+struct t4_reg { -+ unsigned int reg; -+ unsigned int val; -+}; -+ -+#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) -+#define WCT4_GET_REG _IOW(DAHDI_CODE, 61, struct t4_reg) -+#define WCT4_SET_REG _IOW(DAHDI_CODE, 62, struct t4_reg) -+ -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/firmware/Makefile dahdi-linux-2.10.0.1-allo/drivers/dahdi/firmware/Makefile ---- dahdi-linux-2.10.0.1/drivers/dahdi/firmware/Makefile 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-allo/drivers/dahdi/firmware/Makefile 2015-02-10 15:01:15.892795252 +0100 -@@ -41,10 +41,11 @@ - A4B_VERSION:=b0019 - - FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases -+FIRMWARE_URL_ALLO:=http://www.allo.com/firmware/pri-card-second-gen - - ALL_FIRMWARE=FIRMWARE-OCT6114-032 FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256 - ALL_FIRMWARE+=FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 FIRMWARE-TE820 FIRMWARE-TE133 FIRMWARE-TE134 --ALL_FIRMWARE+=FIRMWARE-A8A FIRMWARE-A8B FIRMWARE-A4A FIRMWARE-A4B FIRMWARE-TE435 FIRMWARE-TE436 -+ALL_FIRMWARE+=FIRMWARE-A8A FIRMWARE-A8B FIRMWARE-A4A FIRMWARE-A4B FIRMWARE-TE435 FIRMWARE-TE436 FIRMWARE-allo-1PPCIe FIRMWARE-allo-2PPCIe FIRMWARE-allo-4PPCI FIRMWARE-allo-4PPCIe FIRMWARE-allo-8PPCIe - - # Firmware files should use the naming convention: dahdi-fw-<base name>-<sub name>-<version> or dahdi-fw-<base name>-<version> - # First example: dahdi-fw-oct6114-064-1.05.01 -@@ -69,6 +70,12 @@ - FIRMWARE:=$(FIRMWARE:FIRMWARE-A8B=dahdi-fw-a8a-$(A8A_VERSION).tar.gz) - FIRMWARE:=$(FIRMWARE:FIRMWARE-A4A=dahdi-fw-a4b-$(A4B_VERSION).tar.gz) - FIRMWARE:=$(FIRMWARE:FIRMWARE-A4B=dahdi-fw-a4a-$(A4A_VERSION).tar.gz) -+FIRMWARE:=$(FIRMWARE:FIRMWARE-allo-1PPCIe=allo-dahdi-fw-2aCP1e.tar.gz) -+FIRMWARE:=$(FIRMWARE:FIRMWARE-allo-2PPCIe=allo-dahdi-fw-2aCP2e.tar.gz) -+FIRMWARE:=$(FIRMWARE:FIRMWARE-allo-4PPCI=allo-dahdi-fw-2aCP4.tar.gz) -+FIRMWARE:=$(FIRMWARE:FIRMWARE-allo-4PPCIe=allo-dahdi-fw-2aCP4e.tar.gz) -+FIRMWARE:=$(FIRMWARE:FIRMWARE-allo-8PPCIe=allo-dahdi-fw-2aCP8e.tar.gz) -+ - - FWLOADERS:=dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz - -@@ -100,6 +107,9 @@ - rm -f dahdi-fw-*.tar.gz - rm -f dahdi-fwload-*.tar.gz - rm -f make_firmware_object -+ rm -f allo-dahdi-fw-*.bin -+ rm -f allo-dahdi-fw-*.tar.gz -+ - - # Clean up anything we built - clean: -@@ -113,6 +123,15 @@ - if test ! -f $@; then exit 1; fi; \ - fi - -+allo-dahdi-fw%.tar.gz: -+ @if ( [ "$(HOTPLUG_FIRMWARE)" = "no" ] ) || ( [ -d $(DESTDIR)/usr/lib/hotplug/firmware ] && ! [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.$(subst .tar.gz,,$*) ] ) || ( [ -d $(DESTDIR)/lib/firmware ] && ! [ -f $(DESTDIR)/lib/firmware/.$(subst .tar.gz,,$*) ] ); then \ -+ echo "Attempting to download $@"; \ -+ if test ! -f $@; then $(DOWNLOAD) $(WGET_ARGS) $(FIRMWARE_URL_ALLO)/$@; fi; \ -+ if test ! -f $@; then exit 1; fi; \ -+ (cat $@ | gzip -d | tar --no-same-owner -xf -) \ -+ fi -+ -+ - firmware-loaders: $(FWLOADERS) - - .PHONY: dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz -@@ -145,16 +164,90 @@ - @$(call RUN_INST,dahdi-fw-a8b,$(A8B_VERSION)) - @$(call RUN_INST,dahdi-fw-a4a,$(A4A_VERSION)) - @$(call RUN_INST,dahdi-fw-a4b,$(A4B_VERSION)) -+######################ALLO################################# -+ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP1e ] ) && ( [ -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP1e ] ); then echo "no"; else echo "yes"; fi),yes) -+ -+ @echo "Installing ALLO firmwares to hotplug firmware directories" -+ @install -m 644 allo-dahdi-fw-2aCP1e.bin $(DESTDIR)/usr/lib/hotplug/firmware -+ @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP1e -+ @touch $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP1e -+ @install -m 644 allo-dahdi-fw-2aCP1e.bin $(DESTDIR)/lib/firmware -+ @rm -rf $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP1e -+ @touch $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP1e -+else -+ @echo "Firmware of ALLO card allo-dahdi-fw-2aCP1e.bin is already installed with required version" -+endif -+ -+ -+ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP2e ] ) && ( [ -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP2e ] ); then echo "no"; else echo "yes"; fi),yes) -+ -+ @echo "Installing ALLO firmwares to hotplug firmware directories" -+ @install -m 644 allo-dahdi-fw-2aCP2e.bin $(DESTDIR)/usr/lib/hotplug/firmware -+ @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP2e -+ @touch $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP2e -+ @install -m 644 allo-dahdi-fw-2aCP2e.bin $(DESTDIR)/lib/firmware -+ @rm -rf $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP2e -+ @touch $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP2e -+else -+ @echo "Firmware of ALLO cards allo-dahdi-fw-2aCP2e.bin is already installed with required version" -+endif -+ -+ -+ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4 ] ) && ( [ -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4 ] ); then echo "no"; else echo "yes"; fi),yes) -+ -+ @echo "Installing ALLO firmwares to hotplug firmware directories" -+ @install -m 644 allo-dahdi-fw-2aCP4.bin $(DESTDIR)/usr/lib/hotplug/firmware -+ @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4 -+ @touch $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4 -+ @install -m 644 allo-dahdi-fw-2aCP4.bin $(DESTDIR)/lib/firmware -+ @rm -rf $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4 -+ @touch $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4 -+else -+ @echo "Firmware of ALLO cards allo-dahdi-fw-2aCP4.bin is already installed with required version" -+endif -+ -+ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4e ] ) && ( [ -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4e ] ); then echo "no"; else echo "yes"; fi),yes) -+ -+ @echo "Installing ALLO firmwares to hotplug firmware directories" -+ @install -m 644 allo-dahdi-fw-2aCP4e.bin $(DESTDIR)/usr/lib/hotplug/firmware -+ @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4e -+ @touch $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP4e -+ @install -m 644 allo-dahdi-fw-2aCP4e.bin $(DESTDIR)/lib/firmware -+ @rm -rf $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4e -+ @touch $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP4e -+else -+ @echo "Firmware of ALLO cards allo-dahdi-fw-2aCP4e.bin is already installed with required version" -+endif -+ -+ -+ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP8e ] ) && ( [ -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP8e ] ); then echo "no"; else echo "yes"; fi),yes) -+ -+ @echo "Installing ALLO firmwares to hotplug firmware directories" -+ @install -m 644 allo-dahdi-fw-2aCP8e.bin $(DESTDIR)/usr/lib/hotplug/firmware -+ @rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP8e* -+ @touch $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw-2aCP8e -+ @install -m 644 allo-dahdi-fw-2aCP8e.bin $(DESTDIR)/lib/firmware -+ @rm -rf $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP8e* -+ @touch $(DESTDIR)/lib/firmware/.allo-dahdi-fw-2aCP8e -+else -+ @echo "Firmware of ALLO cards allo-dahdi-fw-2aCP8e.bin is already installed with required version" -+endif -+ -+#########################END###################################### - - # Uninstall any installed dahdi firmware images from hotplug firmware directories - hotplug-uninstall: - if [ -d $(DESTDIR)/usr/lib/hotplug/firmware ]; then \ - rm -f $(DESTDIR)/usr/lib/hotplug/firmware/dahdi-fw-*.bin; \ - rm -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw*; \ -+ rm -f $(DESTDIR)/usr/lib/hotplug/firmware/allo-dahdi-fw-*.bin; \ -+ rm -f $(DESTDIR)/usr/lib/hotplug/firmware/.allo-dahdi-fw*; \ - fi - if [ -d $(DESTDIR)/lib/firmware ]; then \ - rm -f $(DESTDIR)/lib/firmware/dahdi-fw-*.bin; \ - rm -f $(DESTDIR)/lib/firmware/.dahdi-fw*; \ -+ rm -f $(DESTDIR)/lib/firmware/allo-dahdi-fw-*.bin; \ -+ rm -f $(DESTDIR)/lib/firmware/.allo-dahdi-fw*; \ - fi - - make_firmware_object: make_firmware_object.in ../dahdi-base.o diff --git a/dahdi-linux-2.10.1-openvox-1.patch b/dahdi-linux-2.10.1-openvox-1.patch deleted file mode 100644 index 4a8fcf98f892..000000000000 --- a/dahdi-linux-2.10.1-openvox-1.patch +++ /dev/null @@ -1,6228 +0,0 @@ ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kbuild 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/Kbuild 2015-02-10 15:12:07.233961480 +0100 -@@ -14,6 +14,10 @@ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE13XP) += wcte13xp.o - -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115) += opvxd115/ -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA1200) += opvxa1200/ -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA24XX) += opvxa24xx/ -+ - wcte13xp-objs := wcte13xp-base.o wcxb_spi.o wcxb.o wcxb_flash.o - CFLAGS_wcte13xp-base.o += -I$(src)/oct612x -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api - ifeq ($(HOTPLUG_FIRMWARE),yes) ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kconfig 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/Kconfig 2015-02-10 15:03:42.355884929 +0100 -@@ -291,4 +291,34 @@ - - If unsure, say Y. - -+config DAHDI_OPVXD115 -+ tristate "OpenVox TE410P Quad-T1/E1 PCI" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ To compile this driver as a module, choose M here: the -+ module will be called opvxd115. -+ -+ If unsure, say Y. -+ -+config DAHDI_OPVXA1200 -+ tristate "OpenVox A1200P FXS/FXO Interface Driver" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ To compile this driver as a module, choose M here: the -+ module will be called opvxa1200. -+ -+ If unsure, say Y. -+ -+config DAHDI_OPVXA24XX -+ tristate "OpenVox A24xx FXS/FXO Interface Driver" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ To compile this driver as a module, choose M here: the -+ module will be called opvxa24xx. -+ -+ If unsure, say Y. -+ - source "drivers/dahdi/xpp/Kconfig" ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa1200/Kbuild 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa1200/Kbuild 2015-02-10 14:19:03.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 ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa1200/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa1200/Makefile 2015-02-10 14:19:03.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 ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa1200/base.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa1200/base.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,3117 @@ -+/* -+ * 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 -+ * -+ * Rev 1.4.12.6 5/15/2011 Miaolin -+ * use write dma to generate irq. -+ * add parameter watchdma allow reset dma when it is not correctly started. -+ * add delay after reset -+ * change reset time to 1 sec. -+ */ -+ -+#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 <asm/io.h> -+#include <linux/sched.h> -+#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 int watchdma=0; -+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) -+ if (ints & 0x01) -+ /* 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*/) -+ if(ints & 0x01) -+ /* 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; -+ } -+ -+ if(watchdma) { -+ if( (x!=0) && (x!=3) ) { -+ printk("Bad re-sync %d, resetting...\n", x); -+ outb(0x0f, wc->ioaddr + WC_CNTL); -+ for(x=0; x<1000*1000*1000; x++); -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ outb(0x01, wc->ioaddr + WC_OPER); -+ wc->lastchan=-1; -+ return; -+ } -+ } -+ -+ 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; -+} -+ -+DAHDI_IRQ_HANDLER(wctdm_interrupt) -+{ -+ 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; -+ unsigned int tsi; -+ 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); -+ -+ if((wc->fwversion&0x0f)==6) -+ { -+ tsi = (3-(card%4))*8 + (card/4) *128; -+ wctdm_setreg(wc, card, 34, tsi&0xff); -+ wctdm_setreg(wc, card, 35, (tsi>>8)&0x3); -+ wctdm_setreg(wc, card, 36, (tsi+1)&0xff); -+ wctdm_setreg(wc, card, 37, ((tsi+1)>>8)&0x3); -+ } -+ else -+ { -+ /* 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, tsi; -+ int fxsmode=0; -+// int tmpcard; -+ -+ /* 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); -+ if((wc->fwversion&0x0f)==6) -+ { -+ tsi = (3-(card%4))* 8 + (card/4) *128; -+ wctdm_setreg(wc, card, 2, (tsi)&0xff); // Tx Start count low byte 0 -+ wctdm_setreg(wc, card, 3, ((tsi)>>8)&0x3); // Tx Start count high byte 0 -+ wctdm_setreg(wc, card, 4, (tsi+1)&0xff); // Rx Start count low byte 0 -+ wctdm_setreg(wc, card, 5, ((tsi+1)>>8)&0x3); // Rx Start count high byte 0 -+ } -+ else -+ { -+ // 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; -+ -+ wc->ddev = dahdi_create_device(); //Dennis -+ if (!wc->ddev) -+ return -ENOMEM; -+ -+ /* 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, //Dennis -+ "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"; //Dennis -+ 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; -+// init_waitqueue_head(&wc->span.maintq); -+ 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 span with Dahdi\n"); -+ 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(0x00, wc->ioaddr + WC_CNTL); -+ /* Wait for 1 second */ -+ origjiffies = jiffies; -+ while(1) -+ { -+ if ((jiffies-origjiffies) >= (HZ)) -+ break;; -+ } -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ origjiffies = jiffies; -+ while(1) -+ { -+ if ((jiffies-origjiffies) >= (HZ/2)) -+ 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); -+ outb(0x33, 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, DAHDI_IRQ_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); //Dennis -+ 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->ddev->location); //Dennis -+ dahdi_free_device(wc->ddev); -+ 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 = dahdi_pci_module(&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_param(watchdma, 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); -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/Kbuild 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/Kbuild 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,40 @@ -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXA24XX) += opvxa24xx.o -+ -+FIRM_DIR := ../firmware -+ -+EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef -+ -+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 -+ -+ifeq ($(HOTPLUG_FIRMWARE),yes) -+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE -+endif -+ -+opvxa24xx-objs := private.o a24xx.o si321x.o si3050.o ec3000.o callerid.o busydetect.o base.o $(shell $(src)/../oct612x/octasic-helper objects ../oct612x) -+ -+ifneq ($(HOTPLUG_FIRMWARE),yes) -+opvxa24xx-objs += $(FIRM_DIR)/dahdi-fw-oct6114-032.o $(FIRM_DIR)/dahdi-fw-oct6114-064.o $(FIRM_DIR)/dahdi-fw-oct6114-128.o -+endif -+ -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-032.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-032.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-064.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-064.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-128.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-128.o -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/Makefile 2015-02-10 14:19:03.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 ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/a24xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/a24xx.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,286 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * $Id: a24xx.c 185 2010-12-14 07:58:51Z yangshugang $ -+ -+ * 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. -+ * -+ */ -+ -+#include <linux/spinlock.h> -+#include <linux/jiffies.h> -+ -+#include <dahdi/kernel.h> -+ -+#include "base.h" -+#include "proslic.h" -+ -+#define BIT_EC_PRESENT (1<<0) -+ -+#define VPM_DEFAULT_DTMFTHRESHOLD 1000 -+ -+/* indirect_resg */ -+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",0x0ff4}, -+{33,20,"PWR_ALARM_Q3Q4",0x6e7e}, -+{34,21,"PWR_ALARM_Q5Q6",0x0ff4}, -+{35,22,"LOOP_CLOSURE_FILTER",0x8000}, -+{36,23,"RING_TRIP_FILTER",0x0320}, -+{37,24,"TERM_LP_POLE_Q1Q2",0x0012}, -+{38,25,"TERM_LP_POLE_Q3Q4",0x0012}, -+{39,26,"TERM_LP_POLE_Q5Q6",0x0012}, -+{40,27,"CM_BIAS_RINGING",0x0C00}, -+{41,64,"DCDC_MIN_V",0x0C00}, -+{42,255,"DCDC_XTRA",0x1000}, -+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, -+}; -+ -+void __a24xx_wait_just_a_bit(int foo) -+{ -+ long newjiffies; -+ newjiffies = jiffies + foo; -+ while(jiffies < newjiffies); -+} -+ -+void __a24xx_setcard(void *wc_dev, int card) -+{ -+ struct a24xx_dev *dev = (struct a24xx_dev *)(wc_dev); -+ if (dev->curcard != card) { -+ __opvx_a24xx_setcard(dev->mem32, card); -+ dev->curcard = card; -+ } -+} -+ -+inline void __a24xx_spi_setreg(struct a24xx_dev *wc_dev, int card, unsigned char reg, unsigned char value) -+{ -+ __opvx_a24xx_spi_setreg((void *)wc_dev, wc_dev->mem32, card, wc_dev->modtype[card], reg, value, __a24xx_setcard); -+} -+ -+inline unsigned char __a24xx_spi_getreg(struct a24xx_dev *wc_dev, int card, unsigned char reg) -+{ -+ return __opvx_a24xx_spi_getreg((void *)wc_dev, wc_dev->mem32, card, wc_dev->modtype[card], reg, __a24xx_setcard); -+} -+ -+int __a24xx_malloc_chunk(struct a24xx_dev *wc_dev,unsigned int frq) -+{ -+ __opvx_a24xx_set_chunk(&(wc_dev->readchunk), &(wc_dev->writechunk),frq); -+ wc_dev->readdma = wc_dev->writedma + frq * DAHDI_MAX_CHUNKSIZE * (MAX_NUM_CARDS) * 2; -+ -+ 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; -+} -+ -+int __a24xx_wait_access(struct a24xx_dev *wc_dev, 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 = __a24xx_spi_getreg(wc_dev, card, I_STATUS); -+ if (!data) { -+ return 0; -+ } -+ } -+ -+ if(count > (MAX-1)) { -+ printk(" ##### Loop error (%02x) #####\n", data); -+ } -+ -+ return 0; -+} -+ -+int __a24xx_proslic_setreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address, unsigned short data) -+{ -+ int res = -1; -+ /* Translate 3215 addresses */ -+ if (wc_dev->flags[card] & FLAG_3215) { -+ address = __translate_3215(address); -+ if (address == 255) { -+ return 0; -+ } -+ } -+ if(!__a24xx_wait_access(wc_dev, card)) { -+ __a24xx_spi_setreg(wc_dev, card, IDA_LO,(unsigned char)(data & 0xFF)); -+ __a24xx_spi_setreg(wc_dev, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); -+ __a24xx_spi_setreg(wc_dev, card, IAA,address); -+ res = 0; -+ } -+ -+ return res; -+} -+ -+int __a24xx_proslic_getreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address) -+{ -+ int res = -1; -+ char *p=NULL; -+ /* Translate 3215 addresses */ -+ if (wc_dev->flags[card] & FLAG_3215) { -+ address = __translate_3215(address); -+ if (address == 255) { -+ return 0; -+ } -+ } -+ if (!__a24xx_wait_access(wc_dev, card)) { -+ __a24xx_spi_setreg(wc_dev, card, IAA, address); -+ if (!__a24xx_wait_access(wc_dev, card)) { -+ unsigned char data1, data2; -+ data1 = __a24xx_spi_getreg(wc_dev, card, IDA_LO); -+ data2 = __a24xx_spi_getreg(wc_dev, card, IDA_HI); -+ res = data1 | (data2 << 8); -+ } else { -+ p = "Failed to wait inside\n"; -+ } -+ } else { -+ p = "failed to wait\n"; -+ } -+ if (p) { -+ printk("%s\n", p); -+ } -+ return res; -+} -+ -+void __a24xx_vpm_setpresent(struct a24xx_dev *wc_dev) -+{ -+ wc_dev->vpm = BIT_EC_PRESENT; -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_vpm_setpresent_v2(wc_dev->mem32); -+ else -+ __opvx_a24xx_vpm_setpresent(wc_dev->mem32); -+ printk("OpenVox VPM: Present and operational servicing %d span(s)\n", 1/*wc_dev->numspans*/); -+} -+ -+void a24xx_spi_setreg(struct a24xx_dev *wc_dev, int card, unsigned char reg, unsigned char value) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ __a24xx_spi_setreg(wc_dev, card, reg, value); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+} -+ -+unsigned char a24xx_spi_getreg(struct a24xx_dev *wc_dev, int card, unsigned char reg) -+{ -+ unsigned long flags; -+ unsigned char ret; -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ ret = __a24xx_spi_getreg(wc_dev, card, reg); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+ return ret; -+} -+ -+static inline unsigned int a24xx_oct_in(struct a24xx_dev *wc_dev, const unsigned int addr) -+{ -+ unsigned long flags; -+ unsigned int ret; -+ -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ ret = __opvx_a24xx_oct_in_v2(wc_dev->mem32, addr); -+ else -+ ret = __opvx_a24xx_oct_in(wc_dev->mem32, addr); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+ -+ return ret; -+} -+ -+static inline void a24xx_oct_out(struct a24xx_dev *wc_dev, const unsigned int addr, const unsigned int value) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_oct_out_v2(wc_dev->mem32, addr, value); -+ else -+ __opvx_a24xx_oct_out(wc_dev->mem32, addr, value); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+} -+ -+void oct_set_reg(void *data, unsigned int reg, unsigned int val) -+{ -+ struct a24xx_dev *wc_dev = data; -+ a24xx_oct_out(wc_dev, reg, val); -+} -+ -+unsigned int oct_get_reg(void *data, unsigned int reg) -+{ -+ struct a24xx_dev *wc_dev = data; -+ unsigned int ret; -+ ret = a24xx_oct_in(wc_dev, reg); -+ return ret; -+} -+ -+void a24xx_reset_spi(struct a24xx_dev *wc_dev, int card) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ __opvx_a24xx_reset_spi(wc_dev, card, __a24xx_setcard); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+} -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/base.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/base.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,2679 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * $Id: base.c 359 2011-04-06 06:11:39Z yangshugang $ -+ -+ * 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, modified from opvxa1200.c -+ * Rev 0.20 add octasic echo canceller support. -+ * -+ */ -+ -+#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 <asm/io.h> -+#include <linux/delay.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+ -+#ifdef TEST_LOG_INCOME_VOICE -+#include <linux/string.h> -+#include <asm/uaccess.h> /* get_fs(), set_fs(), KERNEL_DS */ -+#include <linux/file.h> /* fput() */ -+#endif -+ -+#include <dahdi/kernel.h> -+#include <dahdi/wctdm_user.h> -+#include "fxo_modes.h" -+ -+#include "proslic.h" -+#include "base.h" -+#include "ec3000.h" -+#include "busydetect.h" -+ -+/* module parameters */ -+int debug; -+int spi_cmd=0x223; -+ -+int reversepolarity = 0; -+int alawoverride = 0; -+int fxotxgain = 0; -+int fxorxgain = 0; -+int fastpickup = 0; -+int fxofullscale = 0; /* fxo full scale tx/rx, register 30, acim */ -+int fwringdetect = 0; -+int _opermode = 0; -+int cidsupport = 1; /* default support caller id analysis */ -+int cidbuflen = 3000; /* in msec, default 3000 */ -+int cidtimeout = 6*1000; /* in msec, default 6000 */ -+int fxstxgain = 0; -+int fxsrxgain = 0; -+int fxshonormode = 0; -+int boostringer = 0; -+int fastringer = 0; -+int lowpower = 0; -+int loopcurrent = 20; -+int timingonly = 0; -+int fixedtimepolarity=0; /* time delay in ms when send polarity after rise edge of 1st ring.*/ -+int ringdebounce = DEFAULT_RING_DEBOUNCE; -+unsigned int battdebounce; -+unsigned int battalarm; -+unsigned int battthresh; -+int robust = 0; -+#ifdef VPM_SUPPORT -+/* ec debug */ -+int ec_debug = 0; -+int vpmsupport = 1; -+#endif -+ -+#define MS_PER_HOOKCHECK (1) -+ -+int ec_spans = 4; -+ -+static char* A2410P_Name = "A2410P"; -+static struct a24xx_desc a2410a = { "OpenVox A2410", 0 }; -+static char* A1610P_Name = "A1610P"; -+static struct a24xx_desc a1610a = { "OpenVox A1610", 0 }; -+static char* A810P_Name = "A810P"; -+static struct a24xx_desc a810a = { "OpenVox A810", 0 }; -+static struct a24xx *ifaces[WC_MAX_IFACES]; -+static char *opermode = "FCC"; -+ -+/* If set to auto, vpmdtmfsupport is enabled for VPM400M and disabled for VPM450M */ -+static int vpmdtmfsupport = -1; /* -1=auto, 0=disabled, 1=enabled*/ -+static unsigned int ms_per_irq = 1; // 1/2/4/8/16 allowed -+static unsigned int max_iface_index = 0; -+static unsigned int irq_stub = 0; -+ -+#define POLARITY_XOR(card) ( \ -+ (reversepolarity != 0) ^ (wc_dev->mod[(card)].fxs.reversepolarity != 0) ^ \ -+ (wc_dev->mod[(card)].fxs.vmwi_lrev != 0) ^\ -+ ((wc_dev->mod[(card)].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) != 0)\ -+ ) -+ -+static const struct dahdi_echocan_features vpm_ec_features = { -+ .NLP_automatic = 1, -+ .CED_tx_detect = 1, -+ .CED_rx_detect = 1, -+}; -+ -+static void a24xx_release(struct a24xx *wc); -+static void a24xx_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); -+ -+static const struct dahdi_echocan_ops vpm_ec_ops = { -+// .name = "OPENVOX VPM", -+ .echocan_free = a24xx_echocan_free, -+}; -+ -+static int a24xx_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, -+ struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec) -+{ -+ struct a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ int channel; -+ const struct dahdi_echocan_ops *ops; -+ const struct dahdi_echocan_features *features; -+ -+ -+ if (!wc_dev->vpm) { -+ return -ENODEV; -+ } -+ -+ if (chan->span->offset >= ec_spans) { -+ return -ENODEV; -+ } -+ -+ if (wc_dev->vpm_ec) { -+ ops = &vpm_ec_ops; -+ features = &vpm_ec_features; -+ } -+ -+ if (ecp->param_count > 0) { -+ printk(KERN_WARNING "OpenVox VPM echo canceller does not support parameters; failing request\n"); -+ return -EINVAL; -+ } -+ -+ *ec = wc->ec[chan->chanpos - 1]; -+ (*ec)->ops = ops; -+ (*ec)->features = *features; -+ -+ channel = chan->chanpos; -+ -+ if (wc_dev->vpm_ec) { -+ channel -= 1; -+ if(ec_debug) { -+ printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, offset is %d, length %d\n", -+ wc_dev->pos, chan->chanpos, channel, ecp->tap_length); -+ } -+ opvx_vpm_setec(wc_dev->vpm_ec, channel, ecp->tap_length); -+ msleep(10); -+ } -+ -+ return 0; -+} -+ -+static void a24xx_echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) -+{ -+ struct a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ int channel; -+ -+ memset(ec, 0, sizeof(*ec)); -+ -+ channel = chan->chanpos; -+ -+ if (wc_dev->vpm_ec) { -+ channel -= 1; -+ if (ec_debug) -+ printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, Span is %d, offset is %d length 0\n", -+ wc_dev->pos, chan->chanpos, chan->span->offset, channel); -+ opvx_vpm_setec(wc_dev->vpm_ec, channel, 0); -+ } -+} -+ -+static void free_wc(struct a24xx *wc) -+{ -+ int i; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ if (wc->ec[i]) { -+ kfree(wc->ec[i]); -+ wc->ec[i] = NULL; -+ } -+ } -+ kfree(wc); -+ wc = NULL; -+} -+ -+static void a24xx_vpm_init(struct a24xx *wc) -+{ -+ int x; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ int laws[4] = { 0, }; -+ int res; -+ -+ 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 ( (wc_dev->fwversion&0xffff) > 0x3) -+ res = __opvx_a24xx_check_vpm_v2(wc_dev->mem32); -+ else -+ res = __opvx_a24xx_check_vpm(wc_dev->mem32); -+ -+ if (res < 0) { -+ if (-1 == res) { -+ printk("OpenVox VPM: Support Disabled\n"); -+ } else if (-2 == res) { -+ printk("OpenVox VPM: Not Present\n"); -+ } -+ return; -+ } -+ -+ /* Setup alaw vs ulaw rules */ -+ for (x = 0;x < 1; x++) { -+ if(wc->span.deflaw == DAHDI_LAW_ALAW) { -+ laws[x] = 1; -+ } -+ else { -+ laws[x] = 0; -+ } -+ } -+ -+ vpm_capacity = opvx_vpm_getcapacity(wc_dev); -+ printk("OpenVox VPM: echo cancellation supports %d channels\n", vpm_capacity); -+ -+ switch (vpm_capacity) { -+ case 32: -+#if defined(HOTPLUG_FIRMWARE) -+ if ((request_firmware(&firmware, oct032_firmware, &wc_dev->dev->dev) != 0) || -+ !firmware) { -+ printk("OpenVox VPM: 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_zaptel_fw_oct6114_032_bin_size; -+#endif -+ break; -+ case 64: -+#if defined(HOTPLUG_FIRMWARE) -+ if ((request_firmware(&firmware, oct064_firmware, &wc_dev->dev->dev) != 0) || -+ !firmware) { -+ printk("OpenVox VPM: 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->dev) != 0) || -+ !firmware) { -+ printk("OpenVox VPM: 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: -+ printk("Unsupported channel capacity found on VPM module (%d).\n", vpm_capacity); -+ return; -+ } -+ -+ if (!(wc_dev->vpm_ec = opvx_vpm_init(wc_dev, laws, /*wc_dev->numspans*/1, firmware))) { -+ printk("OpenVox VPM: Failed to initialize\n"); -+ if (firmware != &embedded_firmware) { -+ release_firmware(firmware); -+ } -+ return; -+ } -+ -+ if (firmware != &embedded_firmware) { -+ release_firmware(firmware); -+ } -+ -+ if (vpmdtmfsupport == -1) { -+ printk("OpenVox VPM: hardware DTMF disabled.\n"); -+ vpmdtmfsupport = 0; -+ } -+ -+ __a24xx_vpm_setpresent(wc_dev); -+ -+} -+ -+#ifdef AUDIO_RINGCHECK -+static inline void ring_check(struct a24xx *wc, int card) -+{ -+ int x; -+ short sample; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if (wc_dev->modtype[card] != MOD_TYPE_FXO) { -+ return; -+ } -+ wc_dev->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_dev->mod[card].fxo.peg != 1)) { -+ if (debug > 1) { -+ printk(KERN_DEBUG "High peg!\n"); -+ } -+ if ((wc_dev->mod[card].fxo.pegtimer < PEGTIME) && (wc_dev->mod[card].fxo.pegtimer > MINPEGTIME)) { -+ wc_dev->mod[card].fxo.pegcount++; -+ } -+ wc_dev->mod[card].fxo.pegtimer = 0; -+ wc_dev->mod[card].fxo.peg = 1; -+ } else if ((sample < -10000) && (wc_dev->mod[card].fxo.peg != -1)) { -+ if (debug > 1) { -+ printk(KERN_DEBUG "Low peg!\n"); -+ } -+ if ((wc_dev->mod[card].fxo.pegtimer < (PEGTIME >> 2)) && (wc_dev->mod[card].fxo.pegtimer > (MINPEGTIME >> 2))) { -+ wc_dev->mod[card].fxo.pegcount++; -+ } -+ wc_dev->mod[card].fxo.pegtimer = 0; -+ wc_dev->mod[card].fxo.peg = -1; -+ } -+ } -+ if (wc_dev->mod[card].fxo.pegtimer > PEGTIME) { -+ /* Reset pegcount if our timer expires */ -+ wc_dev->mod[card].fxo.pegcount = 0; -+ } -+ /* Decrement debouncer if appropriate */ -+ if (wc_dev->mod[card].fxo.ringdebounce) { -+ wc_dev->mod[card].fxo.ringdebounce--; -+ } -+ if (!wc_dev->mod[card].fxo.offhook && !wc_dev->mod[card].fxo.ringdebounce) { -+ if (!wc_dev->mod[card].fxo.ring && (wc_dev->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_dev->mod[card].fxo.offhook) { -+ dahdi_hooksig(&wc->chans[card], DAHDI_RXSIG_RING); -+ } -+ wc_dev->mod[card].fxo.ring = 1; -+ } -+ if (wc_dev->mod[card].fxo.ring && !wc_dev->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_dev->mod[card].fxo.ring = 0; -+ } -+ } -+} -+#endif -+ -+#if 0 -+static int a24xx_hardware_init(struct a24xx_dev *wc_dev, char *sigcap) -+{ -+ unsigned int x; -+ unsigned char ch; -+ -+ /* Signal Reset */ -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_reset_modules_v2(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ else -+ __opvx_a24xx_reset_modules(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ -+ /* Check OpenVox version */ -+ printk("OpenVox %s version: %01x.%01x\n", wc_dev->card_name, wc_dev->fwversion>>16, wc_dev->fwversion&0xffff); -+ -+ /* Clear interrupts */ -+ __opvx_a24xx_clear_irqs(wc_dev->mem32); -+ -+ /* Wait 1/4 of a second more */ -+ //opvx_wait_just_a_bit(HZ/4); -+ -+ /* test cards exist and type at first */ -+ for(x=0; x<wc_dev->max_cards; x+=CARDS_PER_MODULE) { -+ __a24xx_setcard(wc_dev, x); -+ wc_dev->modtype[x] = MOD_TYPE_FXO; -+ ch = __a24xx_spi_getreg(wc_dev, x, 2); /* read register 2, 3050 return 0x3, 3210 return 0x0 */ -+ if(0x03 == ch) { -+ wc_dev->modtype[x+1] = MOD_TYPE_FXO; -+ wc_dev->modtype[x+2] = MOD_TYPE_FXO; -+ wc_dev->modtype[x+3] = MOD_TYPE_FXO; -+ if(debug) { -+ printk("module %d is a FXO\n", x); -+ } -+ } else { -+ wc_dev->modtype[x] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+1] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+2] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+3] = MOD_TYPE_FXS; -+ if(debug) { -+ printk("module %d is a FXS or Not Installed\n", x); -+ } -+ } -+ } -+ -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_reset_modules_v2(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ else -+ __opvx_a24xx_reset_modules(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ int sane=0,ret=0,readi=0; -+ -+ if( (x%4) == 0 && wc_dev->modtype[x]==MOD_TYPE_FXS) { /* set 3215 to daisy chain mode */ -+ __a24xx_setcard(wc_dev, x); -+ __opvx_a24xx_write_8bits(wc_dev->mem32, 0x00); -+ __opvx_a24xx_write_8bits(wc_dev->mem32, 0x80); -+ } -+ -+#if 1 -+ touch_softlockup_watchdog(); // avoid showing CPU softlock message -+ -+ /* Init with Auto Calibration */ -+ if (!(ret=si321x_init_proslic(wc_dev, x, 0, 0, sane))) { -+ wc_dev->cardflag |= (1 << x); -+ if (debug) { -+ readi = a24xx_spi_getreg(wc_dev,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x, -+ ((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- AUTO FXS/DPO\n",x); -+ } else { -+ if(ret!=-2) { -+ sane=1; -+ -+ printk("Init ProSlic with Manual Calibration \n"); -+ /* Init with Manual Calibration */ -+ if (!si321x_init_proslic(wc_dev, x, 0, 1, sane)) { -+ wc_dev->cardflag |= (1 << x); -+ if (debug) { -+ readi = a24xx_spi_getreg(wc_dev,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x, -+ ((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- MANUAL FXS\n",x); -+ } else { -+ printk("Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC"); -+ sigcap[x] = 1; -+ } -+ } else if (!(ret = si3050_init_voicedaa(wc_dev, x, 0, 0, sane))) { -+ wc_dev->cardflag |= (1 << x); -+ printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); -+ } else -+ printk("Module %d: Not installed\n", x); -+ } -+#endif -+ } -+ -+ /* Return error if nothing initialized okay. */ -+ if (!wc_dev->cardflag && !timingonly) { -+ return -1; -+ } -+ -+ return 0; -+} -+#endif -+ -+static int a24xx_hardware_init_all(struct a24xx_dev *wc_dev, char *sigcap) -+{ -+ unsigned int x; -+ unsigned char ch; -+ int sane=0,ret=0; -+ int flag=0,tmp_flag=0,blank_flag=0; -+ -+ /* Signal Reset */ -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_reset_modules_v2(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ else -+ __opvx_a24xx_reset_modules(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ -+ /* Check OpenVox version */ -+ printk("OpenVox %s version: %01x.%01x\n", wc_dev->card_name, wc_dev->fwversion>>16, wc_dev->fwversion&0xffff); -+ -+ /* Clear interrupts */ -+ __opvx_a24xx_clear_irqs(wc_dev->mem32); -+ -+ /* Wait 1/4 of a second more */ -+ //opvx_wait_just_a_bit(HZ/4); -+ -+ /* test cards exist and type at first */ -+ for(x=0; x<wc_dev->max_cards; x+=CARDS_PER_MODULE) { -+ __a24xx_setcard(wc_dev, x); -+ wc_dev->modtype[x] = MOD_TYPE_FXO; -+ ch = __a24xx_spi_getreg(wc_dev, x, 2); /* read register 2, 3050 return 0x3, 3210 return 0x0 */ -+ if(0x03 == ch) { -+ wc_dev->modtype[x+1] = MOD_TYPE_FXO; -+ wc_dev->modtype[x+2] = MOD_TYPE_FXO; -+ wc_dev->modtype[x+3] = MOD_TYPE_FXO; -+ if(debug) { -+ printk("module %d is a FXO\n", x); -+ } -+ } else { -+ wc_dev->modtype[x] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+1] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+2] = MOD_TYPE_FXS; -+ wc_dev->modtype[x+3] = MOD_TYPE_FXS; -+ if(debug) { -+ printk("module %d is a FXS or Not Installed\n", x); -+ } -+ } -+ } -+ -+ if ( (wc_dev->fwversion&0xffff) > 0x3) -+ __opvx_a24xx_reset_modules_v2(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ else -+ __opvx_a24xx_reset_modules(wc_dev->mem32, __a24xx_wait_just_a_bit, HZ); // reset again; -+ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ sane=1,ret=0; -+ touch_softlockup_watchdog(); // avoid showing CPU softlock message -+ -+ /* Init with Auto Calibration */ -+ if(wc_dev->modtype[x] == MOD_TYPE_FXO){ -+ if (!(ret = si3050_init_voicedaa(wc_dev, x, 0, 0, sane))) { -+ wc_dev->cardflag |= (1 << x); -+ } -+ } -+ } -+ -+ /*initial FXS modules*/ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ if(wc_dev->modtype[x] == MOD_TYPE_FXS){ -+ flag |=(1 << x); -+ } -+ } -+ -+ touch_softlockup_watchdog(); -+ if((tmp_flag=si321x_init_proslic_all(wc_dev,flag,0,0,0,&blank_flag))>0) -+ { -+ tmp_flag=si321x_init_proslic_all(wc_dev,tmp_flag,0,1,1,NULL); -+ } -+ flag &=~blank_flag; -+ flag &=~tmp_flag; -+ wc_dev->cardflag |=flag; -+ -+ for (x = 0; x < wc_dev->max_cards; x++){ -+ if(wc_dev->cardflag & (1<<x)){ -+ spin_lock_init(&wc_dev->mod[x].fxs.lasttxhooklock); -+ if(wc_dev->modtype[x] == MOD_TYPE_FXS){ -+ printk("Module %d: Installed -- AUTO FXS/DPO\n",x); -+ }else -+ printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); -+ }else{ -+ if(tmp_flag & (1 << x)){ -+ printk("Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC"); -+ sigcap[x] = 1; //************ -+ } -+ else -+ printk("Module %d: Not installed\n", x); -+ } -+ } -+ -+ /* Return error if nothing initialized okay. */ -+ if (!wc_dev->cardflag && !timingonly) { -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void callerid_ring_on_deal(struct a24xx *wc, int card) -+{ -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if(wc_dev->cid_state[card] == CID_STATE_IDLE) { -+ reset_parser_variable_from_chan_num(wc->span.spanno, wc->chans[card]->channo); -+ if (is_ring_delay_operation(wc->span.spanno, wc->chans[card]->channo)) { -+ wc_dev->cid_state[card] = CID_STATE_RING_DELAY; -+ } else { -+ wc_dev->cid_state[card] = CID_STATE_RING_ON; -+ wc_dev->cid_history_clone_cnt[card] = cidbuflen; -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); -+ } -+ } else if(wc_dev->cid_state[card] == CID_STATE_RING_DELAY) { -+ wc_dev->cid_state[card] = CID_STATE_RING_ON; -+ wc_dev->cid_history_clone_cnt[card] = cidbuflen; -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); -+ } else { -+ if (wc_dev->cid_state[card] != CID_STATE_WAIT_RING_FINISH) { -+ set_signal_unknown_from_chan_num(wc->span.spanno, wc->chans[card]->channo); -+ wc_dev->cid_state[card] = CID_STATE_WAIT_RING_FINISH; -+ } -+ wc_dev->cid_history_clone_cnt[card] = cidtimeout; -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); -+ } -+} -+ -+static void callerid_ring_off_deal(struct a24xx *wc, int card) -+{ -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if(wc_dev->cid_state[card] == CID_STATE_RING_ON) { -+ wc_dev->cid_state[card] = CID_STATE_RING_OFF; -+ } -+ -+ if(wc_dev->cid_state[card] != CID_STATE_RING_DELAY) { -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); -+ } -+} -+ -+static void a24xx_voicedaa_check_hook(struct a24xx *wc, int card) -+{ -+#define MS_PER_CHECK_HOOK 16 -+#ifndef AUDIO_RINGCHECK -+ unsigned char res; -+#endif -+ signed char b; -+ int errors = 0; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ struct fxo *fxo = &wc_dev->mod[card].fxo; -+ -+ /* Try to track issues that plague slot one FXO's */ -+ b = wc_dev->reg0shadow[card]; -+ if ((b & 0x2) || !(b & 0x8)) { -+ /* Not good -- don't look at anything else */ -+ if (debug) { -+ printk(KERN_DEBUG "Errors (%02x) on card %d!\n", b, card + 1); -+ } -+ errors++; -+ } -+ b &= 0x9b; -+ if (fxo->offhook) { -+ if (b != 0x9) { -+ a24xx_spi_setreg(wc_dev, card, 5, 0x9); -+ } -+ } else { -+ if (b != 0x8) { -+ a24xx_spi_setreg(wc_dev, card, 5, 0x8); -+ } -+ } -+ if (errors) { -+ return; -+ } -+ -+ if (!fxo->offhook) { -+ if (fwringdetect) { -+ res = wc_dev->reg0shadow[card] & 0x60; -+ if (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(cidsupport) { -+ callerid_ring_on_deal(wc, card); -+ } 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(cidsupport) { -+ callerid_ring_off_deal(wc, card); -+ } 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_dev->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(cidsupport) { -+ callerid_ring_on_deal(wc, card); -+ } 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(cidsupport) { -+ callerid_ring_off_deal(wc, card); -+ } 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_dev->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_dev->ohdebounce && wc_dev->offhook) { -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); -+ if (debug) { -+ printk(KERN_DEBUG "Signalled On Hook\n"); -+ } -+#ifdef ZERO_BATT_RING -+ wc_dev->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_dev->onhook) { -+ wc_dev->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) { -+ if (cidsupport) { -+ set_cidstart_desc_from_chan_num(wc->span.spanno, wc->chans[card]->channo, wc_dev->cid_state[card]); -+ if (is_callerid_disable(wc->span.spanno, wc->chans[card]->channo)) { -+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY); -+ } -+ } else { -+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY); -+ } -+ } -+ fxo->polarity = fxo->lastpol; -+ } -+ } -+ } -+#undef MS_PER_CHECK_HOOK -+} -+ -+ -+static void a24xx_post_initialize(struct a24xx *wc) -+{ -+ int x; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ /* Finalize signalling */ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ if (wc_dev->cardflag & (1 << x)) { -+ if (wc_dev->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 void a24xx_proslic_check_hook(struct a24xx *wc, int card) -+{ -+ char res; -+ int hook; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ /* For some reason we have to debounce the -+ hook detector. */ -+ -+ res = wc_dev->reg0shadow[card]; -+ hook = (res & 1); -+ if (hook != wc_dev->mod[card].fxs.lastrxhook) { -+ /* Reset the debounce (must be multiple of 4ms) */ -+ wc_dev->mod[card].fxs.debounce = 8 * (4 * 8); -+#if 0 -+ printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, wc_dev->mod[card].fxs.debounce); -+#endif -+ } else { -+ if (wc_dev->mod[card].fxs.debounce > 0) { -+ wc_dev->mod[card].fxs.debounce-= 16 * DAHDI_CHUNKSIZE; -+#if 0 -+ printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, wc_dev->mod[card].fxs.debounce); -+#endif -+ if (!wc_dev->mod[card].fxs.debounce) { -+#if 0 -+ printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook); -+#endif -+ wc_dev->mod[card].fxs.debouncehook = hook; -+ } -+ if (!wc_dev->mod[card].fxs.oldrxhook && wc_dev->mod[card].fxs.debouncehook) { -+ /* Off hook */ -+ if (debug) { -+ printk(KERN_DEBUG "opvxa24xx: Card %d Going off hook\n", card); -+ } -+ switch (wc_dev->mod[card].fxs.lasttxhook) { -+ case SLIC_LF_RINGING: /* Ringing */ -+ case SLIC_LF_OHTRAN_FWD: /* Forward On Hook Transfer */ -+ case SLIC_LF_OHTRAN_REV: /* Reverse On Hook Transfer */ -+ /* just detected OffHook, during Ringing or OnHookTransfer */ -+ wc_dev->mod[card].fxs.idletxhookstate = POLARITY_XOR(card) ? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ break; -+ } -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); -+ if (robust) { -+ si321x_init_proslic(wc_dev, card, 1, 0, 1); -+ } -+ wc_dev->mod[card].fxs.oldrxhook = 1; -+ -+ } else if (wc_dev->mod[card].fxs.oldrxhook && !wc_dev->mod[card].fxs.debouncehook) { -+ /* On hook */ -+ if (debug) { -+ printk(KERN_DEBUG "opvxa24xx: Card %d Going on hook\n", card); -+ } -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); -+ wc_dev->mod[card].fxs.oldrxhook = 0; -+ } -+ } -+ } -+ wc_dev->mod[card].fxs.lastrxhook = hook; -+} -+ -+static void a24xx_transmit(struct a24xx *wc,unsigned int order) -+{ -+ int x, y, pos; -+ volatile unsigned char *txbuf; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ __opvx_a24xx_transmit(wc_dev->mem32, wc_dev->writechunk, &txbuf,ms_per_irq,order); -+ //printk("ints is %d\n", ints); -+ /* Calculate Transmission */ -+ -+ for (y=0;y<DAHDI_CHUNKSIZE;y++) { -+#ifdef __BIG_ENDIAN -+ // operation pending... -+#else -+ for (x=0;x<wc_dev->max_cards;x++) { -+ pos = y * MAX_NUM_CARDS + x; -+ txbuf[pos] = wc->chans[x]->writechunk[y]; -+ } -+#endif -+ } -+} -+ -+static void a24xx_receive(struct a24xx *wc,unsigned int order) -+{ -+ int x, y; -+ volatile unsigned char *rxbuf; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ __opvx_a24xx_receive(wc_dev->mem32, wc_dev->readchunk, &rxbuf ,ms_per_irq,order); -+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { -+#ifdef __BIG_ENDIAN -+ // operation pending... -+#else -+ for (y=0;y<wc_dev->max_cards/*MAX_NUM_CARDS*/;y++) { -+ if (wc_dev->cardflag & (1 << y)) { -+ wc->chans[y]->readchunk[x] = rxbuf[MAX_NUM_CARDS * x + y]; -+ } -+#ifdef TEST_LOG_INCOME_VOICE -+ wc_dev->voc_buf[y][wc_dev->voc_ptr[y]] = rxbuf[MAX_NUM_CARDS * x + y]; -+ wc_dev->voc_ptr[y]++; -+ if(wc_dev->voc_ptr[y] >= voc_buffer_size) { -+ wc_dev->voc_ptr[y] = 0; -+ } -+#endif -+ } -+#endif -+ } -+ -+#if 0 -+ if( (ints&0x0f) == 0x0f) { // dump buffer every 16 times; -+ printk("dump 0x%x\n", ints); -+ for(x=0; x<48; x++) { -+ printk("0x%02x, ", (int)rxbuf[x]); -+ //if( 15== (x%15) ) -+ } -+ printk("\n"); -+ } -+#endif -+ -+ if(cidsupport) { -+ parser_callerid_process(wc, cidbuflen, cidtimeout); -+ } -+ -+#ifdef AUDIO_RINGCHECK -+ for (x=0;x<wc_dev->max_cards;x++) { -+ ring_check(wc, x); -+ } -+#endif -+ /* XXX We're wasting 8 taps. We should get closer :( */ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ if (wc_dev->cardflag & (1 << x)) { -+ dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk); -+ } -+ } -+} -+ -+#if 0 -+DAHDI_IRQ_HANDLER(a24xx_interrupt) -+{ -+ unsigned int ints; -+ int x, y, z,order; -+ int mode; -+ struct a24xx *wc = dev_id; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ struct fxs * fxs ; -+ -+ ints = __opvx_a24xx_get_irqstatus(wc_dev->mem32); -+ -+ if (!ints) -+ return IRQ_NONE; -+ -+ __opvx_a24xx_set_irqstatus(wc_dev->mem32, ints); // clear interrupt register. -+ -+ for (x=0;x<wc_dev->max_cards; x++) { -+ if (wc_dev->cardflag & (1 << x) && (wc_dev->modtype[x] == MOD_TYPE_FXS)) { -+ -+ fxs = &wc_dev->mod[x].fxs; -+ -+ if (SLIC_LF_RINGING == fxs->lasttxhook && !fxs->neonringing) { -+ /* RINGing, prepare for OHT */ -+ fxs->ohttimer = OHT_TIMER << 3; -+ /* OHT mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_OHTRAN_REV : -+ SLIC_LF_OHTRAN_FWD; -+ } else if (fxs->ohttimer) { -+ /* check if still OnHook */ -+ if (!fxs->oldrxhook) { -+ fxs->ohttimer -= DAHDI_CHUNKSIZE; -+ if (fxs->ohttimer) -+ continue; -+ -+ /* Switch to active */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ /* if currently OHT */ -+ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) || (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) { -+ if (fxs->vmwi_hvac) { -+ /* force idle polarity Forward if ringing */ -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ /* Set ring generator for neon */ -+ si321x_set_ring_generator_mode(wc_dev, x, 1); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ /* Apply the change as appropriate */ -+ a24xx_spi_setreg(wc_dev, x, LINE_STATE, fxs->lasttxhook); -+ } -+ } else { -+ fxs->ohttimer = 0; -+ /* Switch to active */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ printk("Channel %d OnHookTransfer abort\n",x); -+ } -+ } -+ } -+ } -+ -+ if (ints & (1<<16)) { /* it is our interrupts */ -+ wc_dev->intcount++; -+ switch(ms_per_irq){ -+ case 1: -+ z = wc_dev->intcount & 0x3; -+ mode = wc_dev->intcount & 0xc; -+ for(y = 0; y < wc_dev->max_cards / 4; y++) { /* do some detect operate every 4ms */ -+ x = z + y*4; -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 4: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 8: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 12: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & 0xf0)) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 2: -+ z = wc_dev->intcount & 0x1; -+ mode = wc_dev->intcount & 0x6; -+ for(y = 0; y < wc_dev->max_cards / 2; y++) { /* do some detect operate every 4ms */ -+ x = z + y*2; -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 2: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 4: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 6: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>1))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 4: -+ mode = wc_dev->intcount & 0x3; -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 1: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 2: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 3: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>2))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 8: -+ mode = wc_dev->intcount & 0x1; -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 1: -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO){ -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ } -+ break; -+ case 0: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>3))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 16: -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>4))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO){ -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ } -+ } -+ break; -+ } -+ -+ if (!(wc_dev->intcount % ( 10000/ms_per_irq ))) { -+ /* Accept an alarm once per 10 seconds */ -+ for (x=0;x<wc_dev->max_cards;x++) -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ if (wc_dev->mod[x].fxs.palarms) { -+ wc_dev->mod[x].fxs.palarms--; -+ } -+ } -+ } -+ /**/ -+ for(order=0;order < ms_per_irq;order++){ -+ a24xx_receive(wc, order); -+ dahdi_receive(&wc->span); -+ -+ dahdi_transmit(&wc->span); -+ a24xx_transmit(wc, order); -+ } -+ } -+ -+ return IRQ_RETVAL(1); -+} -+#endif -+ -+#if 1 -+static int interrupt_onecard_handler(struct a24xx *wc) -+{ -+ unsigned int ints=0; -+ int x, y, z,order; -+ int mode; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ struct fxs * fxs ; -+ -+ if((wc_dev->fwversion < ((1 << 16)|3)) || (wc_dev->master)){ -+ ints = __opvx_a24xx_get_irqstatus(wc_dev->mem32); -+ if (!ints) -+ return IRQ_NONE; -+ } -+ -+ __opvx_a24xx_set_irqstatus(wc_dev->mem32, ints); // clear interrupt register. -+ -+ for (x=0;x<wc_dev->max_cards; x++) { -+ if (wc_dev->cardflag & (1 << x) && (wc_dev->modtype[x] == MOD_TYPE_FXS)) { -+ fxs = &wc_dev->mod[x].fxs; -+ -+ if (SLIC_LF_RINGING == fxs->lasttxhook && !fxs->neonringing) { -+ /* RINGing, prepare for OHT */ -+ fxs->ohttimer = OHT_TIMER << 3; -+ /* OHT mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_OHTRAN_REV : -+ SLIC_LF_OHTRAN_FWD; -+ } else if (fxs->ohttimer) { -+ /* check if still OnHook */ -+ if (!fxs->oldrxhook) { -+ fxs->ohttimer -= DAHDI_CHUNKSIZE; -+ if (fxs->ohttimer) -+ continue; -+ -+ /* Switch to active */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ /* if currently OHT */ -+ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) || (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) { -+ if (fxs->vmwi_hvac) { -+ /* force idle polarity Forward if ringing */ -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ /* Set ring generator for neon */ -+ si321x_set_ring_generator_mode(wc_dev, x, 1); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ /* Apply the change as appropriate */ -+ a24xx_spi_setreg(wc_dev, x, LINE_STATE, fxs->lasttxhook); -+ } -+ } else { -+ fxs->ohttimer = 0; -+ /* Switch to active */ -+ fxs->idletxhookstate = POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ printk("Channel %d OnHookTransfer abort\n",x); -+ } -+ } -+ } -+ } -+ -+ if ( ((ints & (1<<16)) && wc_dev->master) || (!wc_dev->master)) { /* it is our interrupts */ -+ wc_dev->intcount++; -+ switch(ms_per_irq){ -+ case 1: -+ z = wc_dev->intcount & 0x3; -+ mode = wc_dev->intcount & 0xc; -+ for(y = 0; y < wc_dev->max_cards / 4; y++) { /* do some detect operate every 4ms */ -+ x = z + y*4; -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 4: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 8: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 12: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & 0xf0)) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 2: -+ z = wc_dev->intcount & 0x1; -+ mode = wc_dev->intcount & 0x6; -+ for(y = 0; y < wc_dev->max_cards / 2; y++) { /* do some detect operate every 4ms */ -+ x = z + y*2; -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 2: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 4: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 6: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>1))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 4: -+ mode = wc_dev->intcount & 0x3; -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 1: -+ /* Read first shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ //if(x==0) -+ //printk("reg 68 of %x is 0x%x\n", x, wc_dev->reg0shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ break; -+ case 2: -+ /* Read second shadow reg */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ //if(x==1) -+ // printk("reg 64 of %x is 0x%x\n", x, wc_dev->reg1shadow[x]); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ break; -+ case 3: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>2))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 8: -+ mode = wc_dev->intcount & 0x1; -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ switch(mode) { -+ case 1: -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO){ -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ } -+ break; -+ case 0: -+ /* Perform processing */ -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>3))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO) { -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ } -+ break; -+ case 16: -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if (wc_dev->cardflag & (1 << x ) ) { -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 68); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 64); -+ a24xx_proslic_check_hook(wc, x); -+ if (!(wc_dev->intcount & (0xf0>>4))) { -+ si321x_proslic_recheck_sanity(wc_dev, x); -+ } -+ } -+ else if (wc_dev->modtype[x] == MOD_TYPE_FXO){ -+ wc_dev->reg0shadow[x] = a24xx_spi_getreg(wc_dev, x, 5); -+ wc_dev->reg1shadow[x] = a24xx_spi_getreg(wc_dev, x, 29); -+ a24xx_voicedaa_check_hook(wc, x); -+ } -+ } -+ } -+ break; -+ } -+ -+ if (!(wc_dev->intcount % ( 10000/ms_per_irq ))) { -+ /* Accept an alarm once per 10 seconds */ -+ for (x=0;x<wc_dev->max_cards;x++) -+ if (wc_dev->modtype[x] == MOD_TYPE_FXS) { -+ if (wc_dev->mod[x].fxs.palarms) { -+ wc_dev->mod[x].fxs.palarms--; -+ } -+ } -+ } -+ /**/ -+ for(order=0;order < ms_per_irq;order++){ -+ dahdi_transmit(&wc->span); -+ parser_busy_silent_process(wc, 1); -+ a24xx_transmit(wc, order); -+ -+ a24xx_receive(wc, order); -+ parser_busy_silent_process(wc, 0); -+ dahdi_receive(&wc->span); -+ } -+ } -+ return 0; -+} -+ -+DAHDI_IRQ_HANDLER(a24xx_interrupt) -+{ -+ /**/ -+ struct a24xx *wc = dev_id; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ int i; -+ -+ if(!wc_dev->master){ -+ interrupt_onecard_handler(wc); -+ }else{ -+ if(irq_stub){ -+ for(i=0;i<max_iface_index;i++){ -+ wc = ifaces[i]; -+ if(wc){ -+ wc_dev = &wc->dev; -+ if( wc_dev->fwversion >= ((1 << 16)|2) ){ -+ interrupt_onecard_handler(wc); -+ } -+ } -+ } -+ }else -+ interrupt_onecard_handler(wc); -+ } -+ -+ -+ return IRQ_RETVAL(1); -+} -+#endif -+/* Must be called from within an interruptible context */ -+static int set_vmwi(struct a24xx *wc, int chan_idx) -+{ -+ struct a24xx_dev *wc_dev = &wc->dev; -+ struct fxs *const fxs = &wc_dev->mod[chan_idx].fxs; -+ -+ if (fxs->vmwi_active_messages) { -+ fxs->vmwi_lrev = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV) ? 1 : 0; -+ fxs->vmwi_hvdc = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVDC) ? 1 : 0; -+ fxs->vmwi_hvac = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) ? 1 : 0; -+ } else { -+ fxs->vmwi_lrev = 0; -+ fxs->vmwi_hvdc = 0; -+ fxs->vmwi_hvac = 0; -+ } -+ -+ if (debug) { -+ printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, " -+ "lrev=%d, hvdc=%d, hvac=%d\n", -+ chan_idx, -+ fxs->vmwi_active_messages, -+ fxs->vmwi_lrev, -+ fxs->vmwi_hvdc, -+ fxs->vmwi_hvac -+ ); -+ } -+ -+ if (fxs->vmwi_hvac) { -+ /* Can't change ring generator while in On Hook Transfer mode*/ -+ if (!fxs->ohttimer) { -+ if (POLARITY_XOR(chan_idx)) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ /* Set ring generator for neon */ -+ si321x_set_ring_generator_mode(wc_dev, chan_idx, 1); -+ /* Activate ring to send neon pulses */ -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ a24xx_spi_setreg(wc_dev, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ } else { -+ if (fxs->neonringing) { -+ /* Set ring generator for normal ringer */ -+ si321x_set_ring_generator_mode(wc_dev, chan_idx, 0); -+ /* ACTIVE, polarity determined later */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ } else if ((fxs->lasttxhook == SLIC_LF_RINGING) || -+ (fxs->lasttxhook == SLIC_LF_OPEN)) { -+ /* Can't change polarity while ringing or when open, -+ set idlehookstate instead */ -+ if (POLARITY_XOR(chan_idx)) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ if(debug) -+ printk(KERN_DEBUG "Unable to change polarity on channel" -+ "%d, lasttxhook=0x%X\n", -+ chan_idx, -+ fxs->lasttxhook -+ ); -+ return 0; -+ } -+ if (POLARITY_XOR(chan_idx)) { -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ fxs->lasttxhook |= SLIC_LF_REVMASK; -+ } else { -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ fxs->lasttxhook &= ~SLIC_LF_REVMASK; -+ } -+ a24xx_spi_setreg(wc_dev, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ return 0; -+} -+ -+static int a24xx_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 a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ int x; -+ -+ struct fxs *const fxs = &wc_dev->mod[chan->chanpos - 1].fxs; -+ -+ switch (cmd) { -+ case DAHDI_ONHOOKTRANSFER: -+ if (wc_dev->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) { -+ return -EINVAL; -+ } -+ if (get_user(x, (__user int *)data)) { -+ return -EFAULT; -+ } -+#if 0 -+ /**/ -+ wc_dev->mod[chan->chanpos - 1].fxs.ohttimer = x << 3; -+ if (reversepolarity) { -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x6; /* OHT mode when idle */ -+ } else { -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = 0x2; -+ } -+ if (wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) { -+ /* Apply the change if appropriate */ -+ if (reversepolarity) { -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook = 0x6; -+ } else { -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook = 0x2; -+ } -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 64, wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook); -+ } -+#endif -+#if 1 -+ /* Active mode when idle */ -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? -+ SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ if (wc_dev->mod[chan->chanpos - 1].fxs.neonringing) { -+ /* keep same Forward polarity */ -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook = SLIC_LF_OHTRAN_FWD; -+ //printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n",chan->chanpos - 1); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, -+ LINE_STATE, wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook); -+ } else if (wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook == SLIC_LF_ACTIVE_FWD || -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook == SLIC_LF_ACTIVE_REV) { -+ /* Apply the change if appropriate */ -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos - 1) ? -+ SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; -+ //printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n",chan->chanpos - 1); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, -+ LINE_STATE, wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook); -+ } -+#endif -+ break; -+#if 1 -+ case DAHDI_VMWI_CONFIG: -+ if (wc_dev->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (copy_from_user(&(fxs->vmwisetting), -+ (__user void *)data, -+ sizeof(fxs->vmwisetting))) -+ return -EFAULT; -+ //printk("--opvxa24xx:DAHDI_VMWI_CONFIG,card=%d--\n",chan->chanpos - 1); -+ set_vmwi(wc, chan->chanpos - 1); -+ break; -+ case DAHDI_VMWI: -+ if (wc_dev->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (get_user(x, (__user int *) data)) -+ return -EFAULT; -+ if (0 > x) -+ return -EFAULT; -+ fxs->vmwi_active_messages = x; -+ set_vmwi(wc, chan->chanpos - 1); -+ //printk("-----opvxa24xx,DAHDI_VMWI,card=%d,set_vmwi------\n",chan->chanpos - 1); -+ break; -+#endif -+ case DAHDI_SETPOLARITY: -+ if (get_user(x, (__user int *)data)) { -+ return -EFAULT; -+ } -+ if (wc_dev->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) { -+ return -EINVAL; -+ } -+ /* Can't change polarity while ringing or when open */ -+ if ((wc_dev->mod[chan->chanpos -1 ].fxs.lasttxhook == SLIC_LF_RINGING) || -+ (wc_dev->mod[chan->chanpos -1 ].fxs.lasttxhook == SLIC_LF_OPEN)) { -+ return -EINVAL; -+ } -+ wc_dev->mod[chan->chanpos -1 ].fxs.reversepolarity = x; -+#if 0 -+ if ((x && !reversepolarity) || (!x && reversepolarity)) { -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook |= 0x04; -+ } else { -+ wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook &= ~0x04; -+ } -+#endif -+ if (POLARITY_XOR(chan->chanpos - 1)) { -+ wc_dev->mod[chan->chanpos -1 ].fxs.lasttxhook |= SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Reverse Polarity, card %d\n", -+ chan->chanpos - 1); -+ } else { -+ wc_dev->mod[chan->chanpos -1 ].fxs.lasttxhook &= ~SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Normal Polarity, card %d\n", -+ chan->chanpos - 1); -+ } -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, LINE_STATE, wc_dev->mod[chan->chanpos - 1].fxs.lasttxhook); -+ break; -+ case WCTDM_GET_STATS: -+ if (wc_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ stats.tipvolt = a24xx_spi_getreg(wc_dev, chan->chanpos - 1, 80) * -376; -+ stats.ringvolt = a24xx_spi_getreg(wc_dev, chan->chanpos - 1, 81) * -376; -+ stats.batvolt = a24xx_spi_getreg(wc_dev, chan->chanpos - 1, 82) * -376; -+ } else if (wc_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { -+ stats.tipvolt = (signed char)a24xx_spi_getreg(wc_dev, chan->chanpos - 1, 29) * 1000; -+ stats.ringvolt = (signed char)a24xx_spi_getreg(wc_dev, chan->chanpos - 1, 29) * 1000; -+ stats.batvolt = (signed char)a24xx_spi_getreg(wc_dev, 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_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ for (x=0;x<NUM_INDIRECT_REGS;x++) { -+ regs.indirect[x] = si321x_proslic_getreg_indirect(wc_dev, chan->chanpos -1, x); -+ } -+ for (x=0;x<NUM_REGS;x++) { -+ regs.direct[x] = a24xx_spi_getreg(wc_dev, chan->chanpos - 1, x); -+ } -+ } else { -+ memset(®s, 0, sizeof(regs)); -+ for (x=0;x<NUM_FXO_REGS;x++) -+ regs.direct[x] = a24xx_spi_getreg(wc_dev, 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_dev->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); -+ si321x_proslic_setreg_indirect(wc_dev, 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); -+ a24xx_spi_setreg(wc_dev, 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_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { -+ /* Set the ACIM register */ -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 30, (fxofullscale==1) ? (echoregs.acim|0x10) : echoregs.acim); -+ -+ /* Set the digital echo canceller registers */ -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 45, echoregs.coef1); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 46, echoregs.coef2); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 47, echoregs.coef3); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 48, echoregs.coef4); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 49, echoregs.coef5); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 50, echoregs.coef6); -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 51, echoregs.coef7); -+ a24xx_spi_setreg(wc_dev, 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; -+ } -+ -+ si3050_set_hwgain(wc_dev, 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 a24xx_open(struct dahdi_chan *chan) -+{ -+ int channo; -+ -+ struct a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ channo = chan->chanpos - 1; -+ -+ if (!(wc_dev->cardflag & (1 << (chan->chanpos - 1)))) { -+ return -ENODEV; -+ } -+ if (wc_dev->dead) { -+ return -ENODEV; -+ } -+ wc_dev->usecount++; -+ -+ try_module_get(THIS_MODULE); -+ -+ return 0; -+} -+ -+static inline struct a24xx *a24xx_from_span(struct dahdi_span *span) -+{ -+ return container_of(span, struct a24xx, span); -+} -+ -+static int a24xx_watchdog(struct dahdi_span *span, int event) -+{ -+ struct a24xx *wc = a24xx_from_span(span); -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ printk(KERN_INFO "opvxa24xx: Restarting DMA\n"); -+ __opvx_a24xx_restart_dma(wc_dev->mem32); -+ -+ return 0; -+} -+ -+static int a24xx_close(struct dahdi_chan *chan) -+{ -+ struct a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ wc_dev->usecount--; -+ -+ module_put(THIS_MODULE); -+ -+ if (wc_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ /* -+ if (reversepolarity) { -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = 5; -+ } -+ else { -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = 1; -+ }*/ -+ int idlehookstate; -+ idlehookstate = POLARITY_XOR(chan->chanpos - 1)? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ wc_dev->mod[chan->chanpos - 1].fxs.idletxhookstate = idlehookstate; -+ } -+ /* If we're dead, release us now */ -+ if (!wc_dev->usecount && wc_dev->dead) { -+ a24xx_release(wc); -+ } -+ return 0; -+} -+ -+static int a24xx_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) -+{ -+ int reg=0; -+ struct a24xx *wc = chan->pvt; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if (wc_dev->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { -+ /* XXX Enable hooksig for FXO XXX */ -+ switch(txsig) { -+ case DAHDI_TXSIG_START: -+ case DAHDI_TXSIG_OFFHOOK: -+ wc_dev->mod[chan->chanpos - 1].fxo.offhook = 1; -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 5, 0x9); -+ if(cidsupport) { -+ wc_dev->cid_state[chan->chanpos - 1] = CID_STATE_IDLE; -+ wc_dev->cid_history_clone_cnt[chan->chanpos - 1] = 0; -+ wc_dev->cid_history_ptr[chan->chanpos - 1] = 0; -+ memset(wc_dev->cid_history_buf[chan->chanpos - 1], DAHDI_LIN2X(0, chan), cidbuflen * DAHDI_MAX_CHUNKSIZE); -+ } -+ break; -+ case DAHDI_TXSIG_ONHOOK: -+ wc_dev->mod[chan->chanpos - 1].fxo.offhook = 0; -+ a24xx_spi_setreg(wc_dev, 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_dev->mod[chan->chanpos-1].fxs.lasttxhook = wc_dev->mod[chan->chanpos-1].fxs.idletxhookstate; -+ /* Can't change Ring Generator during OHT */ -+ if (!wc_dev->mod[chan->chanpos-1].fxs.ohttimer) { -+ si321x_set_ring_generator_mode(wc_dev, -+ chan->chanpos-1, wc_dev->mod[chan->chanpos-1].fxs.vmwi_hvac); -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = wc_dev->mod[chan->chanpos-1].fxs.vmwi_hvac ? SLIC_LF_RINGING : wc_dev->mod[chan->chanpos-1].fxs.idletxhookstate; -+ } else { -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = wc_dev->mod[chan->chanpos-1].fxs.idletxhookstate; -+ } -+ break; -+ case DAHDI_SIG_FXOGS: -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = 3; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_OFFHOOK: -+ switch(chan->sig) { -+ case DAHDI_SIG_EM: -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = 5; -+ break; -+ default: -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = wc_dev->mod[chan->chanpos-1].fxs.idletxhookstate; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_START: -+ //wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = 4; -+ si321x_set_ring_generator_mode(wc_dev, -+ chan->chanpos-1, 0); -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = SLIC_LF_RINGING; -+ break; -+ case DAHDI_TXSIG_KEWL: -+ wc_dev->mod[chan->chanpos-1].fxs.lasttxhook = 0; -+ break; -+ default: -+ printk(KERN_NOTICE "opvxa24xx: 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 -+ a24xx_spi_setreg(wc_dev, chan->chanpos - 1, 64, wc_dev->mod[chan->chanpos-1].fxs.lasttxhook); -+#endif -+ } -+ return 0; -+} -+ -+#ifdef DAHDI_SPAN_OPS -+static const struct dahdi_span_ops a24xx_span_ops = { -+ .owner = THIS_MODULE, -+ .hooksig = a24xx_hooksig, -+ .open = a24xx_open, -+ .close = a24xx_close, -+ .ioctl = a24xx_ioctl, -+ .watchdog = a24xx_watchdog, -+#ifdef VPM_SUPPORT -+ .echocan_create = a24xx_echocan_create, -+#endif -+ -+}; -+#endif -+ -+static int a24xx_init_spans(struct a24xx *wc) -+{ -+ int x; -+ struct a24xx_dev *wc_dev = &(wc->dev); -+ -+ /* Zapata stuff */ -+ sprintf(wc->span.name, "OPVXA24XX/%d", wc_dev->pos); -+ snprintf(wc->span.desc, sizeof(wc->span.desc)-1, "%s Board %d", wc_dev->variety, wc_dev->pos + 1); -+// snprintf(wc->span.location, sizeof(wc->span.location) - 1, -+// "PCI Bus %02d Slot %02d", wc_dev->dev->bus->number, PCI_SLOT(wc_dev->dev->devfn) + 1); -+ wc_dev->ddev->location = kasprintf(GFP_KERNEL, -+ "PCI Bus %02d Slot %02d", -+ wc_dev->dev->bus->number, -+ PCI_SLOT(wc_dev->dev->devfn) + 1); -+ -+ //printk("wc is 0x%x, wc_dev ix 0x%x, ddev is 0x%x\n", wc, &(wc->dev), wc_dev->ddev); -+ if (!wc_dev->ddev->location) { -+ dahdi_free_device(wc_dev->ddev); -+ wc_dev->ddev = NULL; -+ return -ENOMEM; -+ } -+ -+ wc_dev->ddev->manufacturer = "OpenVox"; //Dennis -+ wc_dev->ddev->devicetype = wc_dev->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; -+ } -+ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ sprintf(wc->chans[x]->name, "OPVXA24XX/%d/%d", wc_dev->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 = &a24xx_span_ops; -+#else -+ wc->span.hooksig = a24xx_hooksig; -+ wc->span.open = a24xx_open; -+ wc->span.close = a24xx_close; -+ wc->span.ioctl = a24xx_ioctl; -+ wc->span.watchdog = a24xx_watchdog; -+#ifdef VPM_SUPPORT -+ if (vpmsupport) -+ wc->span.echocan_create = a24xx_echocan_create; -+#endif -+ wc->span.pvt = wc; -+#endif -+ wc->span.chans = wc->chans; -+ wc->span.channels = wc_dev->max_cards; /*MAX_NUM_CARDS;*/ -+ wc->span.flags = DAHDI_FLAG_RBS; -+// init_waitqueue_head(&wc->span.maintq); -+ list_add_tail(&wc->span.device_node, &wc->dev.ddev->spans); -+// init_waitqueue_head(&wc->regq) -+ -+ if (dahdi_register_device(wc_dev->ddev, &wc->dev.dev->dev)) { -+ printk(KERN_NOTICE "Unable to register span with Dahdi\n"); -+ kfree(wc_dev->ddev->location); -+ dahdi_free_device(wc_dev->ddev); -+ wc_dev->ddev = NULL; -+ printk("dahdi_register_device fail\n"); -+ mdelay(3000); -+ return -1; -+ } -+ return 0; -+} -+ -+static int __devinit a24xx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ int x; -+ int y; -+ struct a24xx *wc; -+ struct a24xx_desc *d = (struct a24xx_desc *)ent->driver_data; -+ struct a24xx_dev *wc_dev; -+ unsigned int fwbuild; -+ char span_flags[MAX_NUM_CARDS] = { 0, }; -+ int z,index; -+ static int initd_ifaces=0; -+ -+ if(!initd_ifaces){ -+ memset((void *)ifaces,0,(sizeof(struct a24xx *))*WC_MAX_IFACES); -+ initd_ifaces=1; -+ } -+ for (x = 0; x < WC_MAX_IFACES; x++) { -+ if (!ifaces[x]) { -+ break; -+ } -+ } -+ if (x >= WC_MAX_IFACES) { -+ printk("Too many interfaces\n"); -+ return -EIO; -+ } -+ index = x; -+ -+ if (pci_enable_device(pdev)) { -+ res = -EIO; -+ } else { -+ int cardcount = 0; -+ -+ wc = kmalloc(sizeof(struct a24xx), GFP_KERNEL); -+ if(!wc) -+ return -ENOMEM; -+ -+ memset(wc, 0, sizeof(struct a24xx)); -+ wc->dev.ddev = dahdi_create_device(); -+#if 0 -+ printk("wc is 0x%x, ddev is 0x%x\n", wc, wc->dev.ddev); -+#endif -+ if (!wc->dev.ddev) { -+ kfree(wc); -+ return -ENOMEM; -+ } -+ wc_dev = &wc->dev; -+ wc_dev->ledstate = 0; -+ -+ for (x=0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); ++x) { -+ wc->chans[x] = &wc->_chans[x]; -+ } -+ -+ spin_lock_init(&wc_dev->lock); -+ wc_dev->curcard = -1; -+ -+ if(ent->device == 0x0810) -+ wc_dev->max_cards = 8; -+ else if(ent->device == 0x1610) -+ wc_dev->max_cards = 16; -+ else -+ wc_dev->max_cards = 24; -+ -+ wc_dev->mem_region = pci_resource_start(pdev, 0); -+ wc_dev->mem_len = pci_resource_len(pdev, 0); -+ wc_dev->mem32 = (unsigned long)ioremap(wc_dev->mem_region, wc_dev->mem_len); -+ wc_dev->dev = pdev; -+ wc_dev->pos = x; -+ wc_dev->variety = d->name; -+ for (y = 0; y < wc_dev->max_cards; y++) { -+ wc_dev->flags[y] = d->flags; -+ } -+ -+ /* Keep track of whether we need to free the region */ -+ if (request_mem_region(wc_dev->mem_region, wc_dev->mem_len, "opvxa24xx")) { -+ wc_dev->freeregion = 1; -+ } -+ -+ if(debug) { -+ printk("======= find a card @ mem32 0x%x, size %ud\n", (unsigned int)wc_dev->mem32, (unsigned int)wc_dev->mem_len); -+ } -+#if 0 -+ printk("======= manual exit\n"); -+ if(wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ return -ENOMEM; -+ } -+#endif -+ -+ wc_dev->fwversion = __opvx_a24xx_get_version(wc_dev->mem32); -+ if(wc_dev->max_cards == 24) -+ wc_dev->card_name = A2410P_Name; -+ else if(wc_dev->max_cards == 16) -+ wc_dev->card_name = A1610P_Name; -+ else if(wc_dev->max_cards == 8) -+ wc_dev->card_name = A810P_Name; -+ -+ if(wc_dev->fwversion < ((1 << 16)|1) ) -+ ms_per_irq = 1; -+ -+ if((ms_per_irq != 1)&& -+ (ms_per_irq != 2)&& -+ (ms_per_irq != 4)&& -+ (ms_per_irq != 8)&& -+ (ms_per_irq != 16)) -+ ms_per_irq = 1; -+ -+ if(wc_dev->fwversion > ((1 << 16)|2)){ -+ if(!index) -+ wc_dev->master = 1; //master card -+ else -+ wc_dev->master = 0; -+ if(!irq_stub) -+ wc_dev->master = 1; -+ }else -+ wc_dev->master = 0; -+ -+ wc->index = index; -+ -+ /* Allocate enough memory for two dahdi chunks, receive and transmit. Each sample uses -+ 8 bits. */ -+ wc_dev->writechunk = pci_alloc_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, &wc_dev->writedma); -+ if (!wc_dev->writechunk) { -+ printk("opvxa24xx: Unable to allocate DMA-able memory\n"); -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ return -ENOMEM; -+ } -+ -+ if(debug) { -+ printk("opvxa24xx: dma buffer allocated at 0x%x, pci(0x%x)\n", (unsigned int)wc_dev->writechunk, (unsigned int)wc_dev->writedma); -+ } -+ -+ __a24xx_malloc_chunk(wc_dev,ms_per_irq); -+ -+ if (a24xx_init_spans(wc)) { -+ printk(KERN_NOTICE "opvxa24xx: Unable to intialize hardware\n"); -+ /* Free Resources */ -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ pci_free_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, (void *)wc_dev->writechunk, wc_dev->writedma); -+ return -ENOMEM; -+ } -+ -+ /* Enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Keep track of which device we are */ -+ pci_set_drvdata(pdev, wc); -+ -+ /* kmalloc ec */ -+ for (x = 0; x < wc_dev->max_cards; x++) { -+ if (!(wc->ec[x] = kmalloc(sizeof(*wc->ec[x]), GFP_KERNEL))) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ } -+ -+ /* init hardware */ -+#if 0 -+ a24xx_hardware_init(wc_dev, span_flags); -+ -+ __opvx_a24xx_setcreg(wc_dev->mem32, 0x4a0, 7, spi_cmd ); -+ int spi_cmd_from_fpga = __opvx_a24xx_getcreg(wc_dev->mem32, 0x4a0, 7); -+ printk("%s:current spi_cmd is 0x%x\n", __FUNCTION__ , spi_cmd_from_fpga ); -+#endif -+ -+ res = a24xx_hardware_init_all(wc_dev, span_flags); -+ if (res < 0) { -+ /* Free Resources */ -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ pci_free_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, (void *)wc_dev->writechunk, wc_dev->writedma); -+ pci_set_drvdata(pdev, NULL); -+ dahdi_unregister_device(wc->dev.ddev); //Dennis -+ kfree(wc->dev.ddev->location); -+ dahdi_free_device(wc->dev.ddev); -+ free_wc(wc); -+ return -EIO; -+ } -+ for (z = 0; z < wc_dev->max_cards/*MAX_NUM_CARDS*/; z++) { -+ if (span_flags[z]) { -+ wc->chans[z]->sigcap = __DAHDI_SIG_FXO | DAHDI_SIG_BROKEN; -+ } -+ } -+ -+ /* init ec module */ -+ if (!wc_dev->vpm) { -+ a24xx_vpm_init(wc); -+ } -+ -+ if(wc_dev->master || ( wc_dev->fwversion < ((1 << 16)|2) ) ){ -+ if (request_irq(pdev->irq, a24xx_interrupt, DAHDI_IRQ_SHARED, "opvxa24xx"/*wc_dev->card_name*/, wc)) { -+ printk(KERN_NOTICE "Unable to request IRQ %d\n", pdev->irq); -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ pci_free_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, (void *)wc_dev->writechunk, wc_dev->writedma); -+ pci_set_drvdata(pdev, NULL); -+ free_wc(wc); -+ return -EIO; -+ } -+ } -+ -+ if(0) { // for debug; -+ -+ printk("exit after alloc irq\n"); -+ /* Free Resources */ -+ if(wc_dev->master || ( wc_dev->fwversion < ((1 << 16)|2) )) -+ free_irq(pdev->irq, wc); -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ pci_free_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, (void *)wc_dev->writechunk, wc_dev->writedma); -+ pci_set_drvdata(pdev, NULL); -+ dahdi_unregister_device(wc->dev.ddev); //Dennis -+ kfree(wc->dev.ddev->location); -+ dahdi_free_device(wc->dev.ddev); -+ free_wc(wc); -+ return -EIO; -+ } -+ -+#ifdef TEST_LOG_INCOME_VOICE -+ for(x=0; x<wc_dev->max_cards; x++) { -+ wc_dev->voc_buf[x] = kmalloc(voc_buffer_size, GFP_KERNEL); -+ wc_dev->voc_ptr[x] = 0; -+ } -+#endif -+ if(cidsupport) { -+ int len = cidbuflen * DAHDI_MAX_CHUNKSIZE; -+ if(debug) { -+ printk("cid support enabled, length is %d msec\n", cidbuflen); -+ } -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ wc_dev->cid_history_buf[x] = kmalloc(len, GFP_KERNEL); -+ wc_dev->cid_history_ptr[x] = 0; -+ wc_dev->cid_history_clone_cnt[x] = 0; -+ wc_dev->cid_state[x] = CID_STATE_IDLE; -+ } -+ } -+ -+ /* set channel sigcap */ -+ a24xx_post_initialize(wc); -+ -+ init_busydetect(wc, opermode); -+ init_callerid(wc); -+ -+ /* Enable interrupts */ -+ __opvx_a24xx_enable_interrupts(wc_dev->mem32); -+ -+ /* Initialize Write/Buffers to all blank data */ -+ memset((void *)wc_dev->writechunk,0, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2); -+ -+ /*set irq frequence*/ -+ if(wc_dev->fwversion >= ((1 << 16)|1) ) -+ __opvx_a24xx_set_irq_frq(wc_dev->mem32,ms_per_irq); -+ -+ if(wc_dev->fwversion > ((1 << 16)|2)){ -+ __opvx_a24xx_set_master(wc_dev->mem32,wc_dev->master^0x01); -+ } -+ /* Start DMA */ -+ __opvx_a24xx_start_dma(wc_dev->mem32, wc_dev->writedma); -+ -+ /* module count */ -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ if (wc_dev->cardflag & (1 << x)) { -+ cardcount++; -+ } -+ } -+ fwbuild = __opvx_a24xx_getcreg(wc_dev->mem32, 0x0, 0xe); -+ printk(KERN_NOTICE "Found an OpenVox %s: Version %x.%x (%d modules),Build 0x%08x\n", wc_dev->card_name, wc_dev->fwversion>>16, wc_dev->fwversion&0xffff, cardcount,fwbuild ); -+ if(debug) { -+ printk(KERN_DEBUG "OpenVox %s debug On\n", wc_dev->card_name); -+ } -+ -+ ifaces[index] = wc; -+ max_iface_index++; -+ -+ res = 0; -+ } -+ -+ return res; -+} -+ -+ -+static void a24xx_release(struct a24xx *wc) -+{ -+#ifdef TEST_LOG_INCOME_VOICE -+ struct file * f = NULL; -+ mm_segment_t orig_fs; -+ int i; -+ char fname[20]; -+#endif -+ int y; -+ char *s; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ /*Unregister dahdi_span*/ -+ dahdi_unregister_device(wc_dev->ddev); //Dennis -+ /* Release mem region and iounmap mem */ -+ if (wc_dev->freeregion) { -+ release_mem_region(wc_dev->mem_region, wc_dev->mem_len); -+ iounmap((void *)wc_dev->mem32); -+ } -+ -+#ifdef TEST_LOG_INCOME_VOICE -+ for(i=0; i<wc_dev->max_cards; 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_dev->voc_buf[i]) { -+ f->f_op->write(f, wc_dev->voc_buf[i], voc_buffer_size, &f->f_pos); -+ kfree(wc_dev->voc_buf[i]); -+ } -+ -+ set_fs(orig_fs); -+ fput(f); -+ } -+#endif -+ -+ /* Release cid history buffer */ -+ if(cidsupport) { -+ int x; -+ for (x = 0; x < wc_dev->max_cards/*MAX_NUM_CARDS*/; x++) { -+ kfree(wc_dev->cid_history_buf[x]); -+ } -+ } -+ -+ /* Release a24xx */ -+ s = wc_dev->card_name; -+ for(y = 0; y < max_iface_index; y++) -+ if(ifaces[y] == wc) -+ break; -+ -+ -+ kfree(wc_dev->ddev->location); //Dennis -+ dahdi_free_device(wc_dev->ddev); -+ free_wc(wc); -+ ifaces[y]=NULL; -+ -+ printk(KERN_INFO "Free an OpenVox %s card\n", s); -+} -+ -+static void __devexit a24xx_remove_one(struct pci_dev *pdev) -+{ -+ struct a24xx *wc = pci_get_drvdata(pdev); -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if (wc) { -+ /* In case hardware is still there */ -+ __opvx_a24xx_disable_interrupts(wc_dev->mem32); -+ -+ /* Wait some time to handle the last irq */ -+ __a24xx_wait_just_a_bit(HZ/10); /* delay 1/10 sec */ -+ -+ /* Stop any DMA */ -+ __opvx_a24xx_stop_dma(wc_dev->mem32); -+ -+ /* Reset tdm controller */ -+ __opvx_a24xx_reset_tdm(wc_dev->mem32); -+ -+ /* Release echo canceller */ -+ if (wc_dev->vpm_ec) { -+ opvx_vpm_release(wc_dev->vpm_ec); -+ } -+ wc_dev->vpm_ec = NULL; -+ -+ if(wc_dev->master || ( wc_dev->fwversion < ((1 << 16)|2) )){ -+ free_irq(pdev->irq, wc); -+ } -+ /* Immediately free resources */ -+ pci_free_consistent(pdev, ms_per_irq * DAHDI_MAX_CHUNKSIZE * MAX_NUM_CARDS * 2 * 2, (void *)wc_dev->writechunk, wc_dev->writedma); -+ -+ destroy_callerid(wc); -+ destroy_busydetect(wc); -+ -+ /* Release span, possibly delayed */ -+ if (!wc_dev->usecount) { -+ a24xx_release(wc); -+ } else { -+ wc_dev->dead = 1; -+ } -+ } -+} -+ -+static struct pci_device_id a24xx_pci_tbl[] = { -+ { 0x1B74, 0x2410, 0x1B74, 0x0001, 0, 0, (unsigned long) &a2410a }, // Information for A2410 revsion A. -+ { 0x1B74, 0x1610, 0x1B74, 0x0001, 0, 0, (unsigned long) &a1610a }, // Information for A1610 revsion A. -+ { 0x1B74, 0x0810, 0x1B74, 0x0001, 0, 0, (unsigned long) &a810a }, // Information for A810 revsion A. -+ { 0 } -+}; -+ -+MODULE_DEVICE_TABLE(pci, a24xx_pci_tbl); -+ -+static struct pci_driver a24xx_driver = { -+ .name = "opvxa24xx", -+ .probe = a24xx_init_one, -+ .remove = __devexit_p(a24xx_remove_one), -+ .suspend = NULL, -+ .resume = NULL, -+ .id_table = a24xx_pci_tbl, -+}; -+ -+static int __init a24xx_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; -+ } -+ /* for the voicedaa_check_hook defaults, if the user has not overridden -+ them by specifying them as module parameters, then get the values -+ from the selected operating mode -+ */ -+ 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 = dahdi_pci_module(&a24xx_driver); -+ if (res) { -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static void __exit a24xx_cleanup(void) -+{ -+ pci_unregister_driver(&a24xx_driver); -+} -+ -+module_param(spi_cmd, int, 0600); -+module_param(debug, int, 0600); -+module_param(ec_debug, int, 0600); -+module_param(vpmsupport, int, 0600); -+module_param(loopcurrent, int, 0600); -+module_param(reversepolarity, int, 0600); -+module_param(robust, int, 0600); -+module_param(_opermode, 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(battalarm, uint, 0600); -+module_param(battthresh, uint, 0600); -+module_param(ringdebounce, 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(cidsupport, int, 0600); -+module_param(cidbuflen, int, 0600); -+module_param(cidtimeout, int, 0600); -+module_param(fxofullscale, int, 0600); -+module_param(fixedtimepolarity, int, 0600); -+module_param(ms_per_irq, int, 0600); -+module_param(irq_stub, int, 0600); -+ -+MODULE_DESCRIPTION("OpenVox A2410 Dahdi Driver"); -+MODULE_AUTHOR("MiaoLin <lin.miao@openvox.cn>"); -+MODULE_LICENSE("GPL v2"); -+ -+module_init(a24xx_init); -+module_exit(a24xx_cleanup); -+ diff --git a/dahdi-linux-2.10.1-openvox-2.patch b/dahdi-linux-2.10.1-openvox-2.patch deleted file mode 100644 index 3be86e27c9a4..000000000000 --- a/dahdi-linux-2.10.1-openvox-2.patch +++ /dev/null @@ -1,5851 +0,0 @@ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/base.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/base.h 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,321 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * $Id: base.h 360 2011-04-06 06:11:45Z yangshugang $ -+ -+ * 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. -+ * -+ */ -+ -+ -+#ifndef _OPVXA2410P_H -+#define _OPVXA2410P_H -+ -+#include <dahdi/kernel.h> -+#include <linux/firmware.h> -+ -+#ifndef SLIC_LF_OPEN -+/* Proslic Linefeed options for register 64 - Linefeed Control */ -+#define SLIC_LF_OPEN 0x0 -+#define SLIC_LF_ACTIVE_FWD 0x1 -+#define SLIC_LF_OHTRAN_FWD 0x2 /* Forward On Hook Transfer */ -+#define SLIC_LF_TIP_OPEN 0x3 -+#define SLIC_LF_RINGING 0x4 -+#define SLIC_LF_ACTIVE_REV 0x5 -+#define SLIC_LF_OHTRAN_REV 0x6 /* Reverse On Hook Transfer */ -+#define SLIC_LF_RING_OPEN 0x7 -+ -+#define SLIC_LF_SETMASK 0x7 -+#define SLIC_LF_OPPENDING 0x10 -+ -+/* Mask used to reverse the linefeed mode between forward and -+ * reverse polarity. */ -+#define SLIC_LF_REVMASK 0x4 -+#endif -+ -+struct ec; -+ -+#define VPM_SUPPORT -+ -+#define CARDS_PER_MODULE 4 -+#define MOD_TYPE_FXS 0 -+#define MOD_TYPE_FXO 1 -+ -+#define NUM_FXO_REGS 60 -+#define WC_MAX_IFACES 128 -+#define DEFAULT_RING_DEBOUNCE 64 /* Ringer Debounce (64 ms) */ -+ -+/* the constants below control the 'debounce' periods enforced by the -+ check_hook routines; these routines are called once every 4 interrupts -+ (the interrupt cycles around the four modules), so the periods are -+ specified in _4 millisecond_ increments -+*/ -+#define DEFAULT_BATT_DEBOUNCE 4 /* Battery debounce (64 ms) */ -+#define POLARITY_DEBOUNCE 64 /* Polarity debounce (64 ms) */ -+#define DEFAULT_BATT_THRESH 3 /* Anything under this is "no battery" */ -+ -+#define OHT_TIMER 6000 /* How long after RING to retain OHT */ -+ -+#define NEON_MWI_RNGY_PULSEWIDTH 0x3e8 /*=> period of 250 mS */ -+ -+#define FLAG_3215 (1 << 0) -+ -+#define MAX_NUM_CARDS 24 -+ -+enum cid_hook_state { -+ CID_STATE_IDLE = 0, -+ CID_STATE_RING_DELAY, -+ 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 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 -+ -+ -+#define __CMD_RD (1 << 20) /* Read Operation */ -+#define __CMD_WR (1 << 21) /* Write Operation */ -+#define __CMD_FIN (1 << 22) /* Has finished receive */ -+#define __CMD_TX (1 << 23) /* Has been transmitted */ -+ -+#define CMD_WR(a,b) (((a) << 8) | (b) | __CMD_WR) -+#define CMD_RD(a) (((a) << 8) | __CMD_RD) -+ -+ -+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 a24xx_dev { -+ struct pci_dev *dev; -+ char *variety; -+ 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; -+ struct dahdi_vmwi_info vmwisetting; -+ int vmwi_active_messages; -+ u32 vmwi_lrev:1; /*MWI Line Reversal*/ -+ u32 vmwi_hvdc:1; /*MWI High Voltage DC Idle line*/ -+ u32 vmwi_hvac:1; /*MWI Neon High Voltage AC Idle line*/ -+ u32 neonringing:1;/*Ring Generator is set for NEON*/ -+ int reversepolarity; /* polarity reversal */ -+ spinlock_t lasttxhooklock; -+ } 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 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 */ -+ -+#ifdef TEST_LOG_INCOME_VOICE -+ char * voc_buf[MAX_NUM_CARDS]; -+ int voc_ptr[MAX_NUM_CARDS]; -+#endif -+ unsigned short ledstate; -+ unsigned int fwversion; -+ int max_cards; -+ char *card_name; -+ unsigned int master; -+ -+ 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]; -+ -+#ifdef VPM_SUPPORT -+ struct ec *vpm_ec; -+ int vpm; -+ -+ unsigned long dtmfactive; -+ unsigned long dtmfmask; -+ unsigned long dtmfmutemask; -+ -+#endif -+ -+}; -+ -+struct a24xx_desc { -+ char *name; -+ int flags; -+}; -+ -+struct a24xx { -+ struct a24xx_dev dev; -+ struct dahdi_span span; -+ struct dahdi_chan _chans[MAX_NUM_CARDS]; -+ struct dahdi_chan *chans[MAX_NUM_CARDS]; -+ struct dahdi_echocan_state *ec[32]; /* Echcan state for each channel */ -+ unsigned int index; -+}; -+ -+/* -+ * from bin -+ */ -+extern void __opvx_a24xx_setcreg(unsigned long mem32, unsigned int offset, unsigned int reg, unsigned int val); -+extern unsigned int __opvx_a24xx_getcreg(unsigned long mem32, unsigned int offset, unsigned char reg); -+extern unsigned char __opvx_a24xx_read_8bits(unsigned long mem32); -+ -+extern void __opvx_a24xx_reset_modules(unsigned long mem32, void (*func)(int), int data); -+extern void __opvx_a24xx_reset_modules_v2(unsigned long mem32, void (*func)(int), int data); -+extern void __opvx_a24xx_setcard(unsigned long mem32, int card); -+extern void __opvx_a24xx_reset_spi(void *wc_dev, int card, void (*func)(void*, int)); -+extern void __opvx_a24xx_write_8bits(unsigned long mem32, unsigned char bits); -+ -+extern void __opvx_a24xx_set_master(unsigned long mem32,unsigned int master); -+extern unsigned int __opvx_a24xx_get_master(unsigned long mem32); -+extern void __opvx_a24xx_set_irq_frq(unsigned long mem32,unsigned int frq); -+extern unsigned int __opvx_a24xx_get_version(unsigned long mem32); -+extern unsigned int __opvx_a24xx_get_irqstatus(unsigned long mem32); -+extern void __opvx_a24xx_set_irqstatus(unsigned long mem32, unsigned int value); -+extern void __opvx_a24xx_clear_irqs(unsigned long mem32); -+extern void __opvx_a24xx_enable_interrupts(unsigned long mem32); -+extern void __opvx_a24xx_disable_interrupts(unsigned long mem32); -+extern unsigned int __opvx_a24xx_get_irqcnt_lo(unsigned long mem32); -+ -+extern void __opvx_a24xx_restart_dma(unsigned long mem32); -+extern void __opvx_a24xx_start_dma(unsigned long mem32, unsigned int data); -+extern void __opvx_a24xx_stop_dma(unsigned long mem32); -+extern void __opvx_a24xx_reset_tdm(unsigned long mem32); -+ -+extern void __opvx_a24xx_spi_setreg(void *wc_dev, unsigned long mem32, int card, int modtype, unsigned char reg, unsigned char value, void (*func)(void*, int)); -+extern unsigned char __opvx_a24xx_spi_getreg(void *wc_dev, unsigned long mem32, int card, int modtype, unsigned char reg, void (*func)(void*, int)); -+ -+extern unsigned int __opvx_a24xx_oct_in(unsigned long mem32, unsigned int addr); -+extern unsigned int __opvx_a24xx_oct_in_v2(unsigned long mem32, unsigned int addr); -+extern void __opvx_a24xx_oct_out(unsigned long mem32, unsigned int addr, unsigned int value); -+extern void __opvx_a24xx_oct_out_v2(unsigned long mem32, unsigned int addr, unsigned int value); -+extern int __opvx_a24xx_check_vpm(unsigned long mem32); -+extern int __opvx_a24xx_check_vpm_v2(unsigned long mem32); -+extern void __opvx_a24xx_vpm_setpresent(unsigned long mem32); -+extern void __opvx_a24xx_vpm_setpresent_v2(unsigned long mem32); -+ -+extern void __opvx_a24xx_transmit(unsigned long mem32, volatile unsigned char *writechunk, volatile unsigned char **txbuf,unsigned int irq_frq , unsigned int order); -+extern void __opvx_a24xx_receive(unsigned long mem32, volatile unsigned char *readchunk, volatile unsigned char **rxbuf,unsigned int irq_frq , unsigned int order); -+ -+extern void __opvx_a24xx_set_chunk(void *readchunk, void *writechunk,unsigned int frq); -+ -+/* -+ * from a24xx.c -+ */ -+extern void __a24xx_wait_just_a_bit(int foo); -+extern void __a24xx_spi_setreg(struct a24xx_dev *wc_dev, int card, unsigned char reg, unsigned char value); -+extern unsigned char __a24xx_spi_getreg(struct a24xx_dev *wc_dev, int card, unsigned char reg); -+extern void a24xx_spi_setreg(struct a24xx_dev *wc_dev, int card, unsigned char reg, unsigned char value); -+extern unsigned char a24xx_spi_getreg(struct a24xx_dev *wc_dev, int card, unsigned char reg); -+extern void a24xx_reset_spi(struct a24xx_dev *wc_dev, int card); -+extern void __a24xx_setcard(void *wc_dev, int card); -+extern void oct_set_reg(void *data, unsigned int reg, unsigned int val); -+extern unsigned int oct_get_reg(void *data, unsigned int reg); -+extern void __a24xx_vpm_setpresent(struct a24xx_dev *wc_dev); -+extern int __a24xx_proslic_setreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address, unsigned short data); -+extern int __a24xx_proslic_getreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address); -+extern int __a24xx_malloc_chunk(struct a24xx_dev *wc_dev,unsigned int frq); -+ -+/* -+ * from si321x.c -+ */ -+extern int si321x_init_ring_generator_mode(struct a24xx_dev *wc_dev, int card); -+extern int si321x_set_ring_generator_mode(struct a24xx_dev *wc_dev, int card, int mode); -+extern int si321x_init_proslic(struct a24xx_dev *wc_dev, int card, int fast, int manual, int sane); -+extern int si321x_init_proslic_all(struct a24xx_dev *wc_dev, int fxs_flag,int fast, int manual, int sane,int *blk_flag); -+extern int si321x_proslic_setreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address, unsigned short data); -+extern int si321x_proslic_getreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address); -+extern void si321x_proslic_recheck_sanity(struct a24xx_dev *wc_dev, int card); -+ -+/* -+ * from si3050.c -+ */ -+int si3050_set_hwgain(struct a24xx_dev *wc_dev, int card, __s32 gain, __u32 tx); -+int si3050_init_voicedaa(struct a24xx_dev *wc_dev, int card, int fast, int manual, int sane); -+ -+#endif -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/busydetect.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/busydetect.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,876 @@ -+/* -+ * OpenVox FXO Detect Busy Voice Driver for DAHDI Telephony interface -+ * -+ * Written by kevin.chen -+ -+ * Copyright (C) 2012-2013 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 history -+ * -+ * Rev 0.10 remove structure country_busytone -+ * add GEN_BUSYTONE_ONTIME and GEN_BUSYTONE_OFFTIME -+ * Rev 0.20 fix bug -+ * after frequency is set to a valid value, cannot reset the zero value -+ * Rev 0.30 support new kernel version 3.10.0 -+ * -+ */ -+ -+#include <linux/proc_fs.h> -+#include "busydetect.h" -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) -+#include <linux/seq_file.h> -+#endif -+ -+static const char *module_name = "opvxdsp"; -+static int ref_count = 0; -+ -+#define MAX_TONE_NUM 3 -+#define TONE_FREQ_NUM 2 -+ -+#define GEN_BUSYTONE_ONTIME 500 -+#define GEN_BUSYTONE_OFFTIME 500 -+ -+#define TONE_THRESHOLD 20548 -+#define SILENT_THRESHOLD 2560 -+#define ENERGY_SCALE (FRAME_SHORT_SIZE >> 1) -+ -+struct freq_state { -+ int freq; -+ /* Calculate the sampling data*/ -+ short prev2; -+ short prev; -+ short fac; -+}; -+ -+struct tone { -+ int busycount; -+ int threshold; -+ int ontime; -+ int offtime; -+ struct freq_state fs[TONE_FREQ_NUM]; -+ struct proc_dir_entry *subentry; -+}; -+ -+struct silent_detect { -+ int detect_tx; -+ int detect_rx; -+ /* Mute timeout */ -+ int length; -+ int threshold; -+ struct proc_dir_entry *subentry; -+ -+ /* Statistics mute sample */ -+ u32 tx_samples; -+ u32 rx_samples; -+}; -+ -+struct param { -+ struct tone tone[MAX_TONE_NUM]; -+ struct silent_detect sd; -+}; -+ -+struct detect_state { -+ int index; -+ u32 length; -+}; -+ -+struct dsp_info { -+ /* The read data cache */ -+ short rdata[FRAME_SHORT_SIZE]; -+ int rlen; -+ /* The write data cache */ -+ short wdata[FRAME_SHORT_SIZE]; -+ int wlen; -+ -+ struct param param; -+ struct proc_dir_entry *entry; -+ -+ u32 energy; -+ int count; -+ int detected_tone; -+ struct detect_state state[3]; -+ -+ /* The busy tone appear */ -+ int appear_busy; -+ -+ /* Calculate parameters for generate waveform */ -+ /* Read and write two direction */ -+ int phase[2][TONE_FREQ_NUM]; -+ int is_offtime[2]; -+ int offset[2]; -+}; -+ -+struct detect_info { -+ struct dsp_info dsp[TOTAL_CARDS]; -+ -+ /* Variable for generater waveform */ -+ u32 phase_rate[TONE_FREQ_NUM]; -+ short gain[TONE_FREQ_NUM]; -+ int ontime; -+ int offtime; -+}; -+ -+static struct detect_info *di = NULL; -+ -+static DECLARE_BITMAP(fxo_cardflag, TOTAL_CARDS); -+static DECLARE_BITMAP(fxs_cardflag, TOTAL_CARDS); -+ -+static struct proc_dir_entry *opvxdsp_entry; -+ -+MODULE_LICENSE("GPL v2"); -+MODULE_AUTHOR("Kevin.chen"); -+MODULE_DESCRIPTION("DAHDI detect busy voice"); -+ -+static int detect_is_close(int channo) -+{ -+ int i; -+ struct param *param = &di->dsp[channo - 1].param; -+ -+ for (i = 0; i < MAX_TONE_NUM; i++) { -+ if (param->tone[i].busycount > 0) { -+ return 0; -+ } -+ } -+ -+ if (param->sd.length > 0 && (param->sd.detect_tx || param->sd.detect_rx)) { -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static void reset_dsp_detect_param(struct dsp_info *dsp) -+{ -+ int i; -+ -+ dsp->param.sd.tx_samples = 0; -+ dsp->param.sd.rx_samples = 0; -+ -+ dsp->detected_tone = -1; -+ dsp->count = 0; -+ for (i = 0; i < 3; i++) { -+ dsp->state[i].index = -1; -+ dsp->state[i].length = 0; -+ } -+} -+ -+static void reset_dsp_generate_param(struct dsp_info *dsp) -+{ -+ int i, j; -+ -+ if (dsp->appear_busy) { -+ dsp->appear_busy = 0; -+ -+ for (i = 0; i < 2; i++) { -+ dsp->is_offtime[i] = 0; -+ dsp->offset[i] = 0; -+ for (j = 0; j < TONE_FREQ_NUM; j++) { -+ dsp->phase[i][j] = 0; -+ } -+ } -+ } -+} -+ -+static void update_detect(struct dsp_info *dsp, short s) -+{ -+ int i, j; -+ short tmp; -+ struct freq_state *fs; -+ -+ for (i = 0; i < MAX_TONE_NUM; i++) { -+ if (dsp->param.tone[i].busycount <= 0) { -+ continue; -+ } -+ -+ for (j = 0; j < TONE_FREQ_NUM; j++) { -+ fs = &dsp->param.tone[i].fs[j]; -+ tmp = fs->prev2; -+ fs->prev2 = fs->prev; -+ fs->prev = (((int)fs->fac * fs->prev2) >> 14) - tmp + (s >> 7); -+ } -+ } -+} -+ -+static u32 detect_result(struct freq_state *fs) -+{ -+ u32 val; -+ -+ val = fs->prev * fs->prev + fs->prev2 * fs->prev2 - ((fs->fac * fs->prev) >> 14) * fs->prev2; -+ /* Reset */ -+ fs->prev = fs->prev2 = 0; -+ -+ return val; -+} -+ -+static int busy_detect(struct dsp_info *dsp, int len) -+{ -+ int i, j; -+ u32 power, max_power = 0; -+ int index = -1; -+ -+ for (i = 0; i < MAX_TONE_NUM; i++) { -+ power = 0; -+ for (j = 0; j < TONE_FREQ_NUM; j++) { -+ power += detect_result(&dsp->param.tone[i].fs[j]); -+ } -+ -+ if (dsp->param.tone[i].busycount > 0 && -+ dsp->energy > dsp->param.tone[i].threshold && -+ power > ENERGY_SCALE * dsp->energy) { -+ if (power > max_power) { -+ max_power = power; -+ index = i; -+ } -+ } -+ } -+ -+ if (index != -1 && dsp->detected_tone != index) { -+ dsp->detected_tone = index; -+ dsp->count = 0; -+ for (i = 0; i < 3; i++) { -+ dsp->state[i].index = -1; -+ dsp->state[i].length = 0; -+ } -+ } -+ -+ if (dsp->state[2].index != index) { -+ dsp->state[2].index = index; -+ dsp->state[1].length += len; -+ } else { -+ if (dsp->state[1].index != index) { -+ if (dsp->detected_tone >= 0) { -+ if (dsp->state[0].index == dsp->detected_tone && dsp->state[1].index == -1) { -+ if ((dsp->state[0].length >= dsp->param.tone[dsp->detected_tone].ontime * 8 - FRAME_SHORT_SIZE * 2) && \ -+ (dsp->state[0].length <= dsp->param.tone[dsp->detected_tone].ontime * 8 + FRAME_SHORT_SIZE * 2) && \ -+ (dsp->state[1].length >= dsp->param.tone[dsp->detected_tone].offtime * 8 - FRAME_SHORT_SIZE * 2)) { -+ dsp->count++; -+ if (dsp->count >= dsp->param.tone[dsp->detected_tone].busycount) { -+ return 1; -+ } -+ } -+ } -+ } -+ memmove(&dsp->state[0], &dsp->state[1], 2 * sizeof(dsp->state[0])); -+ dsp->state[1].index = index; -+ dsp->state[1].length = len; -+ } else { -+ dsp->state[1].length += len; -+ } -+ } -+ -+ return 0; -+} -+ -+static int silent_detect(struct dsp_info *dsp, int len, int is_write) -+{ -+ int res = 0; -+ -+ if (dsp->param.sd.length <= 0) { -+ return res; -+ } -+ -+ if (dsp->energy < dsp->param.sd.threshold) { -+ if (is_write) { -+ dsp->param.sd.tx_samples += len; -+ if (dsp->param.sd.tx_samples >= dsp->param.sd.length * SAMPLE_PER_SEC) { -+ res = 1; -+ } -+ } else { -+ dsp->param.sd.rx_samples += len; -+ if (dsp->param.sd.rx_samples >= dsp->param.sd.length * SAMPLE_PER_SEC) { -+ res = 1; -+ } -+ } -+ } else { -+ dsp->param.sd.tx_samples = 0; -+ dsp->param.sd.rx_samples = 0; -+ } -+ -+ return res; -+} -+ -+static short calc_amp(u32 *acc, u32 rate, short scale) -+{ -+ u32 phase, step; -+ short amp; -+ -+ phase = *acc; -+ phase >>= 23; -+ step = phase & (SIN_DIVISION - 1); -+ if ((phase & SIN_DIVISION)) { -+ step = SIN_DIVISION - step; -+ } -+ -+ amp = sin_table[step]; -+ if ((phase & (2 * SIN_DIVISION))) { -+ amp = -amp; -+ } -+ -+ *acc += rate; -+ return (short)(((u32)amp * scale) >> 15); -+} -+ -+static short generater_amp(struct dsp_info *dsp, int is_write) -+{ -+ int i; -+ short amp = 0; -+ int index = (is_write == 0) ? 0 : 1; -+ -+ dsp->offset[index]++; -+ if (!dsp->is_offtime[index]) { -+ for (i = 0; i < TONE_FREQ_NUM; i++) { -+ if (di->phase_rate[i] > 0) { -+ amp += calc_amp(&dsp->phase[index][i], di->phase_rate[i], di->gain[i]); -+ } -+ } -+ if (dsp->offset[index] >= di->ontime * 8) { -+ dsp->offset[index] = 0; -+ dsp->is_offtime[index] = 1; -+ } -+ } else { -+ if (dsp->offset[index] >= di->offtime * 8) { -+ dsp->offset[index] = 0; -+ dsp->is_offtime[index] = 0; -+ } -+ } -+ -+ return amp; -+} -+ -+static void analysis_dsp(struct dsp_info *dsp, short s[], int len, int is_write) -+{ -+ int i, res = 0; -+ u16 temp; -+ -+ for (i = 0; i < len; i++) { -+ temp = (s[i] < 0 ? -s[i] : s[i]) >> 7; -+ dsp->energy += temp * temp; -+ if (!is_write) { -+ update_detect(dsp, s[i]); -+ } -+ } -+ -+ if (is_write) { -+ -+ if (dsp->param.sd.detect_tx) { -+ res = silent_detect(dsp, len, 1); -+ } -+ } else { -+ res = busy_detect(dsp, len); -+ -+ /* Read only support the silent detect */ -+ if (!res && dsp->param.sd.detect_rx) { -+ res = silent_detect(dsp, len, 0); -+ } -+ } -+ -+ dsp->energy = 0; -+ -+ if (res) { -+ dsp->appear_busy = 1; -+ reset_dsp_detect_param(dsp); -+ } -+} -+ -+void parser_busy_silent_process(struct a24xx *wc, int is_write) -+{ -+ int i, j; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ struct dahdi_chan *chan; -+ struct dsp_info *dsp; -+ -+ if (!di) { -+ /* Initialize this module failed */ -+ return; -+ } -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ chan = wc->chans[i]; -+ dsp = &di->dsp[chan->channo - 1]; -+ if (chan->channo > TOTAL_CARDS) { -+ continue; -+ } -+ if ((wc_dev->modtype[i] != MOD_TYPE_FXO) || -+ (wc_dev->modtype[i] == MOD_TYPE_FXO && !wc_dev->mod[i].fxo.offhook)) { -+ reset_dsp_generate_param(dsp); -+ continue; -+ } -+ -+ if (detect_is_close(chan->channo)) { -+ /* The busy tone and silence detection has been closed */ -+ continue; -+ } -+ -+ if (is_write) { -+ if (dsp->appear_busy) { -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ chan->writechunk[j] = DAHDI_LIN2X(generater_amp(dsp, 1), chan); -+ } -+ } else { -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ dsp->wdata[dsp->wlen++] = DAHDI_XLAW(chan->writechunk[j], chan); -+ } -+ if (dsp->wlen == FRAME_SHORT_SIZE) { -+ dsp->wlen = 0; -+ analysis_dsp(dsp, dsp->wdata, FRAME_SHORT_SIZE, 1); -+ } -+ } -+ } else { -+ if (dsp->appear_busy) { -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ chan->readchunk[j] = DAHDI_LIN2X(generater_amp(dsp, 0), chan); -+ } -+ } else { -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ dsp->rdata[dsp->rlen++] = DAHDI_XLAW(chan->readchunk[j], chan); -+ } -+ if (dsp->rlen == FRAME_SHORT_SIZE) { -+ dsp->rlen = 0; -+ analysis_dsp(dsp, dsp->rdata, FRAME_SHORT_SIZE, 0); -+ } -+ } -+ } -+ } -+} -+ -+static short get_fac(int freq) -+{ -+ if (freq < MIN_INDEX_FREQ) { -+ freq = MIN_INDEX_FREQ; -+ } else if (freq > MAX_INDEX_FREQ) { -+ freq = MAX_INDEX_FREQ; -+ } -+ -+ return fac_table[(freq - MIN_INDEX_FREQ) / STEP_FREQ]; -+} -+ -+static u32 get_phase_rate(int freq) -+{ -+ return (freq * 65536 / SAMPLE_PER_SEC) * 65536; -+} -+ -+static short get_gain(int level) -+{ -+ if (level < MIN_INDEX_LEVEL) { -+ level = MIN_INDEX_LEVEL; -+ } else if (level > MAX_INDEX_LEVEL) { -+ level = MAX_INDEX_LEVEL; -+ } -+ -+ return gain_table[(level - MIN_INDEX_LEVEL) / STEP_LEVEL]; -+} -+ -+static void config_proc_param(struct param *param) -+{ -+ int i, j; -+ -+ for (i = 0; i < MAX_TONE_NUM; i++) { -+ param->tone[i].busycount = 0; -+ param->tone[i].threshold = TONE_THRESHOLD; -+ param->tone[i].ontime = 0; -+ param->tone[i].offtime = 0; -+ for (j = 0; j < TONE_FREQ_NUM; j++) { -+ param->tone[i].fs[j].freq = 0; -+ param->tone[i].fs[j].fac = 0; -+ } -+ } -+ param->sd.detect_tx = 0; -+ param->sd.detect_rx = 0; -+ param->sd.length = 30; -+ param->sd.threshold = SILENT_THRESHOLD; -+} -+ -+static void init_detect_info(struct detect_info *di, const char *opermode) -+{ -+ int i, j; -+ -+ di->ontime = GEN_BUSYTONE_ONTIME; -+ di->offtime = GEN_BUSYTONE_OFFTIME; -+ di->phase_rate[0] = get_phase_rate(450); -+ di->gain[0] = get_gain(-12); -+ -+ /* Set default parameters */ -+ for (i = 0; i < TOTAL_CARDS; i++) { -+ config_proc_param(&di->dsp[i].param); -+ -+ di->dsp[i].detected_tone = -1; -+ for (j = 0; j < 3; j++) { -+ di->dsp[i].state[j].index = -1; -+ } -+ } -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int write_param_proc(struct file *filp, const char __user *buf, -+ unsigned long count, void *data) -+#else -+static ssize_t write_param_proc(struct file *file, const char __user *buf, -+ size_t count, loff_t *pos) -+#endif -+{ -+ char temp[24]; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+ int *param = (int *)data; -+#else -+ int *param = PDE_DATA(file_inode(file)); -+#endif -+ int value; -+ int len; -+ -+ len = count > (sizeof(temp) - 1) ? (sizeof(temp) - 1) : count; -+ -+ if (copy_from_user(temp, buf, len)) { -+ return -EFAULT; -+ } -+ -+ temp[len] = '\0'; -+ -+ value = simple_strtoul(temp, NULL, 10); -+ if (value >= 0) { -+ *param = value; -+ } -+ -+ return count; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int read_param_proc(char *buf, char **start, off_t off, int count, -+ int *eof, void *data) -+{ -+ int res; -+ int *param = (int *)data; -+ -+ if (off > 0) { -+ /* We have finished to read, return 0 */ -+ res = 0; -+ } else { -+ res = sprintf(buf, "%d", *param); -+ } -+ -+ return res; -+} -+ -+static void create_param_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ struct proc_dir_entry *entry; -+ -+ entry = create_proc_entry(name, 0644, base); -+ if (entry) { -+ entry->data = data; -+ entry->read_proc = read_param_proc; -+ entry->write_proc = write_param_proc; -+ } -+} -+#else -+static int param_proc_show(struct seq_file *m, void *v) -+{ -+ int *param = (int *)m->private; -+ -+ seq_printf(m, "%d", *param); -+ return 0; -+} -+ -+static int open_param_proc(struct inode *inode, struct file *file) -+{ -+ return single_open(file, param_proc_show, PDE_DATA(inode)); -+} -+ -+static struct file_operations proc_param_fops = { -+ .open = open_param_proc, -+ .read = seq_read, -+ .write = write_param_proc, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void create_param_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ proc_create_data(name, 0644, base, &proc_param_fops, data); -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int write_param_freq_proc(struct file *filp, const char __user *buf, -+ unsigned long count, void *data) -+#else -+static ssize_t write_param_freq_proc(struct file *file, const char __user *buf, -+ size_t count, loff_t *pos) -+#endif -+{ -+ char temp[24]; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+ struct freq_state *fs = (struct freq_state *)data; -+#else -+ struct freq_state *fs = PDE_DATA(file_inode(file)); -+#endif -+ int value; -+ int len; -+ -+ len = count > (sizeof(temp) - 1) ? (sizeof(temp) - 1) : count; -+ -+ if (copy_from_user(temp, buf, len)) { -+ return -EFAULT; -+ } -+ -+ temp[len] = '\0'; -+ -+ value = simple_strtoul(temp, NULL, 10); -+ if (!value || (value >= MIN_INDEX_FREQ && value <= MAX_INDEX_FREQ)) { -+ fs->freq = value; -+ if (fs->freq) { -+ fs->fac = get_fac(fs->freq); -+ } else { -+ fs->fac = 0; -+ } -+ } -+ -+ return count; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int read_param_freq_proc(char *buf, char **start, off_t off, int count, -+ int *eof, void *data) -+{ -+ int res; -+ struct freq_state *fs = (struct freq_state *)data; -+ -+ if (off > 0) { -+ /* We have finished to read, return 0 */ -+ res = 0; -+ } else { -+ res = sprintf(buf, "%d", fs->freq); -+ } -+ -+ return res; -+} -+ -+static void create_param_freq_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ struct proc_dir_entry *entry; -+ -+ entry = create_proc_entry(name, 0644, base); -+ if (entry) { -+ entry->data = data; -+ entry->read_proc = read_param_freq_proc; -+ entry->write_proc = write_param_freq_proc; -+ } -+} -+#else -+static int param_freq_proc_show(struct seq_file *m, void *v) -+{ -+ struct freq_state *fs = (struct freq_state *)m->private; -+ -+ seq_printf(m, "%d", fs->freq); -+ return 0; -+} -+ -+static int open_param_freq_proc(struct inode *inode, struct file *file) -+{ -+ return single_open(file, param_freq_proc_show, PDE_DATA(inode)); -+} -+ -+static struct file_operations proc_param_freq_fops = { -+ .open = open_param_freq_proc, -+ .read = seq_read, -+ .write = write_param_freq_proc, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void create_param_freq_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ proc_create_data(name, 0644, base, &proc_param_freq_fops, data); -+} -+#endif -+ -+/* -+ * \brief parameter -+ * flag: DECLARE_BITMAP structure definition, TOTAL_CARDS length -+ * is_clean: 0 is to create, 1 is to remove -+ */ -+static void rebuild_recur_proc(unsigned long *flag, int is_clean) -+{ -+ int i, j, k; -+ char temp[24]; -+ struct param *param; -+ struct proc_dir_entry *entry, *subentry; -+ -+ if (!opvxdsp_entry) { -+ return; -+ } -+ -+ if (is_clean) { -+ for (i = 0; i < TOTAL_CARDS; i++) { -+ if (test_bit(i, flag)) { -+ entry = di->dsp[i].entry; -+ if (entry) { -+ param = &di->dsp[i].param; -+ for (j = 0; j < MAX_TONE_NUM; j++) { -+ subentry = param->tone[j].subentry; -+ if (subentry) { -+ remove_proc_entry("busycount", subentry); -+ remove_proc_entry("threshold", subentry); -+ remove_proc_entry("ontime", subentry); -+ remove_proc_entry("offtime", subentry); -+ for (k = 0; k < TONE_FREQ_NUM; k++) { -+ sprintf(temp, "frequency%d", k + 1); -+ remove_proc_entry(temp, subentry); -+ } -+ -+ sprintf(temp, "tone%d", j + 1); -+ remove_proc_entry(temp, entry); -+ } -+ } -+ subentry = param->sd.subentry; -+ if (subentry) { -+ remove_proc_entry("detect_tx", subentry); -+ remove_proc_entry("detect_rx", subentry); -+ remove_proc_entry("length", subentry); -+ remove_proc_entry("threshold", subentry); -+ remove_proc_entry("silent_detect", entry); -+ } -+ -+ sprintf(temp, "%d", i + 1); -+ remove_proc_entry(temp, opvxdsp_entry); -+ } -+ } -+ } -+ } else { -+ for (i = 0; i < TOTAL_CARDS; i++) { -+ if (test_bit(i, flag)) { -+ sprintf(temp, "%d", i + 1); -+ entry = proc_mkdir(temp, opvxdsp_entry); -+ di->dsp[i].entry = entry; -+ if (entry) { -+ param = &di->dsp[i].param; -+ for (j = 0; j < MAX_TONE_NUM; j++) { -+ sprintf(temp, "tone%d", j + 1); -+ subentry = proc_mkdir(temp, entry); -+ param->tone[j].subentry = subentry; -+ if (subentry) { -+ create_param_proc("busycount", subentry, ¶m->tone[j].busycount); -+ create_param_proc("threshold", subentry, ¶m->tone[j].threshold); -+ create_param_proc("ontime", subentry, ¶m->tone[j].ontime); -+ create_param_proc("offtime", subentry, ¶m->tone[j].offtime); -+ for (k = 0; k < TONE_FREQ_NUM; k++) { -+ sprintf(temp, "frequency%d", k + 1); -+ create_param_freq_proc(temp, subentry, ¶m->tone[j].fs[k]); -+ } -+ } -+ } -+ subentry = proc_mkdir("silent_detect", entry); -+ param->sd.subentry = subentry; -+ if (subentry) { -+ create_param_proc("detect_tx", subentry, ¶m->sd.detect_tx); -+ create_param_proc("detect_rx", subentry, ¶m->sd.detect_rx); -+ create_param_proc("length", subentry, ¶m->sd.length); -+ create_param_proc("threshold", subentry, ¶m->sd.threshold); -+ } -+ } -+ } -+ } -+ } -+} -+ -+static void set_chan_cards_bit(struct a24xx *wc) -+{ -+ int i, channo; -+ DECLARE_BITMAP(tempflag, TOTAL_CARDS); -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ bitmap_zero(tempflag, TOTAL_CARDS); -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ channo = wc->chans[i]->channo; -+ if (channo <= TOTAL_CARDS) { -+ if (wc_dev->modtype[i] == MOD_TYPE_FXO) { -+ set_bit(channo - 1, fxo_cardflag); -+ set_bit(channo - 1, tempflag); -+ } -+ } -+ } -+ -+ rebuild_recur_proc(tempflag, 0); -+} -+ -+static void clear_chan_cards_bit(struct a24xx *wc) -+{ -+ int i, channo; -+ DECLARE_BITMAP(tempflag, TOTAL_CARDS); -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ bitmap_zero(tempflag, TOTAL_CARDS); -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ channo = wc->chans[i]->channo; -+ if (channo <= TOTAL_CARDS) { -+ if (wc_dev->modtype[i] == MOD_TYPE_FXO) { -+ clear_bit(channo - 1, fxo_cardflag); -+ set_bit(channo - 1, tempflag); -+ } -+ } -+ } -+ -+ rebuild_recur_proc(tempflag, 1); -+} -+ -+int init_busydetect(struct a24xx *wc, const char *opermode) -+{ -+ int res = 0; -+ -+ if (!ref_count++) { -+ bitmap_zero(fxo_cardflag, TOTAL_CARDS); -+ bitmap_zero(fxs_cardflag, TOTAL_CARDS); -+ -+ di = kzalloc(sizeof(*di), GFP_KERNEL); -+ if (!di) { -+ printk(KERN_ERR "Not enough memory, A2410P not support the busy tone and silence detection\n"); -+ res = -ENOMEM; -+ goto out; -+ } -+ -+ init_detect_info(di, opermode); -+ -+ opvxdsp_entry = proc_mkdir(module_name, NULL); -+ -+ printk(KERN_INFO "A2410P start the busy tone and silence detection\n"); -+ } -+ -+ set_chan_cards_bit(wc); -+out: -+ return res; -+} -+ -+void destroy_busydetect(struct a24xx *wc) -+{ -+ if (ref_count) { -+ clear_chan_cards_bit(wc); -+ -+ if (!--ref_count) { -+ if (di) { -+ remove_proc_entry(module_name, NULL); -+ kfree(di); -+ printk(KERN_INFO "A2410P stop the busy tone and silence detection\n"); -+ } -+ } -+ } -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/busydetect.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/busydetect.h 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,313 @@ -+/* -+ * OpenVox FXO Detect Busy Voice Driver for DAHDI Telephony interface -+ * -+ * Written by kevin.chen -+ -+ * Copyright (C) 2012-2013 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. -+ * -+ */ -+ -+#ifndef _BUSYDETECT_H -+#define _BUSYDETECT_H -+ -+#include "base.h" -+ -+#define FRAME_SHORT_SIZE (DAHDI_CHUNKSIZE * 20) -+#define SAMPLE_PER_SEC 8000 -+ -+#define TOTAL_CARDS 120 -+ -+#define SIN_DIVISION 128 -+static const short sin_table[] = -+{ -+ 201, -+ 603, -+ 1005, -+ 1407, -+ 1809, -+ 2210, -+ 2611, -+ 3012, -+ 3412, -+ 3812, -+ 4211, -+ 4609, -+ 5007, -+ 5404, -+ 5800, -+ 6195, -+ 6590, -+ 6983, -+ 7376, -+ 7767, -+ 8157, -+ 8546, -+ 8933, -+ 9319, -+ 9704, -+ 10088, -+ 10469, -+ 10850, -+ 11228, -+ 11605, -+ 11980, -+ 12354, -+ 12725, -+ 13095, -+ 13463, -+ 13828, -+ 14192, -+ 14553, -+ 14912, -+ 15269, -+ 15624, -+ 15976, -+ 16326, -+ 16673, -+ 17018, -+ 17361, -+ 17700, -+ 18037, -+ 18372, -+ 18703, -+ 19032, -+ 19358, -+ 19681, -+ 20001, -+ 20318, -+ 20632, -+ 20943, -+ 21251, -+ 21555, -+ 21856, -+ 22154, -+ 22449, -+ 22740, -+ 23028, -+ 23312, -+ 23593, -+ 23870, -+ 24144, -+ 24414, -+ 24680, -+ 24943, -+ 25202, -+ 25457, -+ 25708, -+ 25956, -+ 26199, -+ 26439, -+ 26674, -+ 26906, -+ 27133, -+ 27357, -+ 27576, -+ 27791, -+ 28002, -+ 28209, -+ 28411, -+ 28610, -+ 28803, -+ 28993, -+ 29178, -+ 29359, -+ 29535, -+ 29707, -+ 29875, -+ 30038, -+ 30196, -+ 30350, -+ 30499, -+ 30644, -+ 30784, -+ 30920, -+ 31050, -+ 31177, -+ 31298, -+ 31415, -+ 31527, -+ 31634, -+ 31737, -+ 31834, -+ 31927, -+ 32015, -+ 32099, -+ 32177, -+ 32251, -+ 32319, -+ 32383, -+ 32442, -+ 32496, -+ 32546, -+ 32590, -+ 32629, -+ 32664, -+ 32693, -+ 32718, -+ 32738, -+ 32753, -+ 32762, -+ 32767, -+ 32767 -+}; -+ -+/* Level index range -30 ~ 0, step 1 */ -+#define MIN_INDEX_LEVEL -30 -+#define MAX_INDEX_LEVEL 0 -+#define STEP_LEVEL 1 -+static const short gain_table[] = { -+ 722, -+ 810, -+ 909, -+ 1020, -+ 1144, -+ 1284, -+ 1440, -+ 1616, -+ 1813, -+ 2034, -+ 2283, -+ 2561, -+ 2874, -+ 3224, -+ 3618, -+ 4059, -+ 4554, -+ 5110, -+ 5734, -+ 6433, -+ 7218, -+ 8099, -+ 9087, -+ 10196, -+ 11440, -+ 12836, -+ 14402, -+ 16160, -+ 18132, -+ 20344, -+ 22826, -+}; -+ -+/* Frequency index range 300 ~ 700, step 5 */ -+#define MIN_INDEX_FREQ 300 -+#define MAX_INDEX_FREQ 700 -+#define STEP_FREQ 5 -+static const short fac_table[] = { -+ 31861, -+ 31830, -+ 31800, -+ 31768, -+ 31737, -+ 31704, -+ 31672, -+ 31638, -+ 31605, -+ 31570, -+ 31536, -+ 31501, -+ 31465, -+ 31429, -+ 31392, -+ 31355, -+ 31318, -+ 31279, -+ 31241, -+ 31202, -+ 31162, -+ 31122, -+ 31082, -+ 31041, -+ 30999, -+ 30958, -+ 30915, -+ 30872, -+ 30829, -+ 30785, -+ 30741, -+ 30696, -+ 30651, -+ 30605, -+ 30559, -+ 30512, -+ 30465, -+ 30417, -+ 30369, -+ 30321, -+ 30272, -+ 30222, -+ 30172, -+ 30122, -+ 30071, -+ 30020, -+ 29968, -+ 29916, -+ 29863, -+ 29810, -+ 29756, -+ 29702, -+ 29648, -+ 29593, -+ 29537, -+ 29481, -+ 29425, -+ 29368, -+ 29311, -+ 29253, -+ 29195, -+ 29136, -+ 29077, -+ 29017, -+ 28957, -+ 28897, -+ 28836, -+ 28775, -+ 28713, -+ 28651, -+ 28588, -+ 28525, -+ 28462, -+ 28398, -+ 28333, -+ 28268, -+ 28203, -+ 28137, -+ 28071, -+ 28005, -+ 27938, -+}; -+ -+/* busydetect.c */ -+void parser_busy_silent_process(struct a24xx *wc, int is_write); -+ -+int init_busydetect(struct a24xx *wc, const char *opermode); -+void destroy_busydetect(struct a24xx *wc); -+ -+/* callerid.c */ -+void parser_callerid_process(struct a24xx *wc, int cidbuflen, int cidtimeout); -+void set_cidstart_desc_from_chan_num(int spanno, int channo, int cid_state); -+void set_signal_unknown_from_chan_num(int spanno, int channo); -+int is_callerid_disable(int spanno, int channo); -+char is_ring_delay_operation(int spanno, int channo); -+void reset_parser_variable_from_chan_num(int spanno, int channo); -+ -+int init_callerid(struct a24xx *wc); -+void destroy_callerid(struct a24xx *wc); -+ -+#endif /* _BUSYDETECT_H */ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/callerid.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/callerid.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,1429 @@ -+/* -+ * OpenVox Calling Identity Delivery Analysis Driver for DAHDI Telephony interface -+ * -+ * Written by kevin.chen -+ -+ * Copyright (C) 2012-2013 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 history -+ * -+ * Rev 0.10 add ringdly_flag variable, deal with special caller id case. -+ * Rev 0.30 support new kernel version 3.10.0 -+ * -+ */ -+ -+#include <linux/proc_fs.h> -+#include <linux/ctype.h> -+#include <linux/kmod.h> -+#include "base.h" -+#include "busydetect.h" /* use sin_table[] */ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) -+#include <linux/seq_file.h> -+#endif -+ -+static int cid_debug = 0; -+module_param(cid_debug, int, 0600); -+ -+/* Before using this directory, the directory must had been created */ -+static const char *module_name = "opvxdsp"; -+ -+#define MAX_CID_LEN 32 -+#define DTMF_BLOCK_SIZE 102 -+#define MAX_DTMF_DIGITS 64 -+ -+#define DTMF_TIMEOUT_SAMPLES (300 * DAHDI_CHUNKSIZE) /* default 300 msec */ -+ -+/* Support signals for caller id */ -+enum { -+ /* Signal type for caller id fsk */ -+ CALLERID_BELL202_OR_V23, -+ CALLERID_V23JP, -+ MAX_FSK_NUM, -+ /* Dtmf signal */ -+ CALLERID_DTMF, -+}; -+ -+/* type for caller id start */ -+enum { -+ CIDSTART_RING = 1, -+ CIDSTART_POLARITY, -+ CIDSTART_POLARITY_IN, -+ CIDSTART_DTMF, -+ MAX_CIDSTART, -+}; -+ -+/* Unknown caller id signal */ -+#define UNKNOWN_CID_SIGNAL -1 -+ -+static const char *signal_desc[] = { -+ [CALLERID_BELL202_OR_V23] = "bell or v23", -+ [CALLERID_V23JP] = "v23_jp", -+ [CALLERID_DTMF] = "dtmf", -+}; -+static const char *cidstart_desc[] = { -+ [CIDSTART_RING] = "ring", -+ [CIDSTART_POLARITY] = "polarity", -+ [CIDSTART_POLARITY_IN] = "polarity_in", -+ [CIDSTART_DTMF] = "dtmf", -+}; -+static const char *unknown_desc = "unknown"; -+ -+static const int dtmf_fac[] = {27978, 26955, 25700, 24217, 19072, 16324, 13084, 9314}; -+static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; -+ -+typedef struct freq_state { -+ short prev2; -+ short prev; -+ short fac; -+}freq_state_t; -+ -+typedef struct callerid_dtmf { -+ freq_state_t row[4]; -+ freq_state_t col[4]; -+ -+ int cur_sample; -+ u32 energy; -+ u8 digit; -+ u8 last_hit; -+ -+ int timeout; -+ -+ /* Analytical results */ -+ char digits[MAX_DTMF_DIGITS + 1]; -+ int num; -+}__attribute__((packed))callerid_dtmf_t; -+ -+typedef struct complex { -+ int re; -+ int im; -+}complex_t; -+ -+typedef struct callerid_fsk { -+ int baud_rate; -+ int baud_frac; -+ int sig_present; -+ int last_bit; -+ -+ int phase_rate[2]; -+ u32 phase_acc[2]; -+ -+ complex_t window[2][24]; -+ complex_t dot[2]; -+ int dot_pos; -+ int span; -+ -+ short last_amp; -+ int power; -+ -+ /* Analytical results */ -+ u8 name[MAX_CID_LEN]; -+ u8 number[MAX_CID_LEN]; -+ -+ int bit_pos; -+ u8 msg[256]; -+ int msg_len; -+ int continuous_one; -+ int val; -+}__attribute__((packed))callerid_fsk_t; -+ -+typedef struct gen_wave { -+ int bit_no; -+ int bit_pos; -+ int byte_no; -+ -+ int occupied_len; -+ int premark_len; -+ int postmark_len; -+ -+ int msg_len; -+ u8 msg[256]; -+ -+ int baud_frac; -+ int baud_rate; -+ -+ int scaling; -+ int phase_rates[2]; -+ u32 phase_acc; -+}__attribute__((packed))gen_wave_t; -+ -+typedef struct callerid { -+ /* Initial current signal unknown */ -+ int cur_sig; -+ /* Generate the signal */ -+ int appear; -+ -+ /* DTMF signal analysis */ -+ callerid_dtmf_t dtmf; -+ /* Variety of fsk signal analysis */ -+ callerid_fsk_t fsk[MAX_FSK_NUM]; -+ -+ /* Structuration for generator waveform */ -+ gen_wave_t gw; -+}__attribute__((packed))callerid_t; -+ -+struct param { -+ /* The pointer of signal description from the last detection */ -+ const char *last_signal; -+ /* The pointer of signal description from the current detection */ -+ const char *detect_signal; -+ /* Signal the start of caller id */ -+ const char *cidstart; -+ /* Close the current channel caller id support */ -+ u8 disable; -+}; -+ -+struct detect_info { -+ int channo; -+ callerid_t cid; -+ -+ /* Initialized to zero do not find any cidstart signal */ -+ char cidstart_type; -+ -+ /* -+ * Sometimes time interval is shorter between signal of caller id end and the next -+ * bell before, so unable to provide a complete signal to asterisk -+ * Set flag to postpone ring tones appears -+ */ -+ char ringdly_flag; -+ -+ struct param param; -+ struct proc_dir_entry *entry; -+ -+ struct list_head list; -+}__attribute__((packed)); -+ -+#define MAX_LIST_SPAN 20 -+static struct list_head di_list[MAX_LIST_SPAN]; -+ -+static void reset_parser_variable_result(callerid_t *cid); -+ -+static const u16 crc16_table[] = { -+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, -+ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, -+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, -+ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, -+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, -+ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, -+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, -+ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, -+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, -+ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, -+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, -+ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, -+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, -+ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, -+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, -+ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, -+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, -+ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, -+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, -+ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, -+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, -+ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, -+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, -+ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, -+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, -+ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, -+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, -+ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, -+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, -+ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, -+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, -+ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -+}; -+ -+static u16 check_crc16(const u8 *buf, int len) -+{ -+ int i; -+ u16 crc = 0; -+ -+ for (i = 0; i < len; i++) { -+ crc = (crc >> 8) ^ crc16_table[(crc ^ buf[i]) & 0xff]; -+ } -+ return crc; -+} -+ -+static int get_phase_rate(int freq) -+{ -+ return (freq * 65536 / SAMPLE_PER_SEC) * 65536; -+} -+ -+static short calc_amp(u32 acc) -+{ -+ u32 phase, step; -+ short amp; -+ -+ phase = acc; -+ phase >>= 23; -+ step = phase & (SIN_DIVISION - 1); -+ if ((phase & SIN_DIVISION)) { -+ step = SIN_DIVISION - step; -+ } -+ -+ amp = sin_table[step]; -+ if ((phase & (2 * SIN_DIVISION))) { -+ amp = -amp; -+ } -+ return amp; -+} -+ -+static void fsk_put_msg(callerid_fsk_t *fsk, const u8 msg[], int len, int sig_type) -+{ -+ int i, pos; -+ int res; -+ -+ memset(fsk->name, 0, sizeof(fsk->name)); -+ memset(fsk->number, 0, sizeof(fsk->number)); -+ if (sig_type == CALLERID_V23JP) { -+ pos = 7; -+ for (i = 0; i < msg[6]; i++) { -+ if (msg[i + pos] == 0x02) { -+ i++; -+ res = (msg[i + pos] <= MAX_CID_LEN) ? msg[i + pos] : MAX_CID_LEN; -+ memcpy(fsk->number, msg + i + pos + 1, res); -+ i += msg[i + pos] + 1; -+ } else { -+ i++; -+ i += msg[i + pos] + 1; -+ } -+ } -+ } else { -+ if (msg[0] == 0x80 || msg[0] == 0x82) { -+ /* MDMF */ -+ pos = 2; -+ for (i = 0; i < msg[1];) { -+ switch (msg[i + pos]) { -+ case 2: -+ case 4: -+ i++; -+ res = (msg[i + pos] <= MAX_CID_LEN) ? msg[i + pos] : MAX_CID_LEN; -+ memcpy(fsk->number, msg + i + pos + 1, res); -+ i += msg[i + pos] + 1; -+ break; -+ case 7: -+ case 8: -+ i++; -+ res = (msg[i + pos] <= MAX_CID_LEN) ? msg[i + pos] : MAX_CID_LEN; -+ memcpy(fsk->name, msg + i + pos + 1, res); -+ i += msg[i + pos] + 1; -+ break; -+ default: -+ i++; -+ i += msg[i + pos] + 1; -+ break; -+ } -+ } -+ } else if (msg[0] == 0x04) { -+ /* SDMF */ -+ if (msg[1] > 8) { -+ memcpy(fsk->number, msg + 10, (msg[1] - 8) <= MAX_CID_LEN ? (msg[1] - 8) : MAX_CID_LEN); -+ } -+ } -+ } -+} -+ -+static void fsk_put_bit(callerid_fsk_t *fsk, int bit, int sig_type) -+{ -+ int i, sum; -+ -+ if (fsk->bit_pos == 0) { -+ if (!bit) { -+ /* Start bit */ -+ fsk->bit_pos++; -+ if (fsk->continuous_one > 10) { -+ fsk->msg_len = 0; -+ } -+ fsk->continuous_one = 0; -+ } else { -+ fsk->continuous_one++; -+ } -+ } else if (fsk->bit_pos <= 8) { -+ fsk->val >>= 1; -+ if (bit) { -+ fsk->val |= 0x80; -+ } -+ fsk->bit_pos++; -+ } else { -+ /* Stop bit */ -+ if (bit && fsk->msg_len < 256) { -+ if (sig_type == CALLERID_V23JP) { -+ if (fsk->msg_len == 0) { -+ if (fsk->val == 0x90) { -+ fsk->msg[fsk->msg_len++] = (u8)fsk->val; -+ } -+ } else { -+ fsk->msg[fsk->msg_len++] = (u8)fsk->val; -+ } -+ if (fsk->msg_len >= 11 && fsk->msg_len == ((fsk->msg[6] & 0x7f) + 11)) { -+ if (check_crc16(fsk->msg + 2, fsk->msg_len - 2) == 0) { -+ for (i = 0; i < fsk->msg_len - 2; i++) { -+ fsk->msg[i] &= 0x7f; -+ } -+ fsk_put_msg(fsk, fsk->msg, fsk->msg_len - 2, sig_type); -+ } -+ fsk->msg_len = 0; -+ } -+ } else { -+ fsk->msg[fsk->msg_len++] = (u8)fsk->val; -+ if (fsk->msg_len >= 3 && fsk->msg_len == (fsk->msg[1] + 3)) { -+ sum = 0; -+ for (i = 0; i < fsk->msg_len - 1; i++) { -+ sum += fsk->msg[i]; -+ } -+ if (256 - (sum & 0xff) == fsk->msg[i]) { -+ fsk_put_msg(fsk, fsk->msg, fsk->msg_len - 1, sig_type); -+ } -+ fsk->msg_len = 0; -+ } -+ } -+ } /* if (bit && fsk->msg_len < 256) */ -+ -+ fsk->bit_pos = 0; -+ fsk->val = 0; -+ } -+} -+ -+static void analysis_fsk(callerid_fsk_t *fsk, short amp[], int len, int sig_type) -+{ -+ int i, j; -+ int dot_pos; -+ int hit_bit; -+ short x; -+ int dot; -+ int sum[2]; -+ complex_t ph; -+ -+ dot_pos = fsk->dot_pos; -+ -+ for (i = 0; i < len; i++) { -+ for (j = 0; j < 2; j++) { -+ fsk->dot[j].re -= fsk->window[j][dot_pos].re; -+ fsk->dot[j].im -= fsk->window[j][dot_pos].im; -+ -+ ph.re = calc_amp(fsk->phase_acc[j] + (1 << 30)); -+ ph.im = calc_amp(fsk->phase_acc[j]); -+ fsk->phase_acc[j] += fsk->phase_rate[j]; -+ fsk->window[j][dot_pos].re = (ph.re * amp[i]) >> 3; -+ fsk->window[j][dot_pos].im = (ph.im * amp[i]) >> 3; -+ -+ fsk->dot[j].re += fsk->window[j][dot_pos].re; -+ fsk->dot[j].im += fsk->window[j][dot_pos].im; -+ -+ dot = fsk->dot[j].re >> 15; -+ sum[j] = dot * dot; -+ dot = fsk->dot[j].im >> 15; -+ sum[j] += dot * dot; -+ } -+ -+ x = (amp[i] >> 1) - fsk->last_amp; -+ fsk->power += ((x * x - fsk->power) >> 4); -+ fsk->last_amp = amp[i] >> 1; -+ if (fsk->sig_present) { -+ /* calc result 36380=pow(10.0,(level-14.7)/10.0)*32767.0*32767.0, level=-30 */ -+ if (fsk->power < 36380) { -+ fsk->sig_present = 0; -+ fsk->baud_frac = 0; -+ continue; -+ } -+ } else { -+ /* calc result 115046=pow(10.0,(level-9.7)/10.0)*32767.0*32767.0, level=-30 */ -+ if (fsk->power < 115046) { -+ fsk->baud_frac = 0; -+ continue; -+ } -+ -+ fsk->sig_present = 1; -+ fsk->baud_frac = 0; -+ fsk->last_bit = 0; -+ } -+ -+ hit_bit = (sum[0] < sum[1]); -+ if (fsk->last_bit != hit_bit) { -+ fsk->last_bit = hit_bit; -+ fsk->baud_frac = (SAMPLE_PER_SEC >> 1); -+ } -+ -+ fsk->baud_frac += fsk->baud_rate; -+ if (fsk->baud_frac >= SAMPLE_PER_SEC) { -+ fsk->baud_frac -= SAMPLE_PER_SEC; -+ fsk_put_bit(fsk, hit_bit, sig_type); -+ } -+ -+ if (++dot_pos >= fsk->span) { -+ dot_pos = 0; -+ } -+ } -+ -+ fsk->dot_pos = dot_pos; -+} -+ -+static inline u32 detect_result(freq_state_t *fs) -+{ -+ u32 val; -+ -+ val = fs->prev * fs->prev + fs->prev2 * fs->prev2 - ((fs->fac * fs->prev) >> 14) * fs->prev2; -+ fs->prev = fs->prev2 = 0; -+ -+ return val; -+} -+ -+static inline void update_detect(freq_state_t *fs, short s) -+{ -+ short tmp; -+ -+ tmp = fs->prev2; -+ fs->prev2 = fs->prev; -+ fs->prev = (((int)fs->fac * fs->prev2) >> 14) - tmp + (s >> 7); -+} -+ -+static void get_dtmf_number(callerid_dtmf_t *dtmf, u8 number[]) -+{ -+ int i; -+ int code; -+ char *p = dtmf->digits; -+ -+ if (dtmf->num < 2) { -+ return; -+ } -+ -+ if (p[0] == 'B') { -+ code = simple_strtoul(p + 1, NULL, 10); -+ if (code == 0) { -+ /* Unknown caller id number */ -+ number[0] = 'O'; -+ } else if (code == 10) { -+ /* Private caller id number */ -+ number[0] = 'P'; -+ } -+ } else if (p[0] == 'D' && p[2] == '#') { -+ if (p[1] == '1') { -+ /* Private caller id number */ -+ number[0] = 'P'; -+ } else if (p[1] == '2' || p[2] == '3') { -+ /* Unknown caller id number */ -+ number[0] = 'O'; -+ } -+ } else if (p[0] == 'D' || p[0] == 'A') { -+ for (i = 1; i < dtmf->num; i++) { -+ if (p[i] == 'C' || p[i] == '#') { -+ break; -+ } -+ if (isdigit(p[i]) && i <= MAX_CID_LEN) { -+ number[i - 1] = p[i]; -+ } -+ } -+ } else if (isdigit(p[0])) { -+ for (i = 0; i < dtmf->num; i++) { -+ if (isdigit(p[i]) && i < MAX_CID_LEN) { -+ number[i] = p[i]; -+ } else { -+ break; -+ } -+ } -+ } else { -+ /* Unknown caller id number */ -+ number[0] = 'O'; -+ } -+} -+ -+static void analysis_dtmf(callerid_dtmf_t *dtmf, short s[], int len) -+{ -+ int i, j, k; -+ int limit; -+ short temp; -+ int row_energy[4]; -+ int col_energy[4]; -+ int best_row, best_col; -+ u8 hit; -+ -+ for (i = 0; i < len; i = limit) { -+ if (len - i >= DTMF_BLOCK_SIZE - dtmf->cur_sample) { -+ limit = i + DTMF_BLOCK_SIZE - dtmf->cur_sample; -+ } else { -+ limit = len; -+ } -+ -+ for (j = i; j < limit; j++) { -+ temp = (s[j] < 0 ? -s[j] : s[j]) >> 7; -+ dtmf->energy += temp * temp; -+ for (k = 0; k < 4; k++) { -+ update_detect(&dtmf->row[k], s[j]); -+ update_detect(&dtmf->col[k], s[j]); -+ } -+ } -+ -+ dtmf->cur_sample += (limit - i); -+ if (dtmf->cur_sample < DTMF_BLOCK_SIZE) { -+ break; -+ } -+ -+ row_energy[0] = detect_result(&dtmf->row[0]); -+ col_energy[0] = detect_result(&dtmf->col[0]); -+ best_row = 0; -+ best_col = 0; -+ for (j = 1; j < 4; j++) { -+ row_energy[j] = detect_result(&dtmf->row[j]); -+ if (row_energy[j] > row_energy[best_row]) { -+ best_row = j; -+ } -+ col_energy[j] = detect_result(&dtmf->col[j]); -+ if (col_energy[j] > col_energy[best_col]) { -+ best_col = j; -+ } -+ } -+ -+ hit = 0; -+ if (row_energy[best_row] >= 10438 && -+ col_energy[best_col] >= 10438 && -+ col_energy[best_col] < row_energy[best_row] * 2 && -+ col_energy[best_col] * 6 > row_energy[best_row]) { -+ for (j = 0; j < 4; j++) { -+ if ((j != best_row && row_energy[j] * 6 > row_energy[best_row]) || -+ (j != best_col && col_energy[j] * 6 > col_energy[best_col])) { -+ break; -+ } -+ } -+ if (j >= 4 && ((row_energy[best_row] + col_energy[best_col]) > 42 * dtmf->energy)) { -+ hit = dtmf_positions[(best_row << 2) + best_col]; -+ } -+ } -+ -+ if (hit) { -+ dtmf->timeout = 0; -+ } else { -+ dtmf->timeout += DTMF_BLOCK_SIZE; -+ } -+ -+ if (hit != dtmf->digit) { -+ if (dtmf->last_hit != dtmf->digit) { -+ hit = (hit && hit == dtmf->last_hit) ? hit : 0; -+ if (hit) { -+ if (dtmf->num < MAX_DTMF_DIGITS) { -+ dtmf->digits[dtmf->num++] = (char)hit; -+ dtmf->digits[dtmf->num] = '\0'; -+ } -+ } -+ dtmf->digit = hit; -+ } -+ } -+ dtmf->last_hit = hit; -+ dtmf->energy = 0; -+ dtmf->cur_sample = 0; -+ } -+} -+ -+static const u16 mon_yday[2][13] = { -+ /* Normal year */ -+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, -+ /* Leap year */ -+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, -+}; -+ -+static void get_systime_val(int *mon, int *mday, int *hour, int *min) -+{ -+ struct timeval tv; -+ const u16 *ip; -+ int days, rem, y; -+ int yg; -+ -+ do_gettimeofday(&tv); -+ -+#define SECS_PER_HOUR (60 * 60) -+#define SECS_PER_DAY (SECS_PER_HOUR * 24) -+ days = tv.tv_sec / SECS_PER_DAY; -+ rem = tv.tv_sec % SECS_PER_DAY; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) -+ extern struct timezone sys_tz; -+#endif -+ rem += (-sys_tz.tz_minuteswest * 60); -+ while (rem < 0) { -+ rem += SECS_PER_DAY; -+ days--; -+ } -+ while (rem > SECS_PER_DAY) { -+ rem -= SECS_PER_DAY; -+ days++; -+ } -+ -+ *hour = rem / SECS_PER_HOUR; -+ rem %= SECS_PER_HOUR; -+ *min = rem / 60; -+ -+#define IS_LEAP(y) (((y) % 4 == 0) && ((y) % 100 != 0 || (y) % 400 == 0)) -+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) -+#define LEAP_BETWEEN(y) (DIV(y, 4) - DIV(y, 100) + DIV(y, 400)) -+ y = 1970; -+ while (days < 0 || days >= (IS_LEAP(y) ? 366 : 365)) { -+ yg = y + DIV(days, 365); -+ days -= ((yg - y) * 365 + LEAP_BETWEEN(yg - 1) - LEAP_BETWEEN(y - 1)); -+ y = yg; -+ } -+ -+ ip = mon_yday[IS_LEAP(y)]; -+ for (y = 11; days < ip[y]; y--) { -+ continue; -+ } -+ days -= ip[y]; -+ -+ *mon = y + 1; -+ *mday = days + 1; -+} -+ -+static int build_msg(u8 *msg, const char *number, const char *name) -+{ -+ int i, res; -+ int len; -+ int mon, mday, hour, min; -+ int sum = 0; -+ u8 *ptr = msg + 2; -+ -+ get_systime_val(&mon, &mday, &hour, &min); -+ res = sprintf(ptr, "\001\010%02d%02d%02d%02d", mon, mday, hour, min); -+ ptr += res; -+ -+ if (strlen(number)) { -+ len = strlen(number); -+ res = sprintf(ptr, "\002%c", len); -+ ptr += res; -+ for (i = 0; i < len; i++) { -+ ptr[i] = number[i]; -+ } -+ ptr[i] = '\0'; -+ ptr += len; -+ } else { -+ res = sprintf(ptr, "\004\001O"); -+ ptr += res; -+ } -+ -+ if (strlen(name)) { -+ len = strlen(name); -+ res = sprintf(ptr, "\007%c", len); -+ ptr += res; -+ for (i = 0; i < len; i++) { -+ ptr[i] = name[i]; -+ } -+ ptr[i] = '\0'; -+ ptr += len; -+ } else { -+ res = sprintf(ptr, "\010\001O"); -+ ptr += res; -+ } -+ -+ msg[0] = 0x80; -+ msg[1] = ptr - msg - 2; -+ -+ for (i = 0; i < ptr - msg; i++) { -+ sum += msg[i]; -+ } -+ msg[ptr - msg] = 256 - (sum & 0xff); -+ ptr++; -+ -+ return (ptr - msg); -+} -+ -+static int fsk_get_bit(gen_wave_t *gw) -+{ -+ int bit; -+ -+ if (gw->bit_no < gw->occupied_len) { -+ bit = gw->bit_no & 1; -+ gw->bit_no++; -+ } else if (gw->bit_no < gw->occupied_len + gw->premark_len) { -+ bit = 1; -+ gw->bit_no++; -+ } else if (gw->bit_no == gw->occupied_len + gw->premark_len) { -+ if (gw->bit_pos == 0) { -+ /* Start bit */ -+ bit = 0; -+ gw->bit_pos++; -+ } else if (gw->bit_pos <= 8) { -+ bit = (gw->msg[gw->byte_no] >> (gw->bit_pos - 1)) & 1; -+ gw->bit_pos++; -+ } else { -+ /* Stop bit */ -+ bit = 1; -+ gw->bit_pos = 0; -+ if (++gw->byte_no >= gw->msg_len) { -+ gw->bit_no++; -+ } -+ } -+ } else if (gw->bit_no <= gw->occupied_len + gw->premark_len + gw->postmark_len) { -+ bit = 1; -+ gw->bit_no++; -+ } else { -+ /* Completion */ -+ bit = -1; -+ } -+ -+ return bit; -+} -+ -+static short generater_amp(u32 *phase_acc, int phase_rate, int scale) -+{ -+ short amp; -+ -+ amp = (short)(((int)calc_amp(*phase_acc) * scale) >> 15); -+ *phase_acc += phase_rate; -+ return amp; -+} -+ -+static int fsk_gen(gen_wave_t *gw, short amp[], int len) -+{ -+ int i = 0; -+ int bit = 0; -+ static int cur_bit = 1; -+ int cur_phase_rate; -+ -+ cur_phase_rate = gw->phase_rates[cur_bit]; -+ while (i < len) { -+ if ((gw->baud_frac += gw->baud_rate) >= SAMPLE_PER_SEC) { -+ gw->baud_frac -= SAMPLE_PER_SEC; -+ bit = fsk_get_bit(gw); -+ if (bit == -1) { -+ /* Completion */ -+ cur_bit = 1; -+ break; -+ } -+ cur_bit = bit & 1; -+ cur_phase_rate = gw->phase_rates[cur_bit]; -+ } -+ amp[i++] = generater_amp(&gw->phase_acc, cur_phase_rate, gw->scaling); -+ } -+ -+ return bit; -+} -+ -+static void analysis_all_signal(callerid_t *cid, short s[], int len) -+{ -+ int i; -+ -+ analysis_dtmf(&cid->dtmf, s, len); -+ for (i = 0; i < MAX_FSK_NUM; i++) { -+ analysis_fsk(&cid->fsk[i], s, len, i); -+ } -+} -+ -+static void analysis_current_signal(callerid_t *cid, short s[], int len) -+{ -+ switch (cid->cur_sig) { -+ case CALLERID_BELL202_OR_V23: -+ case CALLERID_V23JP: -+ analysis_fsk(&cid->fsk[cid->cur_sig], s, len, cid->cur_sig); -+ break; -+ case CALLERID_DTMF: -+ analysis_dtmf(&cid->dtmf, s, len); -+ break; -+ default: /* UNKNOWN_CID_SIGNAL */ -+ /* signal of caller id is unknown, re-check */ -+ analysis_all_signal(cid, s, len); -+ break; -+ } -+} -+ -+static struct detect_info *get_detect_info_from_chan_num(int spanno, int channo) -+{ -+ struct detect_info *di; -+ -+ if (spanno <= 0 || spanno > MAX_LIST_SPAN) { -+ return NULL; -+ } -+ -+ list_for_each_entry(di, &di_list[spanno - 1], list) { -+ if (di->channo == channo) { -+ /* Find the corresponding matching */ -+ return di; -+ } -+ } -+ -+ return NULL; -+} -+ -+static void set_signal_desc(struct detect_info *di) -+{ -+ di->param.last_signal = di->param.detect_signal; -+ -+ switch (di->cid.cur_sig) { -+ case CALLERID_BELL202_OR_V23: -+ case CALLERID_V23JP: -+ case CALLERID_DTMF: -+ di->param.detect_signal = signal_desc[di->cid.cur_sig]; -+ break; -+ default: /* UNKNOWN_CID_SIGNAL */ -+ di->param.detect_signal = unknown_desc; -+ break; -+ } -+} -+ -+void set_signal_unknown_from_chan_num(int spanno, int channo) -+{ -+ struct detect_info *di; -+ -+ di = get_detect_info_from_chan_num(spanno, channo); -+ if (di) { -+ /* Default standard does not analyze the current signal */ -+ di->cid.cur_sig = UNKNOWN_CID_SIGNAL; -+ set_signal_desc (di); -+ /* set the ring delay flag */ -+ if (di->cid.dtmf.num > 1) { -+ di->ringdly_flag = 1; -+ } else { -+ di->ringdly_flag = di->cid.appear > 0 ? 1 : 0; -+ } -+ } -+} -+ -+char is_ring_delay_operation(int spanno, int channo) -+{ -+ struct detect_info *di; -+ -+ di = get_detect_info_from_chan_num(spanno, channo); -+ if (di) { -+ return di->ringdly_flag; -+ } else { -+ return 0; -+ } -+} -+ -+static void clear_cidstart_type(struct detect_info *di) -+{ -+ di->cidstart_type = 0; -+} -+ -+static void set_cidstart_desc_force(struct detect_info *di, int type) -+{ -+ if (type >= CIDSTART_RING && type < MAX_CIDSTART) { -+ di->cidstart_type = type; -+ di->param.cidstart = cidstart_desc[type]; -+ } -+} -+ -+static void set_cidstart_desc(struct detect_info *di, int type) -+{ -+ if (!di->cidstart_type) { -+ /* Cidstart signal has not yet appeared */ -+ if (type >= CIDSTART_RING && type < MAX_CIDSTART) { -+ di->cidstart_type = type; -+ di->param.cidstart = cidstart_desc[type]; -+ } -+ } -+} -+ -+void set_cidstart_desc_from_chan_num(int spanno, int channo, int cid_state) -+{ -+ int type; -+ struct detect_info *di; -+ -+ if(cid_state == CID_STATE_IDLE) { -+ type = CIDSTART_POLARITY; -+ } else { -+ type = CIDSTART_POLARITY_IN; -+ } -+ -+ di = get_detect_info_from_chan_num(spanno, channo); -+ if (di) { -+ set_cidstart_desc(di, type); -+ } -+} -+ -+int is_callerid_disable(int spanno, int channo) -+{ -+ int res = 0; -+ struct detect_info *di; -+ -+ di = get_detect_info_from_chan_num(spanno, channo); -+ if (di) { -+ res = di->param.disable; -+ } -+ -+ return res; -+} -+ -+static void print_cidinfo(u8 *number, u8 *name) -+{ -+ struct timeval tv; -+ int mon, mday, hour, min; -+ -+ do_gettimeofday(&tv); -+ get_systime_val(&mon, &mday, &hour, &min); -+ printk(KERN_INFO "cid infor: %02d-%02d %02d:%02d number=%s, name=%s\n", mon, mday, hour, min, number, name); -+} -+ -+static void check_callerid_signal(struct detect_info *di, int timeout) -+{ -+ int i, res = 0; -+ callerid_fsk_t *fsk; -+ u8 name[MAX_CID_LEN + 1]; -+ u8 number[MAX_CID_LEN + 1]; -+ callerid_t *cid = &di->cid; -+ -+ if (cid->appear) { -+ /* Last time we have found signal of caller id, directly to exit */ -+ return; -+ } -+ memset(name, 0, sizeof(name)); -+ memset(number, 0, sizeof(number)); -+ if (cid->dtmf.num > 1) { -+ if (cid->dtmf.timeout >= timeout) { -+ get_dtmf_number(&cid->dtmf, number); -+ cid->cur_sig = CALLERID_DTMF; -+ set_cidstart_desc(di, CIDSTART_DTMF); -+ res = 1; -+ } -+ } else { -+ for (i = 0; i < MAX_FSK_NUM; i++) { -+ fsk = &cid->fsk[i]; -+ if (strlen(fsk->number)) { -+ memcpy(number, fsk->number, MAX_CID_LEN); -+ memcpy(name, fsk->name, MAX_CID_LEN); -+ if (cid->dtmf.num == 1) { -+ set_cidstart_desc_force(di, CIDSTART_DTMF); -+ } -+ cid->cur_sig = i; -+ res = 1; -+ break; -+ } -+ } -+ } -+ -+ if (res) { -+ if (strlen(number)) { -+ cid->gw.msg_len = build_msg(cid->gw.msg, number, name); -+ cid->appear = 1; -+ set_signal_desc(di); -+ if (cid_debug) { -+ print_cidinfo(number, name); -+ } -+ } -+ } -+} -+ -+void reset_parser_variable_from_chan_num(int spanno, int channo) -+{ -+ struct detect_info *di; -+ -+ di = get_detect_info_from_chan_num(spanno, channo); -+ if (di) { -+ reset_parser_variable_result(&di->cid); -+ } -+} -+ -+static int generate_callerid(callerid_t *cid, short s[], int len) -+{ -+ if (fsk_gen(&cid->gw, s, len) == -1) { -+ /* Signal of caller id stop transmission */ -+ reset_parser_variable_result(cid); -+ return 0; -+ } else { -+ return 1; -+ } -+} -+ -+void parser_callerid_process(struct a24xx *wc, int cidbuflen, int cidtimeout) -+{ -+ int i, j; -+ /* Analytical work to ensure that within the ring tones */ -+#define LENGTH_PER_PTR (10 * DAHDI_CHUNKSIZE) -+ short data[LENGTH_PER_PTR]; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ struct dahdi_chan *chan; -+ struct detect_info *di; -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ if (wc_dev->modtype[i] == MOD_TYPE_FXO && !wc_dev->mod[i].fxo.offhook) { -+ chan = wc->chans[i]; -+ if (wc_dev->cid_state[i] == CID_STATE_IDLE || -+ wc_dev->cid_state[i] == CID_STATE_RING_DELAY) { -+ /* We need copy data to the caller id voice buffer */ -+ memcpy(wc_dev->cid_history_buf[i] + wc_dev->cid_history_ptr[i], chan->readchunk, DAHDI_CHUNKSIZE); -+ wc_dev->cid_history_ptr[i] = (wc_dev->cid_history_ptr[i] + DAHDI_CHUNKSIZE)%(cidbuflen * DAHDI_MAX_CHUNKSIZE); -+ di = get_detect_info_from_chan_num(wc->span.spanno, chan->channo); -+ if (di && !di->param.disable) { -+ /* Empty data to prevent interference */ -+ memset(chan->readchunk, DAHDI_LIN2X(0, chan), DAHDI_CHUNKSIZE); -+ } -+ } else if (wc_dev->cid_state[i] == CID_STATE_RING_ON) { -+ di = get_detect_info_from_chan_num(wc->span.spanno, chan->channo); -+ if (di) { -+ if (wc_dev->cid_history_clone_cnt[i] > 0) { -+ for (j = 0; j < LENGTH_PER_PTR; j++) { -+ data[j] = DAHDI_XLAW(*(u8 *)(wc_dev->cid_history_buf[i] + wc_dev->cid_history_ptr[i] + j), chan); -+ } -+ analysis_current_signal(&di->cid, data, LENGTH_PER_PTR); -+ wc_dev->cid_history_clone_cnt[i] -= (LENGTH_PER_PTR / DAHDI_CHUNKSIZE); -+ if (wc_dev->cid_history_clone_cnt[i] < 0) { -+ wc_dev->cid_history_clone_cnt[i] = 0; -+ } -+ wc_dev->cid_history_ptr[i] = (wc_dev->cid_history_ptr[i] + LENGTH_PER_PTR)%(cidbuflen * DAHDI_MAX_CHUNKSIZE); -+ } else if (wc_dev->cid_history_clone_cnt[i] == 0) { -+ check_callerid_signal(di, 0); -+ wc_dev->cid_history_clone_cnt[i] = -1; -+ } -+ } -+ } else if (wc_dev->cid_state[i] == CID_STATE_RING_OFF) { -+ di = get_detect_info_from_chan_num(wc->span.spanno, chan->channo); -+ if (di) { -+ if (di->cid.appear) { -+ set_cidstart_desc(di, CIDSTART_RING); -+ if (generate_callerid(&di->cid, data, DAHDI_CHUNKSIZE)) { -+ if (!di->param.disable) { -+ /* Create effective caller id signal */ -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ chan->readchunk[j] = DAHDI_LIN2X(data[j], chan); -+ } -+ } -+ } else { -+ clear_cidstart_type(di); -+ wc_dev->cid_state[i] = CID_STATE_WAIT_RING_FINISH; -+ wc_dev->cid_history_clone_cnt[i] = cidtimeout; -+ } -+ } else { -+ for (j = 0; j < DAHDI_CHUNKSIZE; j++) { -+ data[j] = DAHDI_XLAW(chan->readchunk[j], chan); -+ if (!di->param.disable) { -+ /* Empty data to prevent repeated parsing */ -+ chan->readchunk[j] = DAHDI_LIN2X(0, chan); -+ } -+ } -+ analysis_current_signal(&di->cid, data, DAHDI_CHUNKSIZE); -+ check_callerid_signal(di, DTMF_TIMEOUT_SAMPLES); -+ } /* if (di->cid.appear) */ -+ } -+ } else if (wc_dev->cid_state[i] == CID_STATE_WAIT_RING_FINISH) { -+ if (wc_dev->cid_history_clone_cnt[i] > 0) { -+ wc_dev->cid_history_clone_cnt[i]--; -+ } else { -+ wc_dev->cid_state[i] = CID_STATE_IDLE; -+ } -+ } -+ } -+ } -+} -+ -+static void reset_parser_variable_result(callerid_t *cid) -+{ -+ int i; -+ callerid_dtmf_t *dtmf; -+ callerid_fsk_t *fsk; -+ gen_wave_t *gw; -+ -+ /* Generate the signal reset */ -+ cid->appear = 0; -+ -+ /* Reset the dtmf analytical variables and results */ -+ dtmf = &cid->dtmf; -+ memset(dtmf, 0, sizeof(*dtmf)); -+ for (i = 0; i < 4; i++) { -+ dtmf->row[i].fac = dtmf_fac[i]; -+ dtmf->col[i].fac = dtmf_fac[4 + i]; -+ } -+ -+ /* Reset the variety of fsk analytical variables and results */ -+ for (i = 0; i < MAX_FSK_NUM; i++) { -+ fsk = &cid->fsk[i]; -+ memset(fsk, 0, sizeof(*fsk)); -+ fsk->baud_rate = 1200; -+ fsk->span = SAMPLE_PER_SEC / fsk->baud_rate; -+ if (i == CALLERID_BELL202_OR_V23) { -+ fsk->phase_rate[0] = get_phase_rate(2200); -+ fsk->phase_rate[1] = get_phase_rate(1200); -+ } else { -+ fsk->phase_rate[0] = get_phase_rate(2100); -+ fsk->phase_rate[1] = get_phase_rate(1300); -+ } -+ } -+ -+ /* Reset the waveform analytical variables and results */ -+ fsk = &cid->fsk[CALLERID_BELL202_OR_V23]; -+ gw = &cid->gw; -+ memset(gw, 0, sizeof(*gw)); -+ gw->occupied_len = 300; -+ gw->premark_len = 180; -+ gw->postmark_len = 60; -+ gw->scaling = 2873; /* pow(10.0,(level-3.14)/20.0)*32767.0, level=-14 */ -+ gw->baud_rate = fsk->baud_rate; -+ gw->phase_rates[0] = fsk->phase_rate[0]; -+ gw->phase_rates[1] = fsk->phase_rate[1]; -+} -+ -+static void init_callerid_info(struct detect_info *di, int channo) -+{ -+ /* Save channel number */ -+ di->channo = channo; -+ -+ INIT_LIST_HEAD(&di->list); -+ -+ /* Initial description of the parameters are unknown */ -+ di->param.detect_signal = unknown_desc; -+ di->param.last_signal = unknown_desc; -+ di->param.cidstart = unknown_desc; -+ -+ /* Initial signal is unknown */ -+ di->cid.cur_sig = UNKNOWN_CID_SIGNAL; -+ -+ /* Initialize dtmf, variety of fsk, waveform parameters */ -+ reset_parser_variable_result(&di->cid); -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int read_param_proc(char *buf, char **start, off_t off, int count, -+ int *eof, void *data) -+{ -+ int res; -+ const char **p = (const char **)data; -+ -+ if (off > 0) { -+ /* We have finished to read, return 0 */ -+ res = 0; -+ } else { -+ res = sprintf(buf, "%s", *p); -+ } -+ -+ return res; -+} -+ -+static void create_param_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ struct proc_dir_entry *entry; -+ -+ entry = create_proc_entry(name, 0444, base); -+ if (entry) { -+ entry->data = (void *)data; -+ entry->read_proc = read_param_proc; -+ } -+} -+#else -+static int param_proc_show(struct seq_file *m, void *v) -+{ -+ const char **p = (const char **)m->private; -+ -+ seq_printf(m, "%s", *p); -+ return 0; -+} -+ -+static int open_param_proc(struct inode *inode, struct file *file) -+{ -+ return single_open(file, param_proc_show, PDE_DATA(inode)); -+} -+ -+static struct file_operations proc_param_fops = { -+ .open = open_param_proc, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void create_param_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ proc_create_data(name, 0444, base, &proc_param_fops, data); -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int write_param_off_proc(struct file *file, const char __user *buf, -+ unsigned long count, void *data) -+#else -+static ssize_t write_param_off_proc(struct file *file, const char __user *buf, -+ size_t count, loff_t *pos) -+#endif -+{ -+ char temp[24]; -+ int newval, len; -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+ u8 *val = (u8 *)data; -+#else -+ u8 *val = PDE_DATA(file_inode(file)); -+#endif -+ -+ len = count > (sizeof(temp) - 1) ? (sizeof(temp) - 1) : count; -+ -+ if (copy_from_user(temp, buf, len)) { -+ return -EFAULT; -+ } -+ -+ temp[len] = '\0'; -+ -+ newval = simple_strtoul(temp, NULL, 10); -+ *val = newval > 0 ? 1 : 0; -+ -+ return count; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static int read_param_off_proc(char *buf, char **start, off_t off, int count, -+ int *eof, void *data) -+{ -+ int res; -+ u8 *val = (u8 *)data; -+ -+ if (off > 0) { -+ /* We have finished to read, return 0 */ -+ res = 0; -+ } else { -+ res = sprintf(buf, "%d", *val); -+ } -+ -+ return res; -+} -+ -+static void create_param_off_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ struct proc_dir_entry *entry; -+ -+ entry = create_proc_entry(name, 0644, base); -+ if (entry) { -+ entry->data = data; -+ entry->read_proc = read_param_off_proc; -+ entry->write_proc = write_param_off_proc; -+ } -+} -+#else -+static int param_off_proc_show(struct seq_file *m, void *v) -+{ -+ u8 *val = (u8 *)m->private; -+ -+ seq_printf(m, "%d", *val); -+ return 0; -+} -+ -+static int open_param_off_proc(struct inode *inode, struct file *file) -+{ -+ return single_open(file, param_off_proc_show, PDE_DATA(inode)); -+} -+ -+static struct file_operations proc_param_off_fops = { -+ .open = open_param_off_proc, -+ .read = seq_read, -+ .write = write_param_off_proc, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void create_param_off_proc(const char *name, struct proc_dir_entry *base, void *data) -+{ -+ proc_create_data(name, 0644, base, &proc_param_off_fops, data); -+} -+#endif -+ -+/* -+ * \brief parameter -+ * is_clean: 0 is to create, 1 is to remove -+ */ -+static void rebuild_callerid_proc(struct detect_info *di, int is_clean) -+{ -+ char temp[24]; -+ struct proc_dir_entry *entry; -+ -+ if (is_clean) { -+ entry = di->entry; -+ if (entry) { -+ remove_proc_entry("last_signal", entry); -+ remove_proc_entry("detect_signal", entry); -+ remove_proc_entry("cidstart", entry); -+ remove_proc_entry("disable", entry); -+ -+ sprintf(temp, "%s/%d/opencid", module_name, di->channo); -+ remove_proc_entry(temp, NULL); -+ } -+ } else { -+ sprintf(temp, "%s/%d/opencid", module_name, di->channo); -+ entry = proc_mkdir(temp, NULL); -+ di->entry = entry; -+ if (entry) { -+ create_param_proc("last_signal", entry, &di->param.last_signal); -+ create_param_proc("detect_signal", entry, &di->param.detect_signal); -+ create_param_proc("cidstart", entry, &di->param.cidstart); -+ create_param_off_proc("disable", entry, &di->param.disable); -+ } -+ } -+} -+ -+static void release_callerid_resource(struct a24xx *wc) -+{ -+ int i; -+ struct detect_info *cur, *next; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ -+ if (wc->span.spanno <= 0 || wc->span.spanno > MAX_LIST_SPAN) { -+ return; -+ } -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ if (wc_dev->modtype[i] == MOD_TYPE_FXO) { -+ list_for_each_entry_safe(cur, next, &di_list[wc->span.spanno - 1], list) { -+ if (cur->channo == wc->chans[i]->channo) { -+ /* Find the corresponding matching */ -+ list_del(&cur->list); -+ rebuild_callerid_proc(cur, 1); -+ kfree(cur); -+ break; -+ } -+ } -+ } -+ } -+} -+ -+/* Called after created the top-level parameters directory "module_name" */ -+int init_callerid(struct a24xx *wc) -+{ -+ int i, res = 0; -+ struct detect_info *di; -+ struct a24xx_dev *wc_dev = &wc->dev; -+ static int first_in = 1; -+ -+ if (first_in) { -+ first_in = 0; -+ for (i = 0; i < MAX_LIST_SPAN; i++) { -+ INIT_LIST_HEAD(&di_list[i]); -+ } -+ } -+ -+ if (wc->span.spanno <= 0 || wc->span.spanno > MAX_LIST_SPAN) { -+ return -ENXIO; -+ } -+ -+ for (i = 0; i < wc_dev->max_cards; i++) { -+ if (wc_dev->modtype[i] == MOD_TYPE_FXO) { -+ di = kzalloc(sizeof(*di), GFP_KERNEL); -+ if (!di) { -+ printk(KERN_ERR "Not enough memory, A2410P not support the calling identity delivery analysis"); -+ res = -ENOMEM; -+ goto out; -+ } -+ -+ init_callerid_info(di, wc->chans[i]->channo); -+ rebuild_callerid_proc(di, 0); -+ -+ list_add(&di->list, &di_list[wc->span.spanno - 1]); -+ } -+ } -+ -+ return 0; -+out: -+ release_callerid_resource(wc); -+ return res; -+} -+ -+/* Called before the release of the top-level parameters directory "module_name" */ -+void destroy_callerid(struct a24xx *wc) -+{ -+ release_callerid_resource(wc); -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/ec3000.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/ec3000.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,589 @@ -+/* -+ * Copyright (C) 2005-2006 Digium, Inc. -+ * -+ * Mark Spencer <markster@digium.com> -+ * Mark liu <mark.liu@openvox.cn> -+ * -+ * $Id: ec3000.c 159 2010-12-08 03:27:04Z liuyuan $ -+ * 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 "ec3000.h" -+#include "oct6100api/oct6100_api.h" -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) -+#include <linux/config.h> -+#endif -+ -+/* API for Octasic access */ -+UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime) -+{ -+ /* Why couldn't they just take a timeval like everyone else? */ -+ struct timeval tv; -+ unsigned long long total_usecs; -+ unsigned int mask = ~0; -+ -+ do_gettimeofday(&tv); -+ total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) + -+ (((unsigned long long)(tv.tv_usec))); -+ f_pTime->aulWallTimeUs[0] = (total_usecs & mask); -+ f_pTime->aulWallTimeUs[1] = (total_usecs >> 32); -+ return cOCT6100_ERR_OK; -+} -+ -+UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength) -+{ -+ memset(f_pAddress, f_ulPattern, f_ulLength); -+ return cOCT6100_ERR_OK; -+} -+ -+UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength) -+{ -+ memcpy(f_pDestination, f_pSource, f_ulLength); -+ return cOCT6100_ERR_OK; -+} -+ -+UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate) -+{ -+ return cOCT6100_ERR_OK; -+} -+ -+UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy) -+{ -+#ifdef OCTASIC_DEBUG -+ printk("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 ec { -+ 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 opvx_vpm_setecmode(struct ec *ec, int channel, int mode) -+{ -+ tOCT6100_CHANNEL_MODIFY *modify; -+ UINT32 ulResult; -+ -+ if (ec->ecmode[channel] == mode) -+ return; -+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); -+ if (!modify) { -+ printk("opvxa24xx: Unable to allocate memory for setec!\n"); -+ return; -+ } -+ Oct6100ChannelModifyDef(modify); -+ modify->ulEchoOperationMode = mode; -+ modify->ulChannelHndl = ec->aulEchoChanHndl[channel]; -+ ulResult = Oct6100ChannelModify(ec->pApiInstance, modify); -+ if (ulResult != GENERIC_OK) { -+ printk("Failed to apply echo can changes on channel %d, 0x%x!\n", channel, ulResult); -+ } else { -+#ifdef OCTASIC_DEBUG -+ printk("Echo can on channel %d set to %d\n", channel, mode); -+#endif -+ ec->ecmode[channel] = mode; -+ } -+ kfree(modify); -+} -+ -+void opvx_vpm_setdtmf(struct ec *ec, int channel, int detect, int mute) -+{ -+ tOCT6100_CHANNEL_MODIFY *modify; -+ UINT32 ulResult; -+ -+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL); -+ if (!modify) { -+ printk("opvxa24xx: Unable to allocate memory for setdtmf!\n"); -+ return; -+ } -+ Oct6100ChannelModifyDef(modify); -+ modify->ulChannelHndl = ec->aulEchoChanHndl[channel]; -+ if (mute) { -+ ec->chanflags[channel] |= FLAG_MUTE; -+ modify->VqeConfig.fDtmfToneRemoval = TRUE; -+ } else { -+ ec->chanflags[channel] &= ~FLAG_MUTE; -+ modify->VqeConfig.fDtmfToneRemoval = FALSE; -+ } -+ if (detect) -+ ec->chanflags[channel] |= FLAG_DTMF; -+ else -+ ec->chanflags[channel] &= ~FLAG_DTMF; -+ if (ec->chanflags[channel] & (FLAG_DTMF|FLAG_MUTE)) { -+ if (!(ec->chanflags[channel] & FLAG_ECHO)) { -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE); -+ } -+ } else { -+ if (!(ec->chanflags[channel] & FLAG_ECHO)) -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_DIGITAL); -+ } -+ -+ ulResult = Oct6100ChannelModify(ec->pApiInstance, modify); -+ if (ulResult != GENERIC_OK) { -+ printk("Failed to apply dtmf mute changes on channel %d!\n", channel); -+ } -+/* printk("VPM450m: Setting DTMF on channel %d: %s / %s\n", channel, (detect ? "DETECT" : "NO DETECT"), (mute ? "MUTE" : "NO MUTE")); */ -+ kfree(modify); -+} -+ -+ -+void opvx_vpm_setec(struct ec *ec, int channel, int eclen) -+{ -+ if (eclen) { -+ ec->chanflags[channel] |= FLAG_ECHO; -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_NORMAL); -+ } else { -+ ec->chanflags[channel] &= ~FLAG_ECHO; -+ if (ec->chanflags[channel] & (FLAG_DTMF | FLAG_MUTE)) { -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_HT_RESET); -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_HT_FREEZE); -+ } else -+ opvx_vpm_setecmode(ec, channel, cOCT6100_ECHO_OP_MODE_DIGITAL); -+ } -+/* printk("VPM450m: Setting EC on channel %d to %d\n", channel, eclen); */ -+} -+ -+int opvx_vpm_checkirq(struct ec *ec) -+{ -+ tOCT6100_INTERRUPT_FLAGS InterruptFlags; -+ -+ Oct6100InterruptServiceRoutineDef(&InterruptFlags); -+ Oct6100InterruptServiceRoutine(ec->pApiInstance, &InterruptFlags); -+ -+ return InterruptFlags.fToneEventsPending ? 1 : 0; -+} -+ -+int opvx_vpm_getdtmf(struct ec *ec, 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(ec->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("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 opvx_vpm_getcapacity(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 ec *opvx_vpm_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 ec *ec; -+ int x,y,law; -+#ifdef CONFIG_4KSTACKS -+ unsigned long flags; -+#endif -+ -+ if (!(ec = kmalloc(sizeof(struct ec), GFP_KERNEL))) -+ return NULL; -+ -+ memset(ec, 0, sizeof(struct ec)); -+ -+ if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) { -+ kfree(ec); -+ return NULL; -+ } -+ -+ memset(ChipOpen, 0, sizeof(tOCT6100_CHIP_OPEN)); -+ -+ if (!(ChannelOpen = kmalloc(sizeof(tOCT6100_CHANNEL_OPEN), GFP_KERNEL))) { -+ kfree(ec); -+ kfree(ChipOpen); -+ return NULL; -+ } -+ -+ memset(ChannelOpen, 0, sizeof(tOCT6100_CHANNEL_OPEN)); -+ -+ for (x=0;x<128;x++) -+ ec->ecmode[x] = -1; -+ -+ ec->numchans = numspans * 32; -+ printk("OpenVox VPM: echo cancellation for %d channels\n", ec->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 = ec->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(ec); -+ kfree(ChipOpen); -+ kfree(ChannelOpen); -+ return NULL; -+ } -+ -+ -+ ec->pApiInstance = vmalloc(InstanceSize.ulApiInstanceSize); -+ if (!ec->pApiInstance) { -+ printk("Out of memory (can't allocate %d bytes)!\n", InstanceSize.ulApiInstanceSize); -+ kfree(ec); -+ 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(ec->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(ec); -+ 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 (( numspans > 2) || ((x & 0x03) <2)) { -+ //if ((x & 0x03) < numspans) { -+ if ( x < ec->numchans) { -+ if (isalaw[x / 24]) // each span have 24 channels, it is spec for the 24 channel card. miaolin -+ law = cOCT6100_PCM_A_LAW; -+ else -+ law = cOCT6100_PCM_U_LAW; -+ Oct6100ChannelOpenDef(ChannelOpen); -+ ChannelOpen->pulChannelHndl = &ec->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(ec->pApiInstance, ChannelOpen); -+ if (ulResult != GENERIC_OK) { -+ printk("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 = ec->aulEchoChanHndl[x]; -+ enable.ulToneNumber = tones[y]; -+ if (Oct6100ToneDetectionEnable(ec->pApiInstance, &enable) != GENERIC_OK) -+ printk("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 ec; -+} -+ -+void opvx_vpm_release(struct ec *ec) -+{ -+ UINT32 ulResult; -+ tOCT6100_CHIP_CLOSE ChipClose; -+ -+ Oct6100ChipCloseDef(&ChipClose); -+ ulResult = Oct6100ChipClose(ec->pApiInstance, &ChipClose); -+ if (ulResult != cOCT6100_ERR_OK) { -+ printk("Failed to close chip, code %08x!\n", ulResult); -+ } -+ vfree(ec->pApiInstance); -+ kfree(ec); -+} -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/ec3000.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/ec3000.h 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,50 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * Written by mark.liu<mark.liu@openvox.cn> -+ * $Id: ec3000.h 165 2010-12-09 05:38:49Z liuyuan $ -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _EC3000_H_ -+#define _EC3000_H_ -+ -+#include <linux/firmware.h> -+ -+struct ec; -+ -+/* 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 */ -+extern void opvx_vpm_setec(struct ec *ec, int channel, int eclen); -+extern void opvx_vpm_setdtmf(struct ec *ec, int channel, int detect, int mute); -+extern int opvx_vpm_getdtmf(struct ec *ec, int *channel, int *tone, int *start); -+extern int opvx_vpm_checkirq(struct ec *ec); -+extern unsigned int opvx_vpm_getcapacity(void *wc); -+ -+extern struct ec *opvx_vpm_init(void *wc, int *isalaw, int numspans, const struct firmware *firmware); -+extern void opvx_vpm_release(struct ec *ec); -+ -+#endif -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/private.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/private.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,513 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * Written by mark.liu<mark.liu@openvox.cn> -+ * $Id: private.c 446 2011-05-12 04:01:57Z liuyuan $ -+ * -+ * 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. -+ * -+ */ -+ -+//#ifdef VPM_SUPPORT -+/* ec debug */ -+extern int ec_debug; -+extern int vpmsupport; -+//#endif -+#define PEDANTIC_OCTASIC_CHECKING -+ -+#define ZT_CHUNKSIZE 8 -+#define ZT_MIN_CHUNKSIZE ZT_CHUNKSIZE -+#define ZT_DEFAULT_CHUNKSIZE ZT_CHUNKSIZE -+#define ZT_MAX_CHUNKSIZE ZT_CHUNKSIZE -+ -+#define MAX_NUM_CARDS 24 -+ -+#define CARDS_PER_MODULE 4 -+#define MOD_TYPE_FXS 0 -+#define MOD_TYPE_FXO 1 -+ -+ -+/* register base address */ -+#define REG_BASE 0x00000000 -+#define PIO_BASE 0x000004e0 -+#define TDM0_BASE 0x00000400 -+#define SPI_PCM_BASE 0x000004a0 -+#define TDM_MEM_BASE 0x00001000 -+#define PCI_BASE 0x00004000 -+ -+/* swap memory offset */ -+#define OPVX_RUN 0x0 -+#define OPVX_FWREADY 0x1 -+#define OPVX_FWVERSION 0x2 -+#define OPVX_DMA_REG 0x3 -+#define OPVX_ERR_REG 0x4 -+#define OPVX_IRQ_CNT_LO 0x5 -+#define OPVX_IRQ_CNT_HI 0x6 -+#define OPVX_BURST_SIZE 0x7 -+#define OPVX_BURST_INTERVAL 0x8 -+#define OPVX_PCI_IRQ_FRQ 0x9 -+#define OPVX_CARD_MASTER 0xa -+#define OPVX_IRQ_COMMAND 0xb -+#define OPVX_VPM_PRESENT 0x12 -+#define V2_OPVX_PIO_DATA 0x1c -+#define OPVX_TEST 0x1f -+#define V2_EC_BASE 0x00000100 -+ -+/* irq status register */ -+#define OPVX_IRQ_STATUS (0x40>>2) /* irq status register */ -+#define OPVX_IRQ_ENABLE (0x50>>2) /* irq status register */ -+ -+/* PIO register offset */ -+#define OPVX_PIO_DATA 0 -+#define OPVX_PIO_DIR 1 -+#define OPVX_PIO_CNTL 2 -+ -+/* SPI register offset */ -+#define OPVX_SPI_IN 0 -+#define OPVX_SPI_OUT 1 -+#define OPVX_SPI_STATUS 2 -+#define OPVX_SPI_CNTL 3 -+#define OPVX_SPI_CS 5 -+/* ec controller base addr */ -+#define EC_BASE 0x00000540 -+ -+#define OPVX_EC_CNTL 0 -+#define OPVX_EC_DATA 1 -+#define OPVX_EC_VPM 2 -+ -+/* echo canceller stuff */ -+#define BIT_EC_ADDR_STAGE (1<<0) -+#define BIT_EC_CS (1<<1) -+#define BIT_EC_WR (1<<2) -+#define BIT_EC_RD (1<<3) -+#define BIT_EC_ALE (1<<4) -+#define BIT_EC_RDY (1<<5) -+#define BIT_EC_DAS (1<<6) -+#define BIT_EC_IRQ (1<<7) -+ -+#define BIT_EC_PRESENT (1<<0) -+ -+void __opvx_a24xx_setcreg(unsigned long mem32, unsigned int offset, unsigned int reg, unsigned int val) -+{ -+ //printk("writing offset %d, reg %d at %d, value %d\n", offset, reg, offset + (reg<<2), val); -+ unsigned int *p = (unsigned int*)(mem32 + offset + (reg<<2)); -+ *p = val; -+} -+ -+unsigned int __opvx_a24xx_getcreg(unsigned long mem32, unsigned int offset, unsigned char reg) -+{ -+ //printk("reding offset %d, reg %d at %d\n", offset, reg, offset + (reg<<2)); -+ volatile unsigned int *p = (unsigned int*)(mem32 + offset + (reg<<2)); -+ return (*p); -+} -+ -+unsigned char __opvx_a24xx_read_8bits(unsigned long mem32) -+{ -+ unsigned int res=0; -+ -+ while((__opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_STATUS)&0x40)!=0x40); -+ __opvx_a24xx_setcreg(mem32, SPI_PCM_BASE, OPVX_SPI_OUT, 0); /* we have to write something so the spi can work */ -+ while( (__opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_STATUS)&0x80) != 0x80); /* wait rx finish */ -+ res = __opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_IN); -+ -+ return res&0xff; -+} -+ -+void __opvx_a24xx_start_dma(unsigned long mem32, unsigned int data) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_DMA_REG, data); -+} -+ -+void __opvx_a24xx_stop_dma(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_DMA_REG, 0xffffffff); // -1 means stop dma. -+} -+ -+void __opvx_a24xx_restart_dma(unsigned long mem32) -+{ -+ /* Reset Master and TDM */ -+ // TODO: do our work here. -+} -+ -+void __opvx_a24xx_reset_tdm(unsigned long mem32) -+{ -+ /* Reset TDM */ -+ //TODO: do our work here; -+} -+ -+void __opvx_a24xx_set_irq_frq(unsigned long mem32,unsigned int frq) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_PCI_IRQ_FRQ,frq); -+} -+void __opvx_a24xx_set_master(unsigned long mem32,unsigned int master) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_CARD_MASTER,master); -+} -+unsigned int __opvx_a24xx_get_master(unsigned long mem32) -+{ -+ return __opvx_a24xx_getcreg(mem32, REG_BASE, OPVX_CARD_MASTER); -+} -+ -+unsigned int __opvx_a24xx_get_version(unsigned long mem32) -+{ -+ return __opvx_a24xx_getcreg(mem32, REG_BASE, OPVX_FWVERSION); -+} -+ -+unsigned int __opvx_a24xx_get_irqstatus(unsigned long mem32) -+{ -+ return __opvx_a24xx_getcreg(mem32, PCI_BASE, OPVX_IRQ_STATUS); -+} -+ -+void __opvx_a24xx_set_irqstatus(unsigned long mem32, unsigned int value) -+{ -+ __opvx_a24xx_setcreg(mem32, PCI_BASE, OPVX_IRQ_STATUS, value); // clear interrupt register. -+} -+ -+void __opvx_a24xx_clear_irqs(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, PCI_BASE, OPVX_IRQ_STATUS, 0xffffffff); /* clear all pending irqs */ -+ __opvx_a24xx_setcreg(mem32, SPI_PCM_BASE, OPVX_SPI_CNTL, 0); /* init spi port */ -+} -+ -+void __opvx_a24xx_enable_interrupts(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_BURST_INTERVAL, 0); -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_BURST_SIZE, 2); -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_RUN, 1); -+} -+ -+void __opvx_a24xx_disable_interrupts(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_RUN, 0); -+} -+ -+unsigned int __opvx_a24xx_get_irqcnt_lo(unsigned long mem32) -+{ -+ return __opvx_a24xx_getcreg(mem32, REG_BASE, OPVX_IRQ_CNT_LO); -+} -+ -+void __opvx_a24xx_reset_modules(unsigned long mem32, void (*func)(int), int data) -+{ -+ __opvx_a24xx_setcreg(mem32, PIO_BASE, OPVX_PIO_DIR, 0xffffffff); /* all io as output */ -+ __opvx_a24xx_setcreg(mem32, PIO_BASE, OPVX_PIO_CNTL, 0); /* disable irq */ -+ -+// if(debug) { -+// printk("opvxa24xx: raise reset\n"); -+// } -+ -+ __opvx_a24xx_setcreg(mem32, PIO_BASE, OPVX_PIO_DATA, 0x1); /* GPIO0 As reset*/ -+ /* Wait for 1 second */ -+ -+ (*func)(data/2); /* delay 1/2 sec */ -+ -+ __opvx_a24xx_setcreg(mem32, PIO_BASE, OPVX_PIO_DATA, 0x0); /* GPIO0 As reset*/ -+// if(debug) { -+// printk("opvxa24xx: pull down reset\n"); -+// } -+ -+ (*func)(data/2); /* delay 1/2 sec */ -+ -+ __opvx_a24xx_setcreg(mem32, PIO_BASE, OPVX_PIO_DATA, 0x1); /* GPIO0 As reset*/ -+// if(debug) { -+// printk("opvxa24xx: raise reset finally\n"); -+// } -+ -+ (*func)(data/2); /* delay 1/2 sec */ -+} -+ -+ -+void __opvx_a24xx_write_8bits(unsigned long mem32, unsigned char bits) -+{ -+ volatile unsigned int t; -+ -+ while((__opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_STATUS)&0x40)!=0x40); -+ __opvx_a24xx_setcreg(mem32, SPI_PCM_BASE, OPVX_SPI_OUT, bits); /* we have to write something so the spi can work */ -+ while( (__opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_STATUS)&0x40) != 0x40); /* wait tx finish */ -+ t = __opvx_a24xx_getcreg(mem32, SPI_PCM_BASE, OPVX_SPI_IN); -+} -+ -+static inline void __reset_spi(void *wc_dev) -+{ -+ return; /* we do nothing here */ -+} -+ -+ -+void __opvx_a24xx_setcard(unsigned long mem32, int card) -+{ -+ __opvx_a24xx_setcreg(mem32, SPI_PCM_BASE, OPVX_SPI_CS, 1<<(card/CARDS_PER_MODULE)); -+} -+ -+void __opvx_a24xx_reset_spi(void *wc_dev, int card, void (*func)(void*, int)) -+{ -+ (*func)(wc_dev, card); -+ __reset_spi(wc_dev); -+ __reset_spi(wc_dev); -+} -+ -+static inline int __opvx_a24xx_hit_fxo_daisy(int number_daisy) -+{ -+ int cid; -+ -+ if (number_daisy==0) { -+ cid=0; -+ } else if (number_daisy==1) { -+ cid=0x8; -+ } else if (number_daisy==2) { -+ cid=0x4; -+ } else if (number_daisy==3) { -+ cid=0xc; -+ } else { -+ cid= -1; -+ } -+ -+ return cid; -+} -+ -+void __opvx_a24xx_spi_setreg(void *wc_dev, unsigned long mem32, int card, int modtype, unsigned char reg, unsigned char value, void (*func)(void*, int)) -+{ -+ (*func)(wc_dev, card); -+ if (modtype == MOD_TYPE_FXO) { -+ __opvx_a24xx_write_8bits(mem32, 0x20 | __opvx_a24xx_hit_fxo_daisy(card%CARDS_PER_MODULE)); // fxo daisy operate. -+ __opvx_a24xx_write_8bits(mem32, reg & 0x7f); -+ } else { -+ __opvx_a24xx_write_8bits(mem32, 1<<(card%CARDS_PER_MODULE)); // fxs daisy operate. -+ __opvx_a24xx_write_8bits(mem32, reg & 0x7f); -+ } -+ __opvx_a24xx_write_8bits(mem32, value); -+} -+ -+unsigned char __opvx_a24xx_spi_getreg(void *wc_dev, unsigned long mem32, int card, int modtype, unsigned char reg, void (*func)(void*, int)) -+{ -+ (*func)(wc_dev, card); -+ if (modtype == MOD_TYPE_FXO) { -+ __opvx_a24xx_write_8bits(mem32, 0x60 | __opvx_a24xx_hit_fxo_daisy(card%CARDS_PER_MODULE)); // fxo daisy operate. -+ __opvx_a24xx_write_8bits(mem32, reg & 0x7f); -+ } else { -+ __opvx_a24xx_write_8bits(mem32, 1<<(card%CARDS_PER_MODULE)); // fxs daisy operate. -+ __opvx_a24xx_write_8bits(mem32, reg | 0x80); -+ } -+ return __opvx_a24xx_read_8bits(mem32); -+} -+ -+ -+static inline void __a24xx_raw_oct_out(unsigned long mem32, const unsigned int addr, const unsigned int value) -+{ -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE | BIT_EC_WR); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE | BIT_EC_WR | BIT_EC_ALE); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_DATA, value); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, BIT_EC_WR | BIT_EC_ALE | BIT_EC_CS); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, 0); -+} -+ -+static inline unsigned int __a24xx_raw_oct_in(unsigned long mem32, const unsigned int addr) -+{ -+ unsigned int ret; -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE | BIT_EC_WR); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE | BIT_EC_WR | BIT_EC_ALE); -+#ifdef PEDANTIC_OCTASIC_CHECKING -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, (addr<<16) | BIT_EC_ADDR_STAGE | BIT_EC_ALE); -+#endif -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, BIT_EC_RD | BIT_EC_ALE | BIT_EC_CS); -+ ret = __opvx_a24xx_getcreg(mem32, EC_BASE, OPVX_EC_DATA); -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_CNTL, 0); -+ -+ return ret&0xffff; -+} -+ -+unsigned int __opvx_a24xx_oct_in(unsigned long mem32, unsigned int addr) -+{ -+#ifdef PEDANTIC_OCTASIC_CHECKING -+ int count = 1000; -+#endif -+ __a24xx_raw_oct_out(mem32, 0x0008, (addr >> 20)); -+ __a24xx_raw_oct_out(mem32, 0x000a, (addr >> 4) & ((1 << 16) - 1)); -+ __a24xx_raw_oct_out(mem32, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1)); -+#ifdef PEDANTIC_OCTASIC_CHECKING -+ while((__a24xx_raw_oct_in(mem32, 0x0000) & (1 << 8)) && --count); -+ if (count != 1000) { -+// printk("Yah, read can be slow...\n"); -+ } -+ if (!count) { -+// printk("Read timed out!\n"); -+ } -+#endif -+ return __a24xx_raw_oct_in(mem32, 0x0004); -+} -+ -+void __opvx_a24xx_oct_out(unsigned long mem32, unsigned int addr, unsigned int value) -+{ -+#ifdef PEDANTIC_OCTASIC_CHECKING -+ int count = 1000; -+#endif -+ __a24xx_raw_oct_out(mem32, 0x0008, (addr >> 20)); -+ __a24xx_raw_oct_out(mem32, 0x000a, (addr >> 4) & ((1 << 16) - 1)); -+ __a24xx_raw_oct_out(mem32, 0x0004, value); -+ __a24xx_raw_oct_out(mem32, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1); -+#ifdef PEDANTIC_OCTASIC_CHECKING -+ while((__a24xx_raw_oct_in(mem32, 0x0000) & (1 << 8)) && --count); -+ if (count != 1000) { -+// printk("Yah, write can be slow\n"); -+ } -+ if (!count) { -+// printk("Write timed out!\n"); -+ } -+#endif -+} -+ -+int __opvx_a24xx_check_vpm(unsigned long mem32) -+{ -+ unsigned int check1, check2; -+ -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_VPM, 0); //disable vpm support at first. -+ -+ if (!vpmsupport) { -+// printk("OpenVox VPM: Support Disabled\n"); -+ return -1; -+ } -+ -+ __a24xx_raw_oct_out(mem32, 0x000a, 0x5678); -+ __a24xx_raw_oct_out(mem32, 0x0004, 0x1234); -+ check1 = __a24xx_raw_oct_in(mem32, 0x0004); -+ check2 = __a24xx_raw_oct_in(mem32, 0x000a); -+ -+// if (ec_debug) { -+// printk("OCT Result: %04x/%04x\n", __a24xx_raw_oct_in(mem32, 0x0004), __a24xx_raw_oct_in(mem32, 0x000a)); -+// } -+ -+ if (__a24xx_raw_oct_in(mem32, 0x0004) != 0x1234) { -+// printk("OpenVox VPM: Not Present\n"); -+ return -2; -+ } -+ -+ return 0; -+} -+ -+void __opvx_a24xx_vpm_setpresent(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, EC_BASE, OPVX_EC_VPM, BIT_EC_PRESENT); -+} -+ -+void __opvx_a24xx_set_chunk(void *readchunk, void *writechunk,unsigned int frq,int buf_mult) -+{ -+ unsigned char *tmp; -+ tmp = *((unsigned char **)(writechunk)) + frq * ZT_MAX_CHUNKSIZE * (MAX_NUM_CARDS) * 2; /* in bytes */ -+ *(char **)readchunk = tmp; -+} -+ -+void __opvx_a24xx_transmit(unsigned long mem32, volatile unsigned char *writechunk, volatile unsigned char **txbuf,unsigned int irq_frq , unsigned int order) -+{ -+ unsigned int int_cnt_lo = __opvx_a24xx_get_irqcnt_lo(mem32); -+ -+ if (int_cnt_lo & 0x01) { -+ /* Write is at interrupt address. Start writing from normal offset */ -+ *txbuf = writechunk + ZT_CHUNKSIZE * MAX_NUM_CARDS * order; -+ } else { -+ *txbuf = writechunk + ZT_CHUNKSIZE * MAX_NUM_CARDS * irq_frq + ZT_CHUNKSIZE * MAX_NUM_CARDS * order; -+ } -+} -+ -+void __opvx_a24xx_receive(unsigned long mem32, volatile unsigned char *readchunk, volatile unsigned char **rxbuf,unsigned int irq_frq , unsigned int order) -+{ -+ unsigned int int_cnt_lo = __opvx_a24xx_get_irqcnt_lo(mem32); -+ -+ if (int_cnt_lo & 0x01) { -+ /* Read is at interrupt address. Valid data is available at normal offset */ -+ *rxbuf = readchunk + ZT_CHUNKSIZE * MAX_NUM_CARDS * order; -+ } else { -+ *rxbuf = readchunk + ZT_CHUNKSIZE * MAX_NUM_CARDS * irq_frq + ZT_CHUNKSIZE * MAX_NUM_CARDS * order; -+ } -+} -+ -+void __opvx_a24xx_reset_modules_v2(unsigned long mem32, void (*func)(int), int data) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, V2_OPVX_PIO_DATA, 0x02020200); /* gpio bit[1] set to 1*/ -+ (*func)(data/2); /* delay 1/2 sec */ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, V2_OPVX_PIO_DATA, 0x02020000); /* gpio bit[1] set to 0*/ -+ (*func)(data/2); /* delay 1/2 sec */ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, V2_OPVX_PIO_DATA, 0x02020200); /* gpio bit[1] set to 1*/ -+ (*func)(data/2); /* delay 1/2 sec */ -+} -+ -+unsigned int __opvx_a24xx_oct_in_v2(unsigned long mem32, unsigned int addr) -+{ -+ int count = 1000; -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0008, (addr >> 20)); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x000a, (addr >> 4) & ((1 << 16) - 1)); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (1)); -+ while((__opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x0000) & (1 << 8)) && --count); -+ if (count != 1000) { -+// printk("Yah, read can be slow...\n"); -+ } -+ if (!count) { -+// printk("Read timed out!\n"); -+ } -+ return __opvx_a24xx_getcreg(mem32,V2_EC_BASE, 0x0004); -+} -+ -+ -+void __opvx_a24xx_oct_out_v2(unsigned long mem32, unsigned int addr, unsigned int value) -+{ -+ int count = 1000; -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0008, (addr >> 20)); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x000a, (addr >> 4) & ((1 << 16) - 1)); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0004, value); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0000, (((addr >> 1) & 0x7) << 9) | (1 << 8) | (3 << 12) | 1); -+ while((__opvx_a24xx_getcreg(mem32,V2_EC_BASE, 0x0000) & (1 << 8)) && --count); -+ if (count != 1000) { -+// printk("Yah, write can be slow\n"); -+ } -+ if (!count) { -+// printk("Write timed out!\n"); -+ } -+} -+ -+int __opvx_a24xx_check_vpm_v2(unsigned long mem32) -+{ -+ unsigned int check1, check2; -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_VPM_PRESENT, 0); //disable vpm support at first. -+ -+ if (!vpmsupport) { -+// printk("OpenVox VPM: Support Disabled\n"); -+ return -1; -+ } -+ -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x000a, 0x5678); -+ __opvx_a24xx_setcreg(mem32, V2_EC_BASE, 0x0004, 0x1234); -+ check1 = __opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x0004); -+ check2 = __opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x000a); -+ -+// if (ec_debug) { -+// printk("OCT Result: %04x/%04x\n", __opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x0004), __opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x000a)); -+// } -+ -+ if (__opvx_a24xx_getcreg(mem32, V2_EC_BASE, 0x0004) != 0x1234) { -+// printk("OpenVox VPM: Not Present\n"); -+ return -2; -+ } -+ return 0; -+} -+ -+void __opvx_a24xx_vpm_setpresent_v2(unsigned long mem32) -+{ -+ __opvx_a24xx_setcreg(mem32, REG_BASE, OPVX_VPM_PRESENT, BIT_EC_PRESENT); -+ -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/si3050.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/si3050.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,228 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * Written by mark.liu<mark.liu@openvox.cn> -+ * $Id: si3050.c 301 2011-01-19 05:20:32Z yangshugang $ -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/string.h> -+#include <linux/param.h> -+#include <linux/jiffies.h> -+ -+#include "fxo_modes.h" -+#include "base.h" -+ -+extern int debug; -+extern int alawoverride; -+extern int fxofullscale; /* fxo full scale tx/rx, register 30, acim */ -+extern int fwringdetect; -+extern int _opermode; -+extern int fxotxgain; -+extern int fxorxgain; -+extern int fastpickup; -+ -+static int si3050_voicedaa_insane(struct a24xx_dev *wc_dev, int card) -+{ -+ int blah; -+ blah = a24xx_spi_getreg(wc_dev, card, 2); -+ if (blah != 0x3) { -+ return -2; -+ } -+ blah = a24xx_spi_getreg(wc_dev, card, 11); -+ if (debug) { -+ printk("VoiceDAA System: %02x\n", blah & 0xf); -+ } -+ return 0; -+} -+ -+/********************************************************************* -+ * 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) -+ * -+ *******************************************************************/ -+int si3050_set_hwgain(struct a24xx_dev *wc_dev, int card, __s32 gain, __u32 tx) -+{ -+ if (!(wc_dev->modtype[card] == MOD_TYPE_FXO)) { -+ printk("Cannot adjust gain. Unsupported module type!\n"); -+ return -1; -+ } -+ if (tx) { -+ if (debug) { -+ printk("setting FXO tx gain for card=%d to %d\n", card, gain); -+ } -+ if (gain >= -150 && gain <= 0) { -+ a24xx_spi_setreg(wc_dev, card, 38, 16 + (gain/-10)); -+ a24xx_spi_setreg(wc_dev, card, 40, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ a24xx_spi_setreg(wc_dev, card, 38, gain/10); -+ a24xx_spi_setreg(wc_dev, card, 40, (gain%10)); -+ } else { -+ printk("FXO tx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } else { /* rx */ -+ if (debug) { -+ printk("setting FXO rx gain for card=%d to %d\n", card, gain); -+ } -+ if (gain >= -150 && gain <= 0) { -+ a24xx_spi_setreg(wc_dev, card, 39, 16+ (gain/-10)); -+ a24xx_spi_setreg(wc_dev, card, 41, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ a24xx_spi_setreg(wc_dev, card, 39, gain/10); -+ a24xx_spi_setreg(wc_dev, card, 41, (gain%10)); -+ } else { -+ printk("FXO rx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+int si3050_init_voicedaa(struct a24xx_dev *wc_dev, int card, int fast, int manual, int sane) -+{ -+ unsigned char reg16=0, reg26=0, reg30=0, reg31=0; -+ unsigned char ch; -+ long newjiffies; -+ -+ wc_dev->modtype[card] = MOD_TYPE_FXO; -+ /* Sanity check the ProSLIC */ -+ a24xx_reset_spi(wc_dev, card); -+ if (!sane && si3050_voicedaa_insane(wc_dev, card)) { -+ return -2; -+ } -+ -+ /* Software reset */ -+ a24xx_spi_setreg(wc_dev, card, 1, 0x80); -+ -+ /* Wait just a bit */ -+ __a24xx_wait_just_a_bit(HZ/10); -+ -+ /* Enable PCM, ulaw */ -+ if (alawoverride) { -+ a24xx_spi_setreg(wc_dev, card, 33, 0x20); -+ } else { -+ a24xx_spi_setreg(wc_dev, 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); -+ a24xx_spi_setreg(wc_dev, card, 16, reg16); -+ -+ if(fwringdetect) { -+ /* Enable ring detector full-wave rectifier mode */ -+ a24xx_spi_setreg(wc_dev, card, 18, 2); -+ a24xx_spi_setreg(wc_dev, card, 24, 0); -+ } else { -+ /* Set to the device defaults */ -+ a24xx_spi_setreg(wc_dev, card, 18, 0); -+ a24xx_spi_setreg(wc_dev, 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); -+ a24xx_spi_setreg(wc_dev, card, 26, reg26); -+ -+ /* Set AC Impedence */ -+ reg30 = (fxofullscale==1) ? (fxo_modes[_opermode].acim|0x10) : (fxo_modes[_opermode].acim); -+ a24xx_spi_setreg(wc_dev, card, 30, reg30); -+ -+ /* Misc. DAA parameters */ -+ if (fastpickup) { -+ reg31 = 0xb3; -+ } else { -+ reg31 = 0xa3; -+ } -+ -+ reg31 |= (fxo_modes[_opermode].ohs2 << 3); -+ a24xx_spi_setreg(wc_dev, card, 31, reg31); -+ -+ /* Set Transmit/Receive timeslot */ -+ //printk("set card %d to %d\n", card, (3-(card%4)) * 8 + (card/4) * 64); -+ a24xx_spi_setreg(wc_dev, card, 34, (card%4) * 8 + (card/4) * 32); -+ a24xx_spi_setreg(wc_dev, card, 35, 0x00); -+ a24xx_spi_setreg(wc_dev, card, 36, (card%4) * 8 + (card/4) * 32); -+ a24xx_spi_setreg(wc_dev, card, 37, 0x00); -+ -+ /* Enable ISO-Cap */ -+ a24xx_spi_setreg(wc_dev, card, 6, 0x00); -+ -+ if (fastpickup) { -+ a24xx_spi_setreg(wc_dev, card, 17, a24xx_spi_getreg(wc_dev, card, 17) | 0x20); -+ } -+ -+ /* Wait 1000ms for ISO-cap to come up */ -+ newjiffies = jiffies; -+ newjiffies += 2 * HZ; -+ while((jiffies < newjiffies) && !(a24xx_spi_getreg(wc_dev, card, 11) & 0xf0)) { -+ __a24xx_wait_just_a_bit(HZ/10); -+ } -+ -+ /*if (!(a24xx_spi_getreg(wc_dev, card, 11) & 0xf0)) {*/ -+ ch = a24xx_spi_getreg(wc_dev, card, 11); -+ if( ch == 0xff ) { -+ printk("VoiceDAA not installed at card %d\n", card); -+ return -1; -+ } -+ if (!(ch & 0xf0)) { -+ printk("VoiceDAA did not bring up ISO link properly!\n"); -+ return -1; -+ } -+ if (debug) { -+ printk("ISO-Cap is now up, line side: %02x rev %02x\n", -+ a24xx_spi_getreg(wc_dev, card, 11) >> 4, -+ (a24xx_spi_getreg(wc_dev, card, 13) >> 2) & 0xf); -+ } -+ /* Enable on-hook line monitor */ -+ a24xx_spi_setreg(wc_dev, card, 5, 0x08); -+ -+ /* Take values for fxotxgain and fxorxgain and apply them to module */ -+ si3050_set_hwgain(wc_dev, card, fxotxgain, 1); -+ si3050_set_hwgain(wc_dev, card, fxorxgain, 0); -+ -+ /* NZ -- crank the tx gain up by 7 dB */ -+ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) { -+ printk("Adjusting gain\n"); -+ si3050_set_hwgain(wc_dev, card, 7, 1); -+ } -+ -+ if(debug) { -+ printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", -+ (a24xx_spi_getreg(wc_dev, card, 38)/16) ? -(a24xx_spi_getreg(wc_dev, card, 38) - 16) : a24xx_spi_getreg(wc_dev, card, 38), -+ (a24xx_spi_getreg(wc_dev, card, 40)/16) ? -(a24xx_spi_getreg(wc_dev, card, 40) - 16) : a24xx_spi_getreg(wc_dev, card, 40), -+ (a24xx_spi_getreg(wc_dev, card, 39)/16) ? -(a24xx_spi_getreg(wc_dev, card, 39) - 16) : a24xx_spi_getreg(wc_dev, card, 39), -+ (a24xx_spi_getreg(wc_dev, card, 41)/16) ? -(a24xx_spi_getreg(wc_dev, card, 41) - 16) : a24xx_spi_getreg(wc_dev, card, 41)); -+ } -+ -+ /* battery state still unknown */ -+ return 0; -+ -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxa24xx/si321x.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxa24xx/si321x.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,1469 @@ -+/* -+ * OpenVox A24xx FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Written by MiaoLin<miaolin@openvox.cn> -+ * Written by mark.liu<mark.liu@openvox.cn> -+ * $Id: si321x.c 482 2011-06-02 08:58:56Z liuyuan $ -+ * -+ * 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. -+ * -+ */ -+ -+#include <linux/param.h> -+#include <linux/jiffies.h> -+#include <linux/sched.h> -+ -+#include "proslic.h" -+#include "fxo_modes.h" -+#include "base.h" -+ -+/* module param */ -+extern int debug; -+extern int loopcurrent; -+extern int reversepolarity; -+extern int fxstxgain; -+extern int fxsrxgain; -+extern int boostringer; -+extern int fastringer; -+extern int lowpower; -+extern int _opermode; -+extern int alawoverride; -+extern int fxshonormode; -+ -+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; -+ -+/* indirect_resg */ -+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",0x0ff4}, -+{33,20,"PWR_ALARM_Q3Q4",0x6e7e}, -+{34,21,"PWR_ALARM_Q5Q6",0x0ff4}, -+{35,22,"LOOP_CLOSURE_FILTER",0x8000}, -+{36,23,"RING_TRIP_FILTER",0x0320}, -+{37,24,"TERM_LP_POLE_Q1Q2",0x0012}, -+{38,25,"TERM_LP_POLE_Q3Q4",0x0012}, -+{39,26,"TERM_LP_POLE_Q5Q6",0x0012}, -+{40,27,"CM_BIAS_RINGING",0x0C00}, -+{41,64,"DCDC_MIN_V",0x0C00}, -+{42,255,"DCDC_XTRA",0x1000}, -+{43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, -+}; -+ -+static int si321x_powerup_proslic(struct a24xx_dev *wc_dev, int card, int fast) -+{ -+ unsigned char vbat; -+ unsigned long origjiffies; -+ int lim; -+ -+ /* Set period of DC-DC converter to 1/64 khz */ -+ a24xx_spi_setreg(wc_dev, card, 92, 0xff /* was 0xff */); -+ -+ /* Wait for VBat to powerup */ -+ origjiffies = jiffies; -+ -+ /* Disable powerdown */ -+ a24xx_spi_setreg(wc_dev, card, 14, 0); -+ -+ /* If fast, don't bother checking anymore */ -+ if (fast) -+ return 0; -+ -+ while((vbat = a24xx_spi_getreg(wc_dev, card, 82)) < 0xc0) { -+ /* Wait no more than 500ms */ -+ if ((jiffies - origjiffies) > HZ/2) { -+ break; -+ } -+ } -+ -+ if (vbat < 0xc0) { -+ if (wc_dev->proslic_power == PROSLIC_POWER_UNKNOWN) { -+ printk("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 A24xxP??\n", -+ card, (int)(((jiffies - origjiffies) * 1000 / HZ)), -+ vbat * 375); -+ } -+ wc_dev->proslic_power = PROSLIC_POWER_WARNED; -+ return -1; -+ } else if (debug) { -+ printk("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_dev->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("Loop current out of range! Setting to default 20mA!\n"); -+ } -+ } -+ else if (debug) { -+ printk("Loop current set to %dmA!\n",(lim*3)+20); -+ } -+ a24xx_spi_setreg(wc_dev,card,LOOP_I_LIMIT,lim); -+ -+ /* Engage DC-DC converter */ -+ a24xx_spi_setreg(wc_dev, card, 93, 0x19 /* was 0x19 */); -+#if 0 -+ origjiffies = jiffies; -+ while(0x80 & opvx_a24xx_spi_getreg(wc_dev, card, 93)) { -+ if ((jiffies - origjiffies) > 2 * HZ) { -+ printk("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 = opvx_a24xx_spi_getreg(wc_dev, card, 82); -+ printk("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; -+ -+} -+ -+/*return not OK modules flag*/ -+static int si321x_powerup_proslic_all(struct a24xx_dev *wc_dev, int flag, int fast) -+{ -+ unsigned long origjiffies; -+ struct stat{ -+ unsigned char vbat; -+ unsigned long jifs; -+ }; -+ -+ struct stat stats[24]; -+ int lim; -+ int tmp_flag,x; -+ -+ -+ for(x=0; x < wc_dev->max_cards; x++){ -+ if(flag & (1 << x)){ -+ /* Set period of DC-DC converter to 1/64 khz */ -+ a24xx_spi_setreg(wc_dev, x, 92, 0xff /* was 0xff */); -+ -+ /* Disable powerdown */ -+ a24xx_spi_setreg(wc_dev, x, 14, 0); -+ -+ stats[x].vbat = 0; -+ stats[x].jifs = 0; -+ } -+ } -+ -+ /* Wait for VBat to powerup */ -+ origjiffies = jiffies; -+ -+ /* If fast, don't bother checking anymore */ -+ if (fast) -+ return 0; -+ -+ tmp_flag = flag; -+ while( ((jiffies - origjiffies) <= HZ/2) && tmp_flag){ /* Wait no more than 500ms */ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(tmp_flag & (1 << x)){ -+ //stats[x].vbat = a24xx_spi_getreg(wc_dev, x, 82); -+ stats[x].vbat = a24xx_spi_getreg(wc_dev, x, 82); -+ if(stats[x].vbat >= 0xc0){ -+ stats[x].jifs = jiffies - origjiffies; -+ tmp_flag &=~(1 << x); -+ } -+ } -+ } -+ } -+ -+ for(x=0; x < wc_dev->max_cards; x++){ -+ if(flag & (1 << x)){ -+ if(stats[x].vbat < 0xc0){ -+ if (wc_dev->proslic_power == PROSLIC_POWER_UNKNOWN){ -+ printk("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 A24xxP??\n", -+ x, (int)(((jiffies - origjiffies) * 1000 / HZ)), -+ stats[x].vbat * 375); -+ } -+ //wc_dev->proslic_power = PROSLIC_POWER_WARNED; -+ } -+ else if(debug){ -+ printk("ProSLIC on module %d powered up to -%d volts (%02x) in %d ms\n", -+ x, stats[x].vbat * 376 / 1000, stats[x].vbat, (int)((stats[x].jifs * 1000 / HZ))); -+ } -+ } -+ } -+ if(tmp_flag == flag){ -+ wc_dev->proslic_power = PROSLIC_POWER_WARNED; -+ return tmp_flag; -+ } -+ -+ wc_dev->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("Loop current out of range! Setting to default 20mA!\n"); -+ } -+ } -+ else if (debug) { -+ printk("Loop current set to %dmA!\n",(lim*3)+20); -+ } -+ flag &= ~tmp_flag; -+ -+ for(x=0;x < wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ a24xx_spi_setreg(wc_dev,x,LOOP_I_LIMIT,lim); -+ -+ /* Engage DC-DC converter */ -+ a24xx_spi_setreg(wc_dev, x, 93, 0x19 /* was 0x19 */); -+ } -+ } -+ -+ return tmp_flag; -+} -+ -+static int si321x_proslic_insane(struct a24xx_dev *wc_dev, int card) -+{ -+ int blah,insane_report; -+ insane_report=0; -+ -+ blah = a24xx_spi_getreg(wc_dev, card, 0); -+ if (debug) { -+ printk("ProSLIC on module %d, product %d, version %d (0x%x)\n", card, (blah & 0x30) >> 4, (blah & 0xf), blah&0xff); -+ } -+ -+#if 0 -+ if ((blah & 0x30) >> 4) { -+ printk("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("ProSLIC 3210 version %d is too old\n", blah & 0xf); -+ return -1; -+ } -+ if (a24xx_spi_getreg(wc_dev, card, 1) & 0x80) { -+ /* ProSLIC 3215, not a 3210 */ -+ wc_dev->flags[card] |= FLAG_3215; -+ } -+ -+ blah = a24xx_spi_getreg(wc_dev, card, 8); -+ if (blah != 0x2) { -+ printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah); -+ return -1; -+ } else if ( insane_report) { -+ printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah); -+ } -+ -+ blah = a24xx_spi_getreg(wc_dev, card, 64); -+ if (blah != 0x0) { -+ printk("ProSLIC on module %d insane (2)\n", card); -+ return -1; -+ } else if ( insane_report) { -+ printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah); -+ } -+ -+ blah = a24xx_spi_getreg(wc_dev, card, 11); -+ if (blah != 0x33) { -+ printk("ProSLIC on module %d insane (3)\n", card); -+ return -1; -+ } else if ( insane_report) { -+ printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah); -+ } -+ -+ /* Just be sure it's setup right. */ -+ a24xx_spi_setreg(wc_dev, card, 30, 0); -+ -+ if (debug) { -+ printk("ProSLIC on module %d seems sane.\n", card); -+ } -+ -+ return 0; -+} -+ -+ -+#if 1 -+static int si321x_proslic_calibrate(struct a24xx_dev *wc_dev, int card) -+{ -+ unsigned long origjiffies; -+ int x; -+ /* Perform all calibrations */ -+ a24xx_spi_setreg(wc_dev, card, 97, 0x1f); -+ -+ /* Begin, no speedup */ -+ a24xx_spi_setreg(wc_dev, card, 96, 0x5f); -+ -+ /* Wait for it to finish */ -+ origjiffies = jiffies; -+ while(a24xx_spi_getreg(wc_dev, card, 96)) { -+ if ((jiffies - origjiffies) > 2 * HZ) { -+ printk("Timeout waiting for calibration of module %d\n", card); -+ return -1; -+ } -+ } -+ -+ if (debug) { -+ /* Print calibration parameters */ -+ printk("Calibration Vector Regs 98 - 107: \n"); -+ for (x=98;x<108;x++) { -+ printk("%d: %02x\n", x, a24xx_spi_getreg(wc_dev, card, x)); -+ } -+ } -+ return 0; -+} -+#endif -+ -+/*return not OK cards flag*/ -+static int si321x_proslic_calibrate_all(struct a24xx_dev *wc_dev, int flag) -+{ -+ unsigned long origjiffies; -+ int i,x,tmp_flag; -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ /* Perform all calibrations */ -+ a24xx_spi_setreg(wc_dev, x, 97, 0x1f); -+ -+ /* Begin, no speedup */ -+ a24xx_spi_setreg(wc_dev, x, 96, 0x5f); -+ } -+ } -+ -+ /* Wait for it to finish */ -+ origjiffies = jiffies; -+ tmp_flag = flag; -+ -+ while(((jiffies - origjiffies) < 2 * HZ) && tmp_flag){ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(tmp_flag & (1 << x)){ -+ if(!a24xx_spi_getreg(wc_dev, x, 96)){ -+ tmp_flag &= ~(1 << x); -+ } -+ } -+ } -+ } -+ -+ if (debug) { -+ /* Print calibration parameters */ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ printk("Calibration Vector Regs 98 - 107: \n"); -+ for (i=98;i<108;i++) { -+ printk("Module %d %d: %02x\n", x,i, a24xx_spi_getreg(wc_dev, x, i)); -+ } -+ } -+ } -+ } -+ return tmp_flag; -+} -+ -+static int si321x_proslic_powerleak_test(struct a24xx_dev *wc_dev, int card) -+{ -+ unsigned long origjiffies; -+ unsigned char vbat; -+ -+ /* Turn off linefeed */ -+ a24xx_spi_setreg(wc_dev, card, 64, 0); -+ -+ /* Power down */ -+ a24xx_spi_setreg(wc_dev, card, 14, 0x10); -+ -+ /* Wait for one second */ -+ origjiffies = jiffies; -+ -+ while((vbat = a24xx_spi_getreg(wc_dev, card, 82)) > 0x6) { -+ if ((jiffies - origjiffies) >= (HZ/2)) { -+ break; -+ } -+ } -+ -+ if (vbat < 0x06) { -+ printk("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("Post-leakage voltage: %d volts\n", 376 * vbat / 1000); -+ } -+ return 0; -+} -+ -+/* return OK cards flag*/ -+static int si321x_proslic_powerleak_test_all(struct a24xx_dev *wc_dev, int flag) -+{ -+ unsigned long origjiffies; -+ struct stat{ -+ unsigned char vbat; -+ unsigned long jifs; -+ }; -+ -+ struct stat stats[24]; -+ int x,tmp_flag=0; -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ /* Turn off linefeed */ -+ a24xx_spi_setreg(wc_dev, x, 64, 0); -+ -+ /* Power down */ -+ a24xx_spi_setreg(wc_dev, x, 14, 0x10); -+ } -+ stats[x].vbat=0; -+ stats[x].jifs=0; -+ } -+ -+ /* Wait for one second */ -+ origjiffies = jiffies; -+ -+ tmp_flag = flag; -+ while(((jiffies - origjiffies) < (HZ/2)) && tmp_flag){ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(tmp_flag & (1 << x)){ -+ if((stats[x].vbat = a24xx_spi_getreg(wc_dev, x, 82)) < 0x6){ -+ tmp_flag &= ~(1 << x); -+ stats[x].jifs = jiffies - origjiffies; -+ } -+ } -+ } -+ } -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ if (stats[x].vbat < 0x06) { -+ printk("Excessive leakage detected on module %d: %d volts (%02x) after %d ms\n", x, -+ 376 * stats[x].vbat / 1000, stats[x].vbat, (int)(stats[x].jifs * 1000 / HZ)); -+ } else if (debug) { -+ printk("Post-leakage voltage: %d volts\n", 376 * stats[x].vbat / 1000); -+ } -+ } -+ } -+ -+ return tmp_flag; -+} -+ -+static int si321x_proslic_manual_calibrate(struct a24xx_dev *wc_dev, int card) -+{ -+ unsigned long origjiffies; -+ unsigned char i; -+ -+ a24xx_spi_setreg(wc_dev, card, 21, 0);//(0) Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, card, 22, 0);//(0)Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, card, 23, 0);//(0)Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, card, 64, 0);//(0) -+ -+ a24xx_spi_setreg(wc_dev, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. -+ a24xx_spi_setreg(wc_dev, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM -+ -+ origjiffies=jiffies; -+ while( a24xx_spi_getreg(wc_dev,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); -+ si321x_proslic_setreg_indirect(wc_dev, card, 88,0); -+ si321x_proslic_setreg_indirect(wc_dev,card,89,0); -+ si321x_proslic_setreg_indirect(wc_dev,card,90,0); -+ si321x_proslic_setreg_indirect(wc_dev,card,91,0); -+ si321x_proslic_setreg_indirect(wc_dev,card,92,0); -+ si321x_proslic_setreg_indirect(wc_dev,card,93,0); -+ -+ a24xx_spi_setreg(wc_dev, card, 98,0x10); // This is necessary if the calibration occurs other than at reset time -+ a24xx_spi_setreg(wc_dev, card, 99,0x10); -+ -+ for ( i=0x1f; i>0; i--) { -+ a24xx_spi_setreg(wc_dev, card, 98,i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((a24xx_spi_getreg(wc_dev,card,88)) == 0) -+ break; -+ } // for -+ -+ for ( i=0x1f; i>0; i--) { -+ a24xx_spi_setreg(wc_dev, card, 99,i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((a24xx_spi_getreg(wc_dev,card,89)) == 0) -+ break; -+ }//for -+ -+ /*******************************The preceding is the manual gain mismatch calibration****************************/ -+ /**********************************The following is the longitudinal Balance Cal***********************************/ -+ a24xx_spi_setreg(wc_dev,card,64,1); -+ while((jiffies-origjiffies)<10); // Sleep 100? -+ -+ a24xx_spi_setreg(wc_dev, card, 64, 0); -+ a24xx_spi_setreg(wc_dev, card, 23, 0x4); // enable interrupt for the balance Cal -+ a24xx_spi_setreg(wc_dev, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration -+ a24xx_spi_setreg(wc_dev, card, 96,0x40); -+ -+ a24xx_spi_getreg(wc_dev,card,96); /* Read Reg 96 just cause */ -+ -+ a24xx_spi_setreg(wc_dev, card, 21, 0xFF); -+ a24xx_spi_setreg(wc_dev, card, 22, 0xFF); -+ a24xx_spi_setreg(wc_dev, card, 23, 0xFF); -+ -+ /**The preceding is the longitudinal Balance Cal***/ -+ return(0); -+ -+} -+ -+/*return not OK cards flag*/ -+static int si321x_proslic_manual_calibrate_all(struct a24xx_dev *wc_dev, int flag) -+{ -+ unsigned long origjiffies; -+ unsigned char i; -+ int x,tmp_flag; -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ a24xx_spi_setreg(wc_dev, x, 21, 0);//(0) Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, x, 22, 0);//(0)Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, x, 23, 0);//(0)Disable all interupts in DR21 -+ a24xx_spi_setreg(wc_dev, x, 64, 0);//(0) -+ -+ a24xx_spi_setreg(wc_dev, x, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. -+ a24xx_spi_setreg(wc_dev, x, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM -+ } -+ } -+ -+ origjiffies=jiffies; -+ -+ /*remove not OK cards flag*/ -+ tmp_flag = flag; -+ while(((jiffies-origjiffies)< 80) && tmp_flag){ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(tmp_flag & (1 << x)){ -+ if(a24xx_spi_getreg(wc_dev,x,96) == 0){ -+ tmp_flag &= ~(1 << x); -+ } -+ } -+ } -+ } -+ -+ flag &= ~tmp_flag; -+ -+ //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); -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ si321x_proslic_setreg_indirect(wc_dev,x,88,0); -+ si321x_proslic_setreg_indirect(wc_dev,x,89,0); -+ si321x_proslic_setreg_indirect(wc_dev,x,90,0); -+ si321x_proslic_setreg_indirect(wc_dev,x,91,0); -+ si321x_proslic_setreg_indirect(wc_dev,x,92,0); -+ si321x_proslic_setreg_indirect(wc_dev,x,93,0); -+ -+ a24xx_spi_setreg(wc_dev, x, 98,0x10); // This is necessary if the calibration occurs other than at reset time -+ a24xx_spi_setreg(wc_dev, x, 99,0x10); -+ -+ for ( i=0x1f; i>0; i--) { -+ a24xx_spi_setreg(wc_dev, x, 98,i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((a24xx_spi_getreg(wc_dev,x,88)) == 0) -+ break; -+ } // for -+ -+ for ( i=0x1f; i>0; i--) { -+ a24xx_spi_setreg(wc_dev, x, 99,i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((a24xx_spi_getreg(wc_dev,x,89)) == 0) -+ break; -+ }//for -+ -+ /*******************************The preceding is the manual gain mismatch calibration****************************/ -+ /**********************************The following is the longitudinal Balance Cal***********************************/ -+ a24xx_spi_setreg(wc_dev,x,64,1); -+ } -+ } -+ -+ while((jiffies-origjiffies)<10); // Sleep 100? -+ -+ for(x=0;x<wc_dev->max_cards;x++){ -+ if(flag & (1 << x)){ -+ a24xx_spi_setreg(wc_dev, x, 64, 0); -+ a24xx_spi_setreg(wc_dev, x, 23, 0x4); // enable interrupt for the balance Cal -+ a24xx_spi_setreg(wc_dev, x, 97, 0x1); // this is a singular calibration bit for longitudinal calibration -+ a24xx_spi_setreg(wc_dev, x, 96,0x40); -+ -+ a24xx_spi_getreg(wc_dev,x,96); /* Read Reg 96 just cause */ -+ -+ a24xx_spi_setreg(wc_dev, x, 21, 0xFF); -+ a24xx_spi_setreg(wc_dev, x, 22, 0xFF); -+ a24xx_spi_setreg(wc_dev, x, 23, 0xFF); -+ } -+ } -+ -+ /**The preceding is the longitudinal Balance Cal***/ -+ return tmp_flag; -+} -+ -+static int si321x_proslic_verify_indirect_regs(struct a24xx_dev *wc_dev, 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 = si321x_proslic_getreg_indirect(wc_dev, card, (unsigned char) indirect_regs[i].address)) < 0) { -+ printk("Failed to read indirect register %d\n", i); -+ return -1; -+ } -+ initial= indirect_regs[i].initial; -+ -+ if ( j != initial && (!(wc_dev->flags[card] & FLAG_3215) || (indirect_regs[i].altaddr != 255))) { -+ printk("!!!!!!! %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("Init Indirect Registers completed successfully.\n"); -+ } -+ } else { -+ printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+static int si321x_proslic_init_indirect_regs(struct a24xx_dev *wc_dev, int card) -+{ -+ unsigned char i; -+ -+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) { -+ if(si321x_proslic_setreg_indirect(wc_dev, card, indirect_regs[i].address,indirect_regs[i].initial)) { -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+int si321x_set_ring_generator_mode(struct a24xx_dev *wc_dev, int card, int mode) -+{ -+ int reg20, reg21, reg74; /* RCO, RNGX, VBATH */ -+ struct fxs *const fxs = &wc_dev->mod[card].fxs; -+ -+ fxs->neonringing = mode; /* track ring generator mode */ -+ -+ if (mode) { /* Neon */ -+ if (debug) -+ printk(KERN_DEBUG "NEON ring on chan %d, " -+ "lasttxhook was 0x%x\n", card, fxs->lasttxhook); -+ /* Must be in FORWARD ACTIVE before setting ringer */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ a24xx_spi_setreg(wc_dev, card, LINE_STATE, fxs->lasttxhook); -+ -+ si321x_proslic_setreg_indirect(wc_dev, card, 22, -+ NEON_MWI_RNGY_PULSEWIDTH); -+ si321x_proslic_setreg_indirect(wc_dev, card, 21, -+ 0x7bef); /* RNGX (91.5Vpk) */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 20, -+ 0x009f); /* RCO (RNGX, t rise)*/ -+ -+ a24xx_spi_setreg(wc_dev, card, 34, 0x19); /* Ringing Osc. Control */ -+ a24xx_spi_setreg(wc_dev, card, 74, 0x3f); /* VBATH 94.5V */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 29, 0x4600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the VM led */ -+ } else { -+ a24xx_spi_setreg(wc_dev, card, 34, 0x00); /* Ringing Osc. Control */ -+ /* RNGY Initial Phase */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 22, 0x0000); -+ si321x_proslic_setreg_indirect(wc_dev, card, 29, 0x3600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the ringer */ -+ -+ if (fastringer) { -+ /* Speed up Ringer */ -+ reg20 = 0x7e6d; -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x0247; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Boosting fast ringer" -+ " on chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x014b; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Reducing fast ring " -+ "power on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: fast " -+ "ring_x power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x01b9; -+ if (debug) -+ printk(KERN_DEBUG "Speeding up ringer " -+ "on chan %d (25Hz)\n", -+ card); -+ } -+ /* VBATH */ -+ a24xx_spi_setreg(wc_dev, card, 74, reg74); -+ /*RCO*/ -+ si321x_proslic_setreg_indirect(wc_dev, card, 20, reg20); -+ /*RNGX*/ -+ si321x_proslic_setreg_indirect(wc_dev, card, 21, reg21); -+ -+ } else { -+ /* Ringer Speed */ -+ if (fxshonormode && fxo_modes[_opermode].ring_osc) { -+ reg20 = fxo_modes[_opermode].ring_osc; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: " -+ "ring_osc speed on chan %d\n", -+ card); -+ } else { -+ reg20 = 0x7ef0; /* Default */ -+ } -+ -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x1d1; -+ if (debug) -+ printk(KERN_DEBUG "Boosting ringer on " -+ "chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x108; -+ if (debug) -+ printk(KERN_DEBUG "Reducing ring power " -+ "on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: ring_x" -+ " power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x160; -+ if (debug) -+ printk(KERN_DEBUG "Normal ring power on" -+ " chan %d\n", -+ card); -+ } -+ /* VBATH */ -+ a24xx_spi_setreg(wc_dev, card, 74, reg74); -+ /* RCO */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 20, reg20); -+ /* RNGX */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 21, reg21); -+ } -+ } -+ return 0; -+} -+ -+int si321x_init_ring_generator_mode(struct a24xx_dev *wc_dev, int card){ -+ a24xx_spi_setreg(wc_dev, card, 34, 0x00); /* Ringing Osc. Control */ -+ /* neon trapezoid timers */ -+ a24xx_spi_setreg(wc_dev, card, 48, 0xe0); /* Active Timer low byte */ -+ a24xx_spi_setreg(wc_dev, card, 49, 0x01); /* Active Timer high byte */ -+ a24xx_spi_setreg(wc_dev, card, 50, 0xF0); /* Inactive Timer low byte */ -+ a24xx_spi_setreg(wc_dev, card, 51, 0x05); /* Inactive Timer high byte */ -+ -+ si321x_set_ring_generator_mode(wc_dev, card, 0); -+ -+ return 0; -+} -+ -+int si321x_init_proslic(struct a24xx_dev *wc_dev, 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 && si321x_proslic_insane(wc_dev, card)) { -+ return -2; -+ } -+ -+ /* default messages to none and method to FSK */ -+ memset(&wc_dev->mod[card].fxs.vmwisetting, 0, sizeof(wc_dev->mod[card].fxs.vmwisetting)); -+ wc_dev->mod[card].fxs.vmwi_lrev = 0; -+ wc_dev->mod[card].fxs.vmwi_hvdc = 0; -+ wc_dev->mod[card].fxs.vmwi_hvac = 0; -+ -+ /* By default, don't send on hook */ -+ if (reversepolarity) { -+ wc_dev->mod[card].fxs.idletxhookstate = 5; -+ } else { -+ wc_dev->mod[card].fxs.idletxhookstate = 1; -+ } -+ -+ if (sane) { -+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ -+ a24xx_spi_setreg(wc_dev, card, 14, 0x10); -+ } -+ -+ if (si321x_proslic_init_indirect_regs(wc_dev, card)) { -+ printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", card); -+ return -1; -+ } -+ -+ /* Clear scratch pad area */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 97,0); -+ -+ /* Clear digital loopback */ -+ a24xx_spi_setreg(wc_dev, card, 8, 0); -+ -+ /* Revision C optimization */ -+ a24xx_spi_setreg(wc_dev, card, 108, 0xeb); -+ -+ /* Disable automatic VBat switching for safety to prevent -+ Q7 from accidently turning on and burning out. */ -+ a24xx_spi_setreg(wc_dev, card, 67, 0x07); /* Note, if pulse dialing has problems at high REN loads -+ change this to 0x17 */ -+ -+ /* Turn off Q7 */ -+ a24xx_spi_setreg(wc_dev, card, 66, 1); -+ -+ /* Flush ProSLIC digital filters by setting to clear, while -+ saving old values */ -+ for (x=0;x<5;x++) { -+ tmp[x] = si321x_proslic_getreg_indirect(wc_dev, card, x + 35); -+ si321x_proslic_setreg_indirect(wc_dev, card, x + 35, 0x8000); -+ } -+ -+ /* Power up the DC-DC converter */ -+ if (si321x_powerup_proslic(wc_dev, card, fast)) { ////////////**************** -+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+ -+ if (!fast) { -+ /* Check for power leaks */ -+ if (si321x_proslic_powerleak_test(wc_dev, card)) {///////**************** -+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); -+ } -+ /* Power up again */ -+ if (si321x_powerup_proslic(wc_dev, card, fast)) { ////////////**************** -+ printk("Unable to do FINAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+#ifndef NO_CALIBRATION -+ /* Perform calibration */ -+ if(manual) { -+ if (si321x_proslic_manual_calibrate(wc_dev, card)) { //////////**************** -+ //printk("Proslic failed on Manual Calibration\n"); -+ if (si321x_proslic_manual_calibrate(wc_dev, card)) { ////////////**************** -+ printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); -+ return -1; -+ } -+ printk("Proslic Passed Manual Calibration on Second Attempt\n"); -+ } -+ } -+ else { -+ if(si321x_proslic_calibrate(wc_dev, card)) { ///////**************** -+ //printk("ProSlic died on Auto Calibration.\n"); -+ if (si321x_proslic_calibrate(wc_dev, card)) { ////////////**************** -+ printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); -+ return -1; -+ } -+ printk("Proslic Passed Auto Calibration on Second Attempt\n"); -+ } -+ } -+ /* Perform DC-DC calibration */ -+ a24xx_spi_setreg(wc_dev, card, 93, 0x99); -+ r19 = a24xx_spi_getreg(wc_dev, card, 107); -+ if ((r19 < 0x2) || (r19 > 0xd)) { -+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); -+ a24xx_spi_setreg(wc_dev, card, 107, 0x8); -+ } -+ -+ /* Save calibration vectors */ -+ for (x=0;x<NUM_CAL_REGS;x++) { -+ wc_dev->mod[card].fxs.calregs.vals[x] = a24xx_spi_getreg(wc_dev, card, 96 + x); -+ } -+#endif -+ -+ } else { -+ /* Restore calibration registers */ -+ for (x=0;x<NUM_CAL_REGS;x++) { -+ a24xx_spi_setreg(wc_dev, card, 96 + x, wc_dev->mod[card].fxs.calregs.vals[x]); -+ } -+ } -+ /* Calibration complete, restore original values */ -+ for (x=0;x<5;x++) { -+ si321x_proslic_setreg_indirect(wc_dev, card, x + 35, tmp[x]); -+ } -+ -+ if (si321x_proslic_verify_indirect_regs(wc_dev, card)) { -+ printk(KERN_INFO "Indirect Registers failed verification.\n"); -+ return -1; -+ } -+ -+ -+#if 0 -+ /* Disable Auto Power Alarm Detect and other "features" */ -+ a24xx_spi_setreg(wc_dev, card, 67, 0x0e); -+ blah = opvx_a24xx_spi_getreg(wc_dev, card, 67); -+#endif -+ -+#if 0 -+ if (si321x_proslic_setreg_indirect(wc_dev, card, 97, 0x0)) { // Stanley: for the bad recording fix -+ printk(KERN_INFO "ProSlic IndirectReg Died.\n"); -+ return -1; -+ } -+#endif -+ -+ if (alawoverride) { -+ a24xx_spi_setreg(wc_dev, card, 1, 0x20); -+ } else { -+ a24xx_spi_setreg(wc_dev, card, 1, 0x28); -+ } -+ // U-Law 8-bit interface -+ a24xx_spi_setreg(wc_dev, card, 2, (card%4) * 8 + (card/4) * 32); // Tx Start count low byte 0 -+ a24xx_spi_setreg(wc_dev, card, 3, 0); // Tx Start count high byte 0 -+ a24xx_spi_setreg(wc_dev, card, 4, (card%4) * 8 + (card/4) * 32); // Rx Start count low byte 0 -+ a24xx_spi_setreg(wc_dev, card, 5, 0); // Rx Start count high byte 0 -+ a24xx_spi_setreg(wc_dev, card, 18, 0xff); // clear all interrupt -+ a24xx_spi_setreg(wc_dev, card, 19, 0xff); -+ a24xx_spi_setreg(wc_dev, card, 20, 0xff); -+ a24xx_spi_setreg(wc_dev, card, 73, 0x04); -+ if (fxshonormode) { -+ fxsmode = acim2tiss[fxo_modes[_opermode].acim]; -+ a24xx_spi_setreg(wc_dev, card, 10, 0x08 | fxsmode); -+ if (fxo_modes[_opermode].ring_osc) { -+ si321x_proslic_setreg_indirect(wc_dev, card, 20, fxo_modes[_opermode].ring_osc); -+ } -+ if (fxo_modes[_opermode].ring_x) { -+ si321x_proslic_setreg_indirect(wc_dev, card, 21, fxo_modes[_opermode].ring_x); -+ } -+ } -+ if (lowpower) { -+ a24xx_spi_setreg(wc_dev, card, 72, 0x10); -+ } -+ -+#if 0 -+ a24xx_spi_setreg(wc_dev, card, 21, 0x00); // enable interrupt -+ a24xx_spi_setreg(wc_dev, card, 22, 0x02); // Loop detection interrupt -+ a24xx_spi_setreg(wc_dev, card, 23, 0x01); // DTMF detection interrupt -+#endif -+ -+#if 0 -+ /* Enable loopback */ -+ a24xx_spi_setreg(wc_dev, card, 8, 0x2); -+ a24xx_spi_setreg(wc_dev, card, 14, 0x0); -+ a24xx_spi_setreg(wc_dev, card, 64, 0x0); -+ a24xx_spi_setreg(wc_dev, card, 1, 0x08); -+#endif -+ -+ if (fastringer) { -+ /* Speed up Ringer */ -+ si321x_proslic_setreg_indirect(wc_dev, card, 20, 0x7e6d); -+ si321x_proslic_setreg_indirect(wc_dev, card, 21, 0x01b9); -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ a24xx_spi_setreg(wc_dev, card, 74, 0x3f); -+ if (si321x_proslic_setreg_indirect(wc_dev, card, 21, 0x247)) { -+ return -1; -+ } -+ printk("Boosting fast ringer on slot %d (89V peak)\n", card + 1); -+ } else if (lowpower) { -+ if (si321x_proslic_setreg_indirect(wc_dev, card, 21, 0x14b)) { -+ return -1; -+ } -+ printk("Reducing fast ring power on slot %d (50V peak)\n", card + 1); -+ } else { -+ printk("Speeding up ringer on slot %d (25Hz)\n", card + 1); -+ } -+ } else { -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ a24xx_spi_setreg(wc_dev, card, 74, 0x3f); -+ if (si321x_proslic_setreg_indirect(wc_dev, card, 21, 0x1d1)) { -+ return -1; -+ } -+ printk("Boosting ringer on slot %d (89V peak)\n", card + 1); -+ } else if (lowpower) { -+ if (si321x_proslic_setreg_indirect(wc_dev, card, 21, 0x108)) { -+ return -1; -+ } -+ printk("Reducing ring power on slot %d (50V peak)\n", card + 1); -+ } -+ } -+ if (si321x_init_ring_generator_mode(wc_dev, card)) { -+ return -1; -+ } -+ if(fxstxgain || fxsrxgain) { -+ r9 = a24xx_spi_getreg(wc_dev, 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; -+ } -+ a24xx_spi_setreg(wc_dev,card,9,r9); -+ } -+ -+ if(debug) { -+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n", -+ ((a24xx_spi_getreg(wc_dev, card, 9)/8) == 1) ? "3.5": -+ (((a24xx_spi_getreg(wc_dev, card, 9)/4) == 1) ? "-3.5":"0.0"), -+ ((a24xx_spi_getreg(wc_dev, card, 9)/2) == 1) ?"3.5":((a24xx_spi_getreg(wc_dev,card,9)%2) ? "-3.5":"0.0") -+ ); -+ } -+ -+ a24xx_spi_setreg(wc_dev, card, 64, 0x01); -+ -+ return 0; -+} -+ -+/*** -+*return -+ ret_flag : not OK cards flag -+ blk_flag : not installed cards flag -+***/ -+int si321x_init_proslic_all(struct a24xx_dev *wc_dev, int fxs_flag,int fast, int manual, int sane,int *blk_flag) -+{ -+ int flag=fxs_flag,tmp_flag=0,ret_flag=0; -+ unsigned short tmp[24][5]; -+ unsigned char r19, r9; -+ int x,i; -+ int fxsmode=0; -+ -+ -+ for(i=0;i<wc_dev->max_cards;i++) -+ { -+ if(flag & (1 << i)){ -+ if((i%4) == 0){ -+ __a24xx_setcard(wc_dev, i); -+ __opvx_a24xx_write_8bits(wc_dev->mem32, 0x00); -+ __opvx_a24xx_write_8bits(wc_dev->mem32, 0x80); -+ } -+ -+ /* Sanity check the ProSLIC */ -+ if (!sane && si321x_proslic_insane(wc_dev, i)) { -+ tmp_flag |= 1<<i; -+ continue; -+ } -+ -+ /* default messages to none and method to FSK */ -+ memset(&wc_dev->mod[i].fxs.vmwisetting, 0, sizeof(wc_dev->mod[i].fxs.vmwisetting)); -+ wc_dev->mod[i].fxs.vmwi_lrev = 0; -+ wc_dev->mod[i].fxs.vmwi_hvdc = 0; -+ wc_dev->mod[i].fxs.vmwi_hvac = 0; -+ -+ /* By default, don't send on hook */ -+ if (reversepolarity) { -+ wc_dev->mod[i].fxs.idletxhookstate = 5; -+ } else { -+ wc_dev->mod[i].fxs.idletxhookstate = 1; -+ } -+ -+ if (sane) { -+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ -+ a24xx_spi_setreg(wc_dev, i, 14, 0x10); -+ } -+ -+ if (si321x_proslic_init_indirect_regs(wc_dev, i)) { -+ printk(KERN_INFO "Indirect Registers failed to initialize on module %d.\n", i); -+ tmp_flag |= 1<<i; -+ continue; -+ } -+ -+ /* Clear scratch pad area */ -+ si321x_proslic_setreg_indirect(wc_dev, i, 97,0); -+ -+ /* Clear digital loopback */ -+ a24xx_spi_setreg(wc_dev, i, 8, 0); -+ -+ /* Revision C optimization */ -+ a24xx_spi_setreg(wc_dev, i, 108, 0xeb); -+ -+ /* Disable automatic VBat switching for safety to prevent -+ Q7 from accidently turning on and burning out. */ -+ a24xx_spi_setreg(wc_dev, i, 67, 0x07); /* Note, if pulse dialing has problems at high REN loads -+ change this to 0x17 */ -+ -+ /* Turn off Q7 */ -+ a24xx_spi_setreg(wc_dev, i, 66, 1); -+ -+ /* Flush ProSLIC digital filters by setting to clear, while -+ saving old values */ -+ for (x=0;x<5;x++) { -+ tmp[i][x] = si321x_proslic_getreg_indirect(wc_dev, i, x + 35); -+ si321x_proslic_setreg_indirect(wc_dev, i, x + 35, 0x8000); -+ } -+ } -+ } -+ -+ /*remove not installed cards*/ -+ flag &= ~(tmp_flag); -+ if(blk_flag) -+ *blk_flag = tmp_flag; -+ -+ -+ touch_softlockup_watchdog(); -+ -+ /* Power up the DC-DC converter */ -+ tmp_flag = si321x_powerup_proslic_all(wc_dev, flag, fast); -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(tmp_flag & (1 << i)) -+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n",i); -+ } -+ -+ /*remove not OK cards flag*/ -+ flag &= ~(tmp_flag); -+ ret_flag |= tmp_flag; -+ -+ -+ if (!fast){ -+ /* Check for power leaks */ -+ tmp_flag=si321x_proslic_powerleak_test_all(wc_dev,flag); -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if( (flag & (1 << i)) && !(tmp_flag & (1 << i)) ){ -+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", i); -+ } -+ } -+ -+ /* Power up again */ -+ tmp_flag = si321x_powerup_proslic_all(wc_dev, flag, fast); -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(tmp_flag & (1 << i)) -+ printk("Unable to do FINAL ProSLIC powerup on module %d\n",i); -+ } -+ -+ /*remove not OK cards flag*/ -+ flag &= ~(tmp_flag); -+ ret_flag |= tmp_flag; -+ -+#ifndef NO_CALIBRATION -+ if(manual) { -+ tmp_flag = si321x_proslic_manual_calibrate_all(wc_dev,flag); -+ if(tmp_flag){ -+ tmp_flag = si321x_proslic_manual_calibrate_all(wc_dev,tmp_flag); -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(flag & (1 << i)){ -+ if(tmp_flag & (1 << i)) -+ printk("Proslic Failed on Second Attempt to Calibrate Manually module %d . (Try -DNO_CALIBRATION in Makefile)\n",i); -+ else -+ printk("Proslic Passed Manual Calibration on Second Attempt on module %d \n",i); -+ } -+ } -+ } -+ }else{ -+ tmp_flag = si321x_proslic_calibrate_all(wc_dev,flag); -+ if(tmp_flag){ -+ tmp_flag = si321x_proslic_calibrate_all(wc_dev,tmp_flag); -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(flag & (1 << i)){ -+ if(tmp_flag & (1 << i)) -+ printk("Proslic Failed on Second Attempt to Auto Calibrate module %d . (Try -DNO_CALIBRATION in Makefile)\n",i); -+ else -+ printk("Proslic Passed Auto Calibration on Second Attempt on module %d \n",i); -+ } -+ } -+ } -+ } -+ -+ /*remove not OK cards flag*/ -+ flag &= ~(tmp_flag); -+ ret_flag |= tmp_flag; -+ -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(flag & (1 << i)){ -+ /* Perform DC-DC calibration */ -+ a24xx_spi_setreg(wc_dev, i, 93, 0x99); -+ r19 = a24xx_spi_getreg(wc_dev, i, 107); -+ if ((r19 < 0x2) || (r19 > 0xd)) { -+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); -+ a24xx_spi_setreg(wc_dev, i, 107, 0x8); -+ } -+ /* Save calibration vectors */ -+ for (x=0;x<NUM_CAL_REGS;x++) { -+ wc_dev->mod[i].fxs.calregs.vals[x] = a24xx_spi_getreg(wc_dev, i, 96 + x); -+ } -+ } -+ } -+#endif -+ }else{ -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(flag & (1 << i)){ -+ /* Restore calibration registers */ -+ for (x=0;x<NUM_CAL_REGS;x++) { -+ a24xx_spi_setreg(wc_dev, i, 96 + x, wc_dev->mod[i].fxs.calregs.vals[x]); -+ } -+ } -+ } -+ } -+ -+ tmp_flag = 0; -+ for(i=0;i<wc_dev->max_cards;i++){ -+ if(flag & (1 << i)){ -+ /* Calibration complete, restore original values */ -+ for (x=0;x<5;x++) { -+ si321x_proslic_setreg_indirect(wc_dev, i, x + 35, tmp[i][x]); -+ } -+ -+ if (si321x_proslic_verify_indirect_regs(wc_dev, i)) { -+ printk(KERN_INFO "Indirect Registers failed verification on module %d.\n",i); -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ -+ -+ if (alawoverride) { -+ a24xx_spi_setreg(wc_dev, i, 1, 0x20); -+ } else { -+ a24xx_spi_setreg(wc_dev, i, 1, 0x28); -+ } -+ // U-Law 8-bit interface -+ a24xx_spi_setreg(wc_dev, i, 2, (i%4) * 8 + (i/4) * 32); // Tx Start count low byte 0 -+ a24xx_spi_setreg(wc_dev, i, 3, 0); // Tx Start count high byte 0 -+ a24xx_spi_setreg(wc_dev, i, 4, (i%4) * 8 + (i/4) * 32); // Rx Start count low byte 0 -+ a24xx_spi_setreg(wc_dev, i, 5, 0); // Rx Start count high byte 0 -+ a24xx_spi_setreg(wc_dev, i, 18, 0xff); // clear all interrupt -+ a24xx_spi_setreg(wc_dev, i, 19, 0xff); -+ a24xx_spi_setreg(wc_dev, i, 20, 0xff); -+ a24xx_spi_setreg(wc_dev, i, 73, 0x04); -+ if (fxshonormode) { -+ fxsmode = acim2tiss[fxo_modes[_opermode].acim]; -+ a24xx_spi_setreg(wc_dev, i, 10, 0x08 | fxsmode); -+ if (fxo_modes[_opermode].ring_osc) { -+ si321x_proslic_setreg_indirect(wc_dev, i, 20, fxo_modes[_opermode].ring_osc); -+ } -+ if (fxo_modes[_opermode].ring_x) { -+ si321x_proslic_setreg_indirect(wc_dev, i, 21, fxo_modes[_opermode].ring_x); -+ } -+ } -+ if (lowpower) { -+ a24xx_spi_setreg(wc_dev, i, 72, 0x10); -+ } -+ -+ if (fastringer) { -+ /* Speed up Ringer */ -+ si321x_proslic_setreg_indirect(wc_dev, i, 20, 0x7e6d); -+ si321x_proslic_setreg_indirect(wc_dev, i, 21, 0x01b9); -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ a24xx_spi_setreg(wc_dev, i, 74, 0x3f); -+ if (si321x_proslic_setreg_indirect(wc_dev, i, 21, 0x247)) { -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ printk("Boosting fast ringer on slot %d (89V peak)\n", i + 1); -+ } else if (lowpower) { -+ if (si321x_proslic_setreg_indirect(wc_dev, i, 21, 0x14b)) { -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ printk("Reducing fast ring power on slot %d (50V peak)\n", i + 1); -+ } else { -+ printk("Speeding up ringer on slot %d (25Hz)\n", i + 1); -+ } -+ } else { -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ a24xx_spi_setreg(wc_dev, i, 74, 0x3f); -+ if (si321x_proslic_setreg_indirect(wc_dev, i, 21, 0x1d1)) { -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ printk("Boosting ringer on slot %d (89V peak)\n", i + 1); -+ } else if (lowpower) { -+ if (si321x_proslic_setreg_indirect(wc_dev, i, 21, 0x108)) { -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ printk("Reducing ring power on slot %d (50V peak)\n", i + 1); -+ } -+ } -+ -+ if (si321x_init_ring_generator_mode(wc_dev, i)) { -+ tmp_flag |=(1<<i); -+ continue; -+ } -+ -+ if(fxstxgain || fxsrxgain) { -+ r9 = a24xx_spi_getreg(wc_dev, i, 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; -+ } -+ a24xx_spi_setreg(wc_dev,i,9,r9); -+ } -+ -+ if(debug) { -+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n", -+ ((a24xx_spi_getreg(wc_dev, i, 9)/8) == 1) ? "3.5": -+ (((a24xx_spi_getreg(wc_dev, i, 9)/4) == 1) ? "-3.5":"0.0"), -+ ((a24xx_spi_getreg(wc_dev, i, 9)/2) == 1) ?"3.5":((a24xx_spi_getreg(wc_dev,i,9)%2) ? "-3.5":"0.0") -+ ); -+ } -+ -+ a24xx_spi_setreg(wc_dev, i, 64, 0x01); -+ } -+ } -+ ret_flag |= tmp_flag; -+ -+ return ret_flag; -+} -+ -+int si321x_proslic_setreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address, unsigned short data) -+{ -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ ret = __a24xx_proslic_setreg_indirect(wc_dev, card, address, data); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+ -+ return ret; -+} -+ -+int si321x_proslic_getreg_indirect(struct a24xx_dev *wc_dev, int card, unsigned char address) -+{ -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&wc_dev->lock, flags); -+ ret = __a24xx_proslic_getreg_indirect(wc_dev, card, address); -+ spin_unlock_irqrestore(&wc_dev->lock, flags); -+ -+ return ret; -+} -+ -+void si321x_proslic_recheck_sanity(struct a24xx_dev *wc_dev, int card) -+{ -+ int res; -+ -+ /* Check loopback */ -+ res = wc_dev->reg1shadow[card]; -+ if (!res && (res != wc_dev->mod[card].fxs.lasttxhook)) // read real state from register By wx -+ res=a24xx_spi_getreg(wc_dev, card, 64); -+ if (!res && (res != wc_dev->mod[card].fxs.lasttxhook)) { -+ res = a24xx_spi_getreg(wc_dev, card, 8); -+ if (res) { -+ printk("Ouch, part reset, quickly restoring reality (%d)\n", card); -+ si321x_init_proslic(wc_dev, card, 1, 0, 1); -+ } else { -+ if (wc_dev->mod[card].fxs.palarms++ < MAX_ALARMS) { -+ printk("Power alarm on module %d, resetting!\n", card + 1); -+ if (wc_dev->mod[card].fxs.lasttxhook == 4) -+ wc_dev->mod[card].fxs.lasttxhook = 1; -+ a24xx_spi_setreg(wc_dev, card, 64, wc_dev->mod[card].fxs.lasttxhook); -+ } else { -+ if (wc_dev->mod[card].fxs.palarms == MAX_ALARMS) -+ printk("Too many power alarms on card %d, NOT resetting!\n", card + 1); -+ } -+ } -+ } -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/Kbuild 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/Kbuild 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,33 @@ -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OPVXD115) += opvxd115.o -+ -+FIRM_DIR := ../firmware -+ -+EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-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) -+ -+ifeq ($(HOTPLUG_FIRMWARE),yes) -+ EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE -+endif -+ -+opvxd115-objs := base.o vpm450m.o -+ -+ifneq ($(HOTPLUG_FIRMWARE),yes) -+opvxd115-objs += $(FIRM_DIR)/dahdi-fw-oct6114-032.o $(FIRM_DIR)/dahdi-fw-oct6114-064.o $(FIRM_DIR)/dahdi-fw-oct6114-128.o $(FIRM_DIR)/dahdi-fw-oct6114-256.o -+$(warning WARNING: You are compiling firmware into wct4xxp.ko which is not available under the terms of the GPL. It may be a violation of the GPL to distribute the resulting image since it combines both GPL and non-GPL work. You should consult a lawyer of your own before distributing such an image.) -+endif -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-032.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-032.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-064.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-064.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-128.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-128.o -+ -+$(obj)/$(FIRM_DIR)/dahdi-fw-oct6114-256.o: $(obj)/base.o -+ $(MAKE) -C $(obj)/$(FIRM_DIR) dahdi-fw-oct6114-256.o diff --git a/dahdi-linux-2.10.1-openvox-3.patch b/dahdi-linux-2.10.1-openvox-3.patch deleted file mode 100644 index e2598b5e8bef..000000000000 --- a/dahdi-linux-2.10.1-openvox-3.patch +++ /dev/null @@ -1,7272 +0,0 @@ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/base.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/base.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,5624 @@ -+/* -+ * TE410P Quad-T1/E1 PCI Driver version 0.1, 12/16/02 -+ * -+ * Written by Mark Spencer <markster@digium.com> -+ * Based on previous works, designs, and archetectures conceived and -+ * written by Jim Dixon <jim@lambdatel.com>. -+ * Further modified, optimized, and maintained by -+ * Matthew Fredrickson <creslin@digium.com> and -+ * Russ Meyerriecks <rmeyerriecks@digium.com> -+ * -+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony. -+ * Copyright (C) 2001-2012, 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 <linux/crc32.h> -+#include <linux/slab.h> -+ -+#include <stdbool.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 -+ -+/* Support first generation cards? */ -+#define SUPPORT_GEN1 -+ -+/* Define to get more attention-grabbing but slightly more I/O using -+ alarm status */ -+#undef 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 -+ -+#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 */ -+ struct cpu_workqueue_struct *cpu_wq; -+ 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_FORCE_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 -+ */ -+/* #define CONFIG_FORCE_EXTENDED_RESET */ -+/* #define CONFIG_NOEXTENDED_RESET */ -+ -+/* -+ * Uncomment the following definition in order to disable Active-State Power -+ * Management on the PCIe bridge for PCIe cards. This has been known to work -+ * around issues where the BIOS enables it on the cards even though the -+ * platform does not support it. -+ * -+ */ -+/* #define CONFIG_WCT4XXP_DISABLE_ASPM */ -+ -+#if defined(CONFIG_FORCE_EXTENDED_RESET) && defined(CONFIG_NOEXTENDED_RESET) -+#error "You cannot define both CONFIG_FORCE_EXTENDED_RESET and " \ -+ "CONFIG_NOEXTENDED_RESET." -+#endif -+ -+int debug = 0; -+static int timingcable = 0; -+static int t1e1override = -1; /* deprecated */ -+static char *default_linemode = "auto"; -+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*/ -+#endif /* VPM_SUPPORT */ -+ -+/* 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; -+static int ignore_rotary; -+ -+#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 FLAG_2NDGEN (1 << 3) -+#define FLAG_2PORT (1 << 4) -+#define FLAG_VPM2GEN (1 << 5) -+#define FLAG_OCTOPT (1 << 6) -+#define FLAG_3RDGEN (1 << 7) -+#define FLAG_BURST (1 << 8) -+#define FLAG_EXPRESS (1 << 9) -+#define FLAG_5THGEN (1 << 10) -+#define FLAG_8PORT (1 << 11) -+ -+#define FLAG_1PORT (1 << 15) -+#define CANARY 0xc0de -+ -+/* names of available HWEC modules */ -+#ifdef VPM_SUPPORT -+#define T4_VPM_PRESENT (1 << 28) -+static const char *vpmoct032_name = "VPMOCT032"; -+static const char *vpmoct064_name = "VPMOCT064"; -+static const char *vpmoct128_name = "VPMOCT128"; -+static const char *vpmoct256_name = "VPMOCT256"; -+#endif -+ -+struct devtype { -+ char *desc; -+ unsigned int flags; -+}; -+ -+static struct devtype opvxd115p2 = { "OpenVox D115P/D115E Single-port E1/T1 card (2nd GEN))", FLAG_2NDGEN | FLAG_1PORT}; -+static struct devtype opvxd130p5 = { "OpenVox D130P/D130E Single-port E1/T1 card (3rd GEN)", FLAG_5THGEN | FLAG_BURST | FLAG_2NDGEN | FLAG_3RDGEN | FLAG_1PORT}; -+ -+ -+struct t4; -+ -+enum linemode {T1, E1, J1}; -+ -+struct spi_state { -+ int wrreg; -+ int rdreg; -+}; -+ -+struct t4_span { -+ struct t4 *owner; -+ u32 *writechunk; /* Double-word aligned write memory */ -+ u32 *readchunk; /* Double-word aligned read memory */ -+ enum linemode linemode; -+ int sync; -+ int alarmtimer; -+ int notclear; -+ unsigned long alarm_time; -+ unsigned long losalarm_time; -+ unsigned long aisalarm_time; -+ unsigned long yelalarm_time; -+ unsigned long alarmcheck_time; -+ 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 -+ /* 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; -+#endif -+#ifdef ENABLE_WORKQUEUES -+ struct work_struct swork; -+#endif -+ struct dahdi_chan *chans[32]; /* Individual channels */ -+ struct dahdi_echocan_state *ec[32]; /* Echocan state for each channel */ -+}; -+ -+struct t4 { -+ /* This structure exists one per card */ -+ struct pci_dev *dev; /* Pointer to PCI device */ -+ unsigned int intcount; -+ int num; /* Which card we are */ -+ int syncsrc; /* active sync source */ -+ struct dahdi_device *ddev; -+ struct t4_span *tspans[8]; /* 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 */ -+ const struct devtype *devtype; -+ unsigned int reset_required:1; /* If reset needed in serial_setup */ -+ unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */ -+ unsigned int t1e1:8; /* T1 / E1 select pins */ -+ int ledreg; /* LED Register */ -+ int ledreg2; /* LED Register2 */ -+ unsigned int gpio; -+ unsigned int gpioctl; -+ int e1recover; /* E1 recovery timer */ -+ spinlock_t reglock; /* lock register access */ -+ int spansstarted; /* number of spans started */ -+ u32 *writechunk; /* Double-word aligned write memory */ -+ u32 *readchunk; /* Double-word aligned read memory */ -+#ifdef ENABLE_WORKQUEUES -+ atomic_t worklist; -+ struct workqueue_struct *workq; -+#endif -+ int last0; /* for detecting double-missed IRQ */ -+ -+ /* DMA related fields */ -+ unsigned int dmactrl; -+ dma_addr_t readdma; -+ dma_addr_t writedma; -+ void __iomem *membase; /* Base address of card */ -+ -+#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 -+ unsigned long checkflag; -+ struct work_struct bh_work; -+ /* Latency related additions */ -+ unsigned char rxident; -+ unsigned char lastindex; -+ int numbufs; -+ int needed_latency; -+ -+#ifdef VPM_SUPPORT -+ struct vpm450m *vpm; -+#endif -+ struct spi_state st; -+}; -+ -+static inline bool is_pcie(const struct t4 *wc) -+{ -+ return (wc->devtype->flags & FLAG_EXPRESS) > 0; -+} -+ -+static inline bool has_e1_span(const struct t4 *wc) -+{ -+ return (wc->t1e1 > 0); -+} -+ -+static inline bool is_octal(const struct t4 *wc) -+{ -+ return (wc->devtype->flags & FLAG_8PORT) > 0; -+} -+ -+static inline int T4_BASE_SIZE(struct t4 *wc) -+{ -+ if (is_octal(wc)) -+ return DAHDI_MAX_CHUNKSIZE * 32 * 8; -+ else -+ return DAHDI_MAX_CHUNKSIZE * 32 * 4; -+} -+ -+/** -+ * ports_on_framer - The number of ports on the framers. -+ * @wc: Board to check. -+ * -+ * The framer ports could be different the the number of ports on the card -+ * since the dual spans have four ports internally but two ports extenally. -+ * -+ */ -+static inline unsigned int ports_on_framer(const struct t4 *wc) -+{ -+ return (is_octal(wc)) ? 8 : 4; -+} -+ -+#ifdef VPM_SUPPORT -+static void t4_vpm_init(struct t4 *wc); -+ -+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); -+ -+static const struct dahdi_echocan_features vpm_ec_features = { -+ .NLP_automatic = 1, -+ .CED_tx_detect = 1, -+ .CED_rx_detect = 1, -+}; -+ -+static const struct dahdi_echocan_ops vpm_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_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); -+static int t4_reset_counters(struct dahdi_span *span); -+#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_LEDS2 12 -+ -+#define WC_SET_AUTH (1 << 20) -+#define WC_GET_AUTH (1 << 12) -+ -+#define WC_LFRMR_CS (1 << 10) /* Framer's ChipSelect signal */ -+#define WC_LCS (1 << 11) -+#define WC_LCS2 (1 << 12) -+#define WC_LALE (1 << 13) -+#define WC_LFRMR_CS2 (1 << 14) /* Framer's ChipSelect signal 2 */ -+#define WC_LREAD (1 << 15) -+#define WC_LWRITE (1 << 16) -+ -+#define WC_ACTIVATE (1 << 12) -+ -+#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 FMR5 0x21 /* Framer Mode Register 5 */ -+#define FMR5_XLU (1 << 4) /* Transmit loopup code */ -+#define FMR5_XLD (1 << 5) /* Transmit loopdown code */ -+#define FMR5_EIBR (1 << 6) /* Internal Bit Robbing Access */ -+#define DEC_T 0x60 /* Diable Error Counter */ -+#define IERR_T 0x1B /* Single Bit Defect Insertion Register */ -+#define IBV (1 << 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 struct t4 *cards[MAX_T4_CARDS]; -+ -+struct t8_firm_header { -+ u8 header[6]; -+ __le32 chksum; -+ u8 pad[18]; -+ __le32 version; -+} __packed; -+ -+#define MAX_TDM_CHAN 32 -+#define MAX_DTMF_DET 16 -+ -+#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF) -+#define HDLC_IMR1_MASK (FRMR_IMR1_XDU | FRMR_IMR1_XPR) -+ -+static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr) -+{ -+ unsigned int res = readl(wc->membase + (addr * sizeof(u32))); -+ return res; -+} -+ -+static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value) -+{ -+#ifdef DEBUG -+ unsigned int tmp; -+#endif -+ writel(value, wc->membase + (addr * sizeof(u32))); -+#ifdef DEBUG -+ tmp = __t4_pci_in(wc, WC_VERSION); -+ if ((tmp & 0xffff0000) != 0xc01a0000) -+ dev_notice(&wc->dev->dev, -+ "Version Synchronization Error!\n"); -+#else -+ __t4_pci_in(wc, WC_VERSION); -+#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) -+{ -+ if (span <= 3) { -+ 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); -+ } else { -+ int oldreg = wc->ledreg2; -+ -+ span &= 3; -+ wc->ledreg2 &= ~(0x3 << (span << 1)); -+ wc->ledreg2 |= (color << (span << 1)); -+ if (oldreg != wc->ledreg2) -+ __t4_pci_out(wc, WC_LEDS2, wc->ledreg2); -+ } -+} -+ -+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 unsigned int __t4_framer_in(const struct t4 *wc, int unit, -+ const unsigned int addr) -+{ -+ unsigned int ret; -+ register u32 val; -+ void __iomem *const wc_laddr = wc->membase + (WC_LADDR*sizeof(u32)); -+ void __iomem *const wc_version = wc->membase + (WC_VERSION*sizeof(u32)); -+ void __iomem *const wc_ldata = wc->membase + (WC_LDATA*sizeof(u32)); -+ int haddr = (((unit & 4) ? 0 : WC_LFRMR_CS2)); -+ unit &= 0x3; -+ -+ val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; -+ writel(val, wc_laddr); -+ readl(wc_version); -+ writel(val | WC_LFRMR_CS | WC_LREAD, wc_laddr); -+ readl(wc_version); -+ ret = readb(wc_ldata); -+ writel(val, wc_laddr); -+ readl(wc_version); -+ return ret; -+} -+ -+static 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 void __t4_framer_out(const struct t4 *wc, int unit, const u8 addr, -+ const unsigned int value) -+{ -+ register u32 val; -+ void __iomem *const wc_laddr = wc->membase + (WC_LADDR*sizeof(u32)); -+ void __iomem *const wc_version = wc->membase + (WC_VERSION*sizeof(u32)); -+ void __iomem *const wc_ldata = wc->membase + (WC_LDATA*sizeof(u32)); -+ int haddr = (((unit & 4) ? 0 : WC_LFRMR_CS2)); -+ -+ val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; -+ writel(val, wc_laddr); -+ readl(wc_version); -+ writel(value, wc_ldata); -+ readl(wc_version); -+ writel(val | WC_LFRMR_CS | WC_LWRITE, wc_laddr); -+ readl(wc_version); -+ writel(val, wc_laddr); -+ readl(wc_version); -+} -+ -+static 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 __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 (!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)); -+ __t4_pci_out(wc, WC_LADDR, (0)); -+} -+ -+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)); -+ __t4_pci_out(wc, WC_LADDR, (WC_LWRITE | WC_LALE)); -+ __t4_pci_out(wc, WC_LADDR, (WC_LALE)); -+ 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 (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 (!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 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 void t4_check_vpm(struct t4 *wc) -+{ -+ int channel, tone, start, span; -+ -+ if (vpm450m_checkirq(wc->vpm)) { -+ while(vpm450m_getdtmf(wc->vpm, &channel, &tone, &start)) { -+ span = channel & 0x3; -+ channel >>= 2; -+ if (!has_e1_span(wc)) -+ 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)); -+ } -+ } -+ } -+ } -+} -+ -+#endif /* VPM_SUPPORT */ -+ -+static void hdlc_stop(struct t4 *wc, unsigned int span) -+{ -+ struct t4_span *t = wc->tspans[span]; -+ unsigned char imr0, imr1, mode; -+ unsigned long flags; -+ 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); -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ 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; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* 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); -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* 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 (E1 != ts->linemode) { -+ 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); -+ } -+} -+ -+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 const char *__t4_echocan_name(struct t4 *wc) -+{ -+ if (wc->vpm) { -+ if (wc->numspans == 1) -+ return vpmoct032_name; -+ if (wc->numspans == 2) -+ return vpmoct064_name; -+ else if (wc->numspans == 4) -+ return vpmoct128_name; -+ else if (wc->numspans == 8) -+ return vpmoct256_name; -+ } -+ return NULL; -+} -+ -+static const char *t4_echocan_name(const struct dahdi_chan *chan) -+{ -+ struct t4 *wc = chan->pvt; -+ return __t4_echocan_name(wc); -+} -+ -+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 bool alaw = (chan->span->deflaw == 2); -+ -+ if (!vpmsupport || !wc->vpm) -+ return -ENODEV; -+ -+ if (ecp->param_count > 0) { -+ dev_warn(&wc->dev->dev, "%s echo canceller does not support " -+ "parameters; failing request\n", -+ chan->ec_factory->get_name(chan)); -+ return -EINVAL; -+ } -+ -+ *ec = tspan->ec[chan->chanpos - 1]; -+ (*ec)->ops = &vpm_ec_ops; -+ (*ec)->features = vpm_ec_features; -+ -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ 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_set_alaw_companding(wc->vpm, channel, alaw); -+ vpm450m_setec(wc->vpm, channel, ecp->tap_length); -+ return 0; -+} -+ -+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec) -+{ -+ struct t4 *wc = chan->pvt; -+ int channel; -+ -+ if (!wc->vpm) -+ return; -+ -+ memset(ec, 0, sizeof(*ec)); -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ 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->vpm, channel, 0); -+} -+#endif -+ -+static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) -+{ -+ struct t4_regs regs; -+ struct t4_reg reg; -+ int x; -+ struct t4 *wc = chan->pvt; -+#ifdef VPM_SUPPORT -+ int j; -+ int channel; -+ struct t4_span *ts = wc->tspans[chan->span->offset]; -+#endif -+ -+ switch(cmd) { -+ case WCT4_SET_REG: -+ if (copy_from_user(®, (struct t4_reg __user *)data, -+ sizeof(reg))) -+ return -EFAULT; -+ t4_pci_out(wc, reg.reg, reg.val); -+ break; -+ case WCT4_GET_REG: -+ if (copy_from_user(®, (struct t4_reg __user *)data, -+ sizeof(reg))) -+ return -EFAULT; -+ reg.val = t4_pci_in(wc, reg.reg); -+ if (copy_to_user((struct t4_reg __user *)data, -+ ®, sizeof(reg))) -+ return -EFAULT; -+ break; -+ 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((void __user *) 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); -+ -+ channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; -+ if (is_octal(wc)) -+ channel = channel << 3; -+ else -+ channel = channel << 2; -+ channel |= chan->span->offset; -+ vpm450m_setdtmf(wc->vpm, 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); -+ ++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); -+} -+ -+/** -+ * t4_set_framer_bits - Atomically set bits in a framer register. -+ */ -+static void t4_set_framer_bits(struct t4 *wc, unsigned int spanno, -+ unsigned int const addr, u16 bits) -+{ -+ unsigned long flags; -+ unsigned int reg; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reg = __t4_framer_in(wc, spanno, addr); -+ __t4_framer_out(wc, spanno, addr, (reg | bits)); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+} -+ -+static int t4_maint(struct dahdi_span *span, int cmd) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ unsigned int reg; -+ unsigned long flags; -+ -+ if (E1 == ts->linemode) { -+ 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); -+ t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); -+ break; -+ case DAHDI_MAINT_NETWORKLINELOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network line loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); -+ break; -+ case DAHDI_MAINT_NETWORKPAYLOADLOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network payload loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); -+ break; -+ case DAHDI_MAINT_LOOPUP: -+ case DAHDI_MAINT_LOOPDOWN: -+ dev_info(&wc->dev->dev, -+ "Loopup & loopdown not supported in E1 mode\n"); -+ return -ENOSYS; -+ 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"); -+ t4_set_framer_bits(wc, span->offset, FMR0, FMR0_SIM); -+ break; -+ 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); -+ t4_set_framer_bits(wc, span->offset, LIM0_T, LIM0_LL); -+ break; -+ case DAHDI_MAINT_NETWORKLINELOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network line loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, LIM1_T, LIM1_RL); -+ break; -+ case DAHDI_MAINT_NETWORKPAYLOADLOOP: -+ dev_info(&wc->dev->dev, -+ "Turning on network payload loopback\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR2_T, FMR2_PLB); -+ break; -+ case DAHDI_MAINT_LOOPUP: -+ dev_info(&wc->dev->dev, "Transmitting loopup code\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLU); -+ ts->span.maintstat = DAHDI_MAINT_REMOTELOOP; -+ break; -+ case DAHDI_MAINT_LOOPDOWN: -+ dev_info(&wc->dev->dev, "Transmitting loopdown code\n"); -+ t4_clear_maint(span); -+ t4_set_framer_bits(wc, span->offset, FMR5, FMR5_XLD); -+ break; -+ 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"); -+ return -ENOSYS; -+ case DAHDI_RESET_COUNTERS: -+ t4_reset_counters(span); -+ break; -+ case DAHDI_MAINT_ALARM_SIM: -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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 -+ */ -+ __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; -+ 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 = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ unsigned int reg; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* 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))); -+ -+ /* Clear loopup/loopdown signals on the line */ -+ reg = __t4_framer_in(wc, span->offset, FMR5); -+ __t4_framer_out(wc, span->offset, FMR5, (reg & ~(FMR5_XLU | FMR5_XLD))); -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ span->mainttimer = 0; -+ -+ return 0; -+} -+ -+static int t4_reset_counters(struct dahdi_span *span) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ memset(&ts->span.count, 0, sizeof(ts->span.count)); -+ return 0; -+} -+ -+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 (E1 == ts->linemode) { -+ 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 = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ -+ tspan = span->offset + 1; -+ if (tspan < 0) { -+ dev_notice(&wc->dev->dev, "D115: 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 == 8) && -+ (!(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->tspans[4]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[5]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[6]->span.flags & DAHDI_FLAG_RUNNING)) && -+ (!(wc->tspans[7]->span.flags & DAHDI_FLAG_RUNNING))) -+ || -+ ((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 */ -+ 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 (E1 == wc->linemode) { -+ /* 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 = container_of(span, struct t4_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, "D115: Configuring span %d\n", -+ span->spanno); -+ -+ if (lc->sync < 0) -+ lc->sync = 0; -+ if (lc->sync > wc->numspans) { -+ dev_warn(&wc->dev->dev, "WARNING: Cannot set priority on span %d to %d. Please set to a number between 1 and %d\n", -+ span->spanno, 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[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; -+ -+ 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_spanconfig(struct file *file, struct dahdi_span *span, -+ struct dahdi_lineconfig *lc) -+{ -+ int ret; -+ struct dahdi_device *const ddev = span->parent; -+ struct dahdi_span *s; -+ -+ ret = _t4_spanconfig(file, span, lc); -+ -+ /* Make sure all the spans have a basic configuration in case they are -+ * not all specified in the configuration files. */ -+ lc->sync = 0; -+ list_for_each_entry(s, &ddev->spans, device_node) { -+ WARN_ON(!s->channels); -+ if (!s->channels) -+ continue; -+ if (!s->chans[0]->sigcap) -+ _t4_spanconfig(file, s, lc); -+ } -+ return ret; -+} -+ -+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, "D115: Reconfigured " -+ "channel %d (%s) sigtype %d\n", -+ chan->channo, chan->name, sigtype); -+ else -+ dev_notice(&wc->dev->dev, "D115: 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 set_span_devicetype(struct t4 *wc) -+{ -+#ifdef VPM_SUPPORT -+ const char *vpmstring = __t4_echocan_name(wc); -+ -+ if (vpmstring) { -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s (%s)", -+ wc->devtype->desc, vpmstring); -+ } else { -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); -+ } -+#else -+ wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); -+#endif -+ -+ if (!wc->ddev->devicetype) -+ return -ENOMEM; -+ return 0; -+} -+ -+/* 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; -+ int basesize = T4_BASE_SIZE(wc) >> 2; -+ -+ if (!has_e1_span(wc)) -+ 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 * (basesize))); -+ ts->readchunk = (void *)(wc->readchunk + (x * 32 * 2) + (which * (basesize))); -+ 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 * (basesize))); -+ mychans->readchunk = (void *)(wc->readchunk + ((x * 32 + y + offset) * 2) + (which * (basesize))); -+ } -+ } -+ } -+} -+ -+static int __t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, -+ bool first_time); -+static int __t4_hardware_init_2(struct t4 *wc, bool first_time); -+ -+static int t4_hardware_stop(struct t4 *wc); -+ -+static void t4_framer_reset(struct t4 *wc) -+{ -+ const bool first_time = false; -+ bool have_vpm = wc->vpm != NULL; -+ if (have_vpm) { -+ release_vpm450m(wc->vpm); -+ wc->vpm = NULL; -+ } -+ t4_hardware_stop(wc); -+ __t4_set_sclk_src(wc, WC_SELF, 0, 0); -+ __t4_hardware_init_1(wc, wc->devtype->flags, first_time); -+ __t4_hardware_init_2(wc, first_time); -+ if (have_vpm) { -+ t4_vpm_init(wc); -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } -+ setup_chunks(wc, 0); -+ wc->lastindex = 0; -+} -+ -+/** -+ * t4_serial_setup - Setup serial parameters and system interface. -+ * @wc: The card to configure. -+ * -+ */ -+static void t4_serial_setup(struct t4 *wc) -+{ -+ unsigned long flags; -+ unsigned int unit; -+ bool reset_required = false; -+ -+ if (debug) { -+ dev_info(&wc->dev->dev, -+ "D115: Setting up global serial parameters\n"); -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reset_required = wc->reset_required > 0; -+ wc->reset_required = 0; -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (reset_required) -+ t4_framer_reset(wc); -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from -+ * channel 0 */ -+ __t4_framer_out(wc, 0, 0x85, 0xe0); -+ if (is_octal(wc)) -+ __t4_framer_out(wc, 0, FRMR_GPC2, 0x00); -+ -+ /* IPC: Interrupt push/pull active low */ -+ __t4_framer_out(wc, 0, 0x08, 0x01); -+ -+ if (is_octal(wc)) { -+ /* Global clocks (16.384 Mhz CLK) */ -+ __t4_framer_out(wc, 0, 0x92, 0x00); /* GCM1 */ -+ __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, 0x01); -+ __t4_framer_out(wc, 0, 0x97, 0x0b); -+ __t4_framer_out(wc, 0, 0x98, 0xdb); -+ __t4_framer_out(wc, 0, 0x99, 0xdf); -+ } else { -+ /* 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); -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ for (unit = 0; unit < ports_on_framer(wc); ++unit) { -+ spin_lock_irqsave(&wc->reglock, flags); -+ -+ /* Configure interrupts */ -+ /* GCR: Interrupt on Activation/Deactivation of each */ -+ __t4_framer_out(wc, unit, FRMR_GCR, 0x00); -+ -+ /* Configure system interface */ -+ if (is_octal(wc)) { -+ /* SIC1: 16.384 Mhz clock/bus, double buffer receive / -+ * transmit, byte interleaved */ -+ __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2 | 0x08); -+ } else { -+ /* SIC1: 8.192 Mhz clock/bus, double buffer receive / -+ * transmit, byte interleaved */ -+ __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2); -+ } -+ /* SIC2: No FFS, no center receive eliastic buffer, phase */ -+ __t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); -+ /* SIC3: Edges for capture */ -+ if (is_octal(wc)) { -+ __t4_framer_out(wc, unit, FRMR_SIC3, 0x04 | (1 << 4)); -+ } else { -+ __t4_framer_out(wc, unit, FRMR_SIC3, 0x04); -+ } -+ /* CMR2: We provide sync and clock for tx and rx. */ -+ __t4_framer_out(wc, unit, FRMR_CMR2, 0x00); -+ -+ if (is_octal(wc)) { -+ /* Set RCLK to 16 MHz */ -+ __t4_framer_out(wc, unit, FRMR_CMR4, 0x5); -+ -+ if (!has_e1_span(wc)) { /* T1/J1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x07); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ if (wc->tspans[unit]->linemode == J1) -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x87); -+ else -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x07); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } else { /* E1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } -+ -+ } else { -+ if (!has_e1_span(wc)) { /* T1/J1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x03); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x84); -+ if (J1 == wc->tspans[unit]->linemode) -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x83); -+ else -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x03); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x84); -+ } else { /* E1 mode */ -+ __t4_framer_out(wc, unit, FRMR_XC0, 0x00); -+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC0, 0x04); -+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04); -+ } -+ } -+ -+ /* Configure ports */ -+ -+ /* PC1: SPYR/SPYX input on RPA/XPA */ -+ __t4_framer_out(wc, unit, 0x80, 0x00); -+ -+ /* PC2: RMFB/XSIG output/input on RPB/XPB */ -+ /* PC3: Some unused stuff */ -+ /* PC4: Some more unused stuff */ -+ if (is_octal(wc)) { -+ __t4_framer_out(wc, unit, 0x81, 0xBB); -+ __t4_framer_out(wc, unit, 0x82, 0xf5); -+ __t4_framer_out(wc, unit, 0x83, 0x35); -+ } else if (wc->falc31) { -+ __t4_framer_out(wc, unit, 0x81, 0xBB); -+ __t4_framer_out(wc, unit, 0x82, 0xBB); -+ __t4_framer_out(wc, unit, 0x83, 0xBB); -+ } else { -+ __t4_framer_out(wc, unit, 0x81, 0x22); -+ __t4_framer_out(wc, unit, 0x82, 0x65); -+ __t4_framer_out(wc, unit, 0x83, 0x35); -+ } -+ -+ /* PC5: XMFS active low, SCLKR is input, RCLK is output */ -+ __t4_framer_out(wc, unit, 0x84, 0x01); -+ -+ if (debug & DEBUG_MAIN) { -+ dev_notice(&wc->dev->dev, -+ "Successfully initialized serial bus " -+ "for unit %d\n", unit); -+ } -+ -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ } -+} -+ -+/** -+ * t4_span_assigned - Called when the span is assigned by DAHDI. -+ * @span: Span that has been assigned. -+ * -+ * When this function is called, the span has a valid spanno and all the -+ * channels on the span have valid channel numbers assigned. -+ * -+ * This function is necessary because a device may be registered, and -+ * then user space may then later decide to assign span numbers and the -+ * channel numbers. -+ * -+ */ -+static void t4_span_assigned(struct dahdi_span *span) -+{ -+ struct t4_span *tspan = container_of(span, struct t4_span, span); -+ struct t4 *wc = tspan->owner; -+ struct dahdi_span *pos; -+ unsigned int unassigned_spans = 0; -+ unsigned long flags; -+ -+ /* We use this to make sure all the spans are assigned before -+ * running the serial setup. */ -+ list_for_each_entry(pos, &wc->ddev->spans, device_node) { -+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &pos->flags)) -+ ++unassigned_spans; -+ } -+ -+ if (0 == unassigned_spans) { -+ t4_serial_setup(wc); -+ -+ 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); -+ } -+} -+ -+static void free_wc(struct t4 *wc) -+{ -+ unsigned int x, y; -+ -+ flush_scheduled_work(); -+ -+ for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) { -+ if (!wc->tspans[x]) -+ continue; -+ for (y = 0; y < ARRAY_SIZE(wc->tspans[x]->chans); y++) { -+ kfree(wc->tspans[x]->chans[y]); -+ kfree(wc->tspans[x]->ec[y]); -+ } -+ kfree(wc->tspans[x]); -+ } -+ -+ kfree(wc->ddev->devicetype); -+ kfree(wc->ddev->location); -+ kfree(wc->ddev->hardware_id); -+ dahdi_free_device(wc->ddev); -+ kfree(wc); -+} -+ -+/** -+ * t4_alloc_channels - Allocate the channels on a span. -+ * @wc: The board we're allocating for. -+ * @ts: The span we're allocating for. -+ * @linemode: Which mode (T1/E1/J1) to use for this span. -+ * -+ * This function must only be called before the span is assigned it's -+ * possible for user processes to have an open reference to the -+ * channels. -+ * -+ */ -+static int t4_alloc_channels(struct t4 *wc, struct t4_span *ts, -+ enum linemode linemode) -+{ -+ int i; -+ -+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &ts->span.flags)) { -+ dev_dbg(&wc->dev->dev, -+ "Cannot allocate channels on a span that is already " -+ "assigned.\n"); -+ return -EINVAL; -+ } -+ -+ /* Cleanup any previously allocated channels. */ -+ for (i = 0; i < ARRAY_SIZE(ts->chans); ++i) { -+ kfree(ts->chans[i]); -+ kfree(ts->ec[i]); -+ ts->chans[i] = NULL; -+ ts->ec[i] = NULL; -+ } -+ -+ ts->linemode = linemode; -+ for (i = 0; i < ((E1 == ts->linemode) ? 31 : 24); i++) { -+ struct dahdi_chan *chan; -+ struct dahdi_echocan_state *ec; -+ -+ chan = kzalloc(sizeof(*chan), GFP_KERNEL); -+ if (!chan) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ ts->chans[i] = chan; -+ -+ ec = kzalloc(sizeof(*ec), GFP_KERNEL); -+ if (!ec) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ ts->ec[i] = ec; -+ } -+ -+ return 0; -+} -+ -+static void t4_init_one_span(struct t4 *wc, struct t4_span *ts) -+{ -+ unsigned long flags; -+ unsigned int reg; -+ int i; -+ -+ snprintf(ts->span.name, sizeof(ts->span.name) - 1, -+ "D115/%d/%d", wc->num, ts->span.offset + 1); -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, -+ "D115 (E1/T1) Card %d Span %d", wc->num, -+ ts->span.offset + 1); -+ -+ switch (ts->linemode) { -+ case T1: -+ ts->span.spantype = SPANTYPE_DIGITAL_T1; -+ break; -+ case E1: -+ ts->span.spantype = SPANTYPE_DIGITAL_E1; -+ break; -+ case J1: -+ ts->span.spantype = SPANTYPE_DIGITAL_J1; -+ break; -+ } -+ -+ /* HDLC Specific init */ -+ ts->sigchan = NULL; -+ ts->sigmode = sigmode; -+ ts->sigactive = 0; -+ -+ if (E1 != ts->linemode) { -+ 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; -+ -+ for (i = 0; i < ts->span.channels; i++) { -+ struct dahdi_chan *const chan = ts->chans[i]; -+ chan->pvt = wc; -+ snprintf(chan->name, sizeof(chan->name) - 1, -+ "%s/%d", ts->span.name, i + 1); -+ t4_chan_set_sigcap(&ts->span, i); -+ chan->chanpos = i + 1; -+ } -+ -+ /* Enable 1sec timer interrupt */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ reg = __t4_framer_in(wc, ts->span.offset, FMR1_T); -+ __t4_framer_out(wc, ts->span.offset, FMR1_T, (reg | FMR1_ECM)); -+ -+ /* Enable Errored Second interrupt */ -+ __t4_framer_out(wc, ts->span.offset, ESM, 0); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ t4_reset_counters(&ts->span); -+} -+ -+/** -+ * t4_set_linemode - Allows user space to change the linemode before spans are assigned. -+ * @span: span on which to change the linemode. -+ * @linemode: A value from enumerated spantypes -+ * -+ * This callback is used to override the E1/T1 mode jumper settings and set -+ * the linemode on for each span. Called when the "spantype" attribute -+ * is written in sysfs under the dahdi_device. -+ * -+ */ -+static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode) -+{ -+ struct t4_span *ts = container_of(span, struct t4_span, span); -+ struct t4 *wc = ts->owner; -+ int res = 0; -+ enum linemode mode; -+ const char *old_name; -+ static DEFINE_MUTEX(linemode_lock); -+ unsigned long flags; -+ -+ dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, -+ dahdi_spantype2str(linemode)); -+ -+ if (span->spantype == linemode) -+ return 0; -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ wc->reset_required = 1; -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* Do not allow the t1e1 member to be changed by multiple threads. */ -+ mutex_lock(&linemode_lock); -+ old_name = dahdi_spantype2str(span->spantype); -+ switch (linemode) { -+ case SPANTYPE_DIGITAL_T1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to T1 line mode.\n", old_name); -+ mode = T1; -+ wc->t1e1 &= ~(1 << span->offset); -+ break; -+ case SPANTYPE_DIGITAL_E1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to E1 line mode.\n", old_name); -+ mode = E1; -+ wc->t1e1 |= (1 << span->offset); -+ break; -+ case SPANTYPE_DIGITAL_J1: -+ dev_info(&wc->dev->dev, -+ "Changing from %s to J1 line mode.\n", old_name); -+ mode = J1; -+ wc->t1e1 &= ~(1 << span->offset); -+ break; -+ default: -+ dev_err(&wc->dev->dev, -+ "Got invalid linemode %d from dahdi\n", linemode); -+ res = -EINVAL; -+ } -+ -+ if (!res) { -+ t4_alloc_channels(wc, ts, mode); -+ t4_init_one_span(wc, ts); -+ dahdi_init_span(span); -+ } -+ -+ mutex_unlock(&linemode_lock); -+ return res; -+} -+ -+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, -+ .ioctl = t4_ioctl, -+ .hdlc_hard_xmit = t4_hdlc_hard_xmit, -+ .assigned = t4_span_assigned, -+ .set_spantype = t4_set_linemode, -+}; -+ -+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, -+ .ioctl = t4_ioctl, -+ .hdlc_hard_xmit = t4_hdlc_hard_xmit, -+ .dacs = t4_dacs, -+ .assigned = t4_span_assigned, -+ .set_spantype = t4_set_linemode, -+#ifdef VPM_SUPPORT -+ .echocan_create = t4_echocan_create, -+ .echocan_name = t4_echocan_name, -+#endif -+}; -+ -+/** -+ * init_spans - Do first initialization on all the spans -+ * @wc: Card to initialize the spans on. -+ * -+ * This function is called *before* the dahdi_device is first registered -+ * with the system. What happens in t4_init_one_span can happen between -+ * when the device is registered and when the spans are assigned via -+ * sysfs (or automatically). -+ * -+ */ -+static void init_spans(struct t4 *wc) -+{ -+ int x, y; -+ int gen2; -+ struct t4_span *ts; -+ unsigned int reg; -+ unsigned long flags; -+ -+ gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN); -+ for (x = 0; x < wc->numspans; x++) { -+ ts = wc->tspans[x]; -+ -+ sprintf(ts->span.name, "D115/%d/%d", wc->num, x + 1); -+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, -+ "D115 (E1/T1) Card %d Span %d", wc->num, x+1); -+ switch (ts->linemode) { -+ case T1: -+ ts->span.spantype = SPANTYPE_DIGITAL_T1; -+ break; -+ case E1: -+ ts->span.spantype = SPANTYPE_DIGITAL_E1; -+ break; -+ case J1: -+ ts->span.spantype = SPANTYPE_DIGITAL_J1; -+ break; -+ } -+ -+ /* HDLC Specific init */ -+ ts->sigchan = NULL; -+ ts->sigmode = sigmode; -+ ts->sigactive = 0; -+ -+ if (E1 != ts->linemode) { -+ 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); -+ -+ if (gen2) { -+ ts->span.ops = &t4_gen2_span_ops; -+ } else { -+ ts->span.ops = &t4_gen1_span_ops; -+ } -+ -+ for (y=0;y<wc->tspans[x]->span.channels;y++) { -+ struct dahdi_chan *mychans = ts->chans[y]; -+ sprintf(mychans->name, "D115/%d/%d/%d", wc->num, x + 1, y + 1); -+ t4_chan_set_sigcap(&ts->span, x); -+ mychans->pvt = wc; -+ mychans->chanpos = y + 1; -+ } -+ -+ /* Start checking for alarms in 250 ms */ -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(250); -+ -+ /* Enable 1sec timer interrupt */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ t4_reset_counters(&ts->span); -+ -+ } -+ -+ set_span_devicetype(wc); -+ setup_chunks(wc, 0); -+ wc->lastindex = 0; -+} -+ -+static int syncsrc = 0; -+static int syncnum = 0 /* -1 */; -+static int syncspan = 0; -+static DEFINE_SPINLOCK(synclock); -+ -+static void __t4_set_rclk_src(struct t4 *wc, int span) -+{ -+ if (is_octal(wc)) { -+ int cmr5 = 0x00 | (span << 5); -+ int cmr1 = 0x38; /* Clock Mode: RCLK sourced by DCO-R1 -+ by default, Disable Clock-Switching */ -+ -+ __t4_framer_out(wc, 0, 0x44, cmr1); -+ __t4_framer_out(wc, 0, FRMR_CMR5, cmr5); -+ } else { -+ 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); -+} -+ -+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); -+} -+ -+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; /* wct4xxp card number */ -+ int newsyncspan = 0; /* span on given wct4xxp card */ -+ spin_lock_irqsave(&synclock, flags); -+ 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 < cards[x]->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); -+ spin_unlock_irqrestore(&synclock, flags); -+ return 0; -+} -+ -+static void __t4_set_timing_source_auto(struct t4 *wc) -+{ -+ int x, i; -+ 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); -+ } -+ -+ /* Propagate sync selection to dahdi_span struct -+ * this is read by dahdi_tool to display the span's -+ * master/slave sync information */ -+ for (i = 0; i < wc->numspans; i++) { -+ wc->tspans[i]->span.syncsrc = wc->syncsrc + 1; -+ } -+ } -+} -+ -+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; -+ -+ if (is_octal(wc)) -+ fmr1 = 0x9c | 0x02; /* FMR1: Mode 1, T1 mode, CRC on for ESF, 8.192 Mhz system data rate, no XAIS */ -+ else -+ 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 = (is_octal(wc) || 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, FMR5, FMR5_EIBR); /* 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; -+ if (is_octal(wc)) { -+ /* 16 MHz */ -+ fmr1 = 0x44 | 0x02; /* FMR1: E1 mode, Automatic force resync, PCM30 mode, 8.192 Mhz backplane, no XAIS */ -+ } else { -+ /* 8 MHz */ -+ 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 = (is_octal(wc) || 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 */ -+ -+ __t4_framer_out(wc, unit, 0x2f, 0x00); -+ __t4_framer_out(wc, unit, 0x30, 0x00); -+ __t4_framer_out(wc, unit, 0x31, 0x00); -+ -+ dev_info(&wc->dev->dev, "opvxd115: Span %d configured for %s/%s%s\n", -+ unit + 1, framing, line, crc4); -+} -+ -+/** -+ * t4_check_for_interrupts - Return 0 if the card is generating interrupts. -+ * @wc: The card to check. -+ * -+ * If the card is not generating interrupts, this function will also place all -+ * the spans on the card into red alarm. -+ * -+ */ -+static int t4_check_for_interrupts(struct t4 *wc) -+{ -+ unsigned int starting_intcount = wc->intcount; -+ unsigned long stop_time = jiffies + HZ*2; -+ unsigned long flags; -+ int x; -+ -+ msleep(20); -+ spin_lock_irqsave(&wc->reglock, flags); -+ while (starting_intcount == wc->intcount) { -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ if (time_after(jiffies, stop_time)) { -+ for (x = 0; x < wc->numspans; x++) -+ wc->tspans[x]->span.alarms = DAHDI_ALARM_RED; -+ dev_err(&wc->dev->dev, "Interrupts not detected.\n"); -+ return -EIO; -+ } -+ msleep(100); -+ spin_lock_irqsave(&wc->reglock, flags); -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ return 0; -+} -+ -+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 = container_of(span, struct t4_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 (E1 == ts->linemode) -+ __t4_configure_e1(wc, span->offset, span->lineconfig); -+ else -+ __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->devtype->flags & FLAG_5THGEN) -+ __t4_pci_out(wc, 5, (ms_per_irq << 16) | wc->numbufs); -+ else -+ __t4_pci_out(wc, 5, (1 << 16) | 1); -+ /* enable interrupts */ -+ /* Start DMA, enabling DMA interrupts on read only */ -+ wc->dmactrl |= (ts->spanflags & FLAG_2NDGEN) ? 0xc0000000 : 0xc0000003; -+#ifdef VPM_SUPPORT -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+#endif -+ /* Seed interrupt register */ -+ __t4_pci_out(wc, WC_INTR, 0x0c); -+ if (noburst || !(ts->spanflags & FLAG_BURST)) -+ wc->dmactrl |= (1 << 26); -+ else -+ 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); -+ -+ local_irq_save(flags); -+ t4_check_alarms(wc, span->offset); -+ t4_check_sigbits(wc, span->offset); -+ local_irq_restore(flags); -+ -+ if (wc->tspans[0]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Primary Sync Source\n", -+ span->spanno); -+ if (wc->numspans >= 2) { -+ if (wc->tspans[1]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Secondary Sync Source\n", -+ span->spanno); -+ } -+ if (wc->numspans >= 4) { -+ if (wc->tspans[2]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Tertiary Sync Source" -+ "\n", span->spanno); -+ if (wc->tspans[3]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Quaternary Sync " -+ "Source\n", span->spanno); -+ } -+ if (wc->numspans == 8) { -+ if (wc->tspans[4]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Quinary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[5]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Senary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[6]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Septenary Sync " -+ "Source\n", span->spanno); -+ if (wc->tspans[7]->sync == span->spanno) -+ dev_info(&wc->dev->dev, "SPAN %d: Octonary Sync " -+ "Source\n", span->spanno); -+ } -+ -+ if (!alreadyrunning) { -+ if (t4_check_for_interrupts(wc)) -+ return -EIO; -+ } -+ -+ if (debug) -+ dev_info(&wc->dev->dev, "Completed startup!\n"); -+ clear_bit(T4_IGNORE_LATENCY, &wc->checkflag); -+ return 0; -+} -+ -+static int t4_startup(struct file *file, struct dahdi_span *span) -+{ -+ int ret; -+ struct dahdi_device *const ddev = span->parent; -+ struct dahdi_span *s; -+ -+ ret = _t4_startup(file, span); -+ list_for_each_entry(s, &ddev->spans, device_node) { -+ if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags)) { -+ _t4_startup(file, s); -+ } -+ } -+ return ret; -+} -+ -+#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; -+ if (wc->numspans == 1) -+ wc->tspans[0]->e1check = 0; -+ if (wc->numspans >= 2) -+ wc->tspans[0]->e1check = wc->tspans[1]->e1check = 0; -+ if (wc->numspans == 4) -+ wc->tspans[2]->e1check = wc->tspans[3]->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) -+{ -+ unsigned int *readchunk; -+ int dbl = 0; -+ int x,y,z; -+ unsigned int tmp; -+ int offset=0; -+ if (!has_e1_span(wc)) -+ 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 (unlikely(dbl && (debug & DEBUG_MAIN))) -+ dev_notice(&wc->dev->dev, "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]; -+ if (wc->numspans == 4) { -+ wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; -+ wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; -+ } -+ wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; -+ wc->tspans[0]->span.chans[z]->readchunk[x] = tmp >> 24; -+ } -+ if (has_e1_span(wc)) { -+ if (wc->e1recover > 0) -+ wc->e1recover--; -+ tmp = readchunk[0]; -+ if (wc->numspans == 4) { -+ e1_check(wc, 3, (tmp & 0x7f)); -+ e1_check(wc, 2, (tmp & 0x7f00) >> 8); -+ } -+ e1_check(wc, 1, (tmp & 0x7f0000) >> 16); -+ e1_check(wc, 0, (tmp & 0x7f000000) >> 24); -+ for (z=24;z<31;z++) { -+ /* Only E1 channels now */ -+ tmp = readchunk[z+1]; -+ if (wc->numspans == 4) { -+ if (wc->tspans[3]->span.channels > 24) -+ wc->tspans[3]->span.chans[z]->readchunk[x] = tmp & 0xff; -+ if (wc->tspans[2]->span.channels > 24) -+ wc->tspans[2]->span.chans[z]->readchunk[x] = (tmp & 0xff00) >> 8; -+ } -+ if (wc->tspans[1]->span.channels > 24) -+ wc->tspans[1]->span.chans[z]->readchunk[x] = (tmp & 0xff0000) >> 16; -+ 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 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 -+ _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) -+{ -+ u32 *writechunk; -+ int x, y, z; -+ unsigned int tmp; -+ int offset = 0; -+ if (!has_e1_span(wc)) -+ 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[3]->span.chans[z]->writechunk[x]) | -+ (wc->tspans[2]->span.chans[z]->writechunk[x] << 8) | -+ (wc->tspans[1]->span.chans[z]->writechunk[x] << 16) | -+ (wc->tspans[0]->span.chans[z]->writechunk[x] << 24); -+ writechunk[z+offset] = tmp; -+ } -+ if (has_e1_span(wc)) { -+ for (z=24;z<31;z++) { -+ /* Only E1 channels now */ -+ tmp = 0; -+ if (wc->numspans == 4) { -+ if (wc->tspans[3]->span.channels > 24) -+ tmp |= wc->tspans[3]->span.chans[z]->writechunk[x]; -+ if (wc->tspans[2]->span.channels > 24) -+ tmp |= (wc->tspans[2]->span.chans[z]->writechunk[x] << 8); -+ } -+ if (wc->tspans[1]->span.channels > 24) -+ tmp |= (wc->tspans[1]->span.chans[z]->writechunk[x] << 16); -+ 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_dahdi_rbsbits(struct dahdi_chan *const chan, int rxs) -+{ -+ if ((debug & DEBUG_RBS) && printk_ratelimit()) { -+ const struct t4_span *tspan = container_of(chan->span, -+ struct t4_span, -+ span); -+ const struct t4 *const wc = tspan->owner; -+ dev_notice(&wc->dev->dev, "Detected sigbits change on " \ -+ "channel %s to %04x\n", chan->name, rxs); -+ } -+ dahdi_rbsbits(chan, rxs); -+} -+ -+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 (E1 == ts->linemode) { -+ 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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) -+ t4_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) { -+ t4_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) { -+ t4_dahdi_rbsbits(ts->span.chans[i], rxs); -+ } -+ } -+ } -+ } -+} -+ -+/* Must be called from within hardirq context. */ -+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]; -+ -+ if (time_before(jiffies, ts->alarmcheck_time)) -+ return; -+ -+ if (!(ts->span.flags & DAHDI_FLAG_RUNNING)) -+ return; -+ -+ spin_lock(&wc->reglock); -+ -+ 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 (E1 == ts->linemode) { -+ 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, -+ "Lost crc4-multiframe alignment\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, -+ "Obtained crc4-multiframe alignment\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)) { -+ dev_notice(&wc->dev->dev, -+ "span %d: Loopup detected,"\ -+ " enabling remote loop\n", -+ span+1); -+ __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)) { -+ dev_notice(&wc->dev->dev, -+ "span %d: Loopdown detected,"\ -+ " disabling remote loop\n", -+ span+1); -+ __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) || -+ dahdi_have_netdev(ts->span.chans[x])) -+ j++; -+ if (!j) -+ alarms |= DAHDI_ALARM_NOTOPEN; -+ } -+ -+ /* Loss of Frame Alignment */ -+ if (c & 0x20) { -+ if (!ts->alarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce LOF/LFA */ -+ dev_info(&wc->dev->dev, "D115: LOF/LFA " -+ "detected on span %d but debouncing " -+ "for %d ms\n", span + 1, -+ alarmdebounce); -+ } -+ ts->alarm_time = jiffies + -+ msecs_to_jiffies(alarmdebounce); -+ } else if (time_after(jiffies, ts->alarm_time)) { -+ /* Disable Slip Interrupts */ -+ e = __t4_framer_in(wc, span, 0x17); -+ __t4_framer_out(wc, span, 0x17, (e|0x03)); -+ -+ alarms |= DAHDI_ALARM_RED; -+ } -+ } else { -+ ts->alarm_time = 0; -+ } -+ -+ /* Loss of Signal */ -+ if (c & 0x80) { -+ if (!ts->losalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce LOS */ -+ dev_info(&wc->dev->dev, "D115: LOS " -+ "detected on span %d but debouncing " -+ "for %d ms\n", -+ span + 1, losalarmdebounce); -+ } -+ ts->losalarm_time = jiffies + -+ msecs_to_jiffies(losalarmdebounce); -+ } else if (time_after(jiffies, ts->losalarm_time)) { -+ /* Disable Slip Interrupts */ -+ e = __t4_framer_in(wc, span, 0x17); -+ __t4_framer_out(wc, span, 0x17, (e|0x03)); -+ -+ alarms |= DAHDI_ALARM_RED; -+ } -+ } else { -+ ts->losalarm_time = 0; -+ } -+ -+ /* Alarm Indication Signal */ -+ if (c & 0x40) { -+ if (!ts->aisalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce AIS */ -+ dev_info(&wc->dev->dev, "D115: AIS " -+ "detected on span %d but debouncing " -+ "for %d ms\n", -+ span + 1, aisalarmdebounce); -+ } -+ ts->aisalarm_time = jiffies + -+ msecs_to_jiffies(aisalarmdebounce); -+ } else if (time_after(jiffies, ts->aisalarm_time)) { -+ alarms |= DAHDI_ALARM_BLUE; -+ } -+ } else { -+ ts->aisalarm_time = 0; -+ } -+ -+ /* 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"); -+ } -+ } -+ -+ 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->yelalarm_time) { -+ if (unlikely(debug)) { -+ /* starting to debounce AIS */ -+ dev_info(&wc->dev->dev, "D115: yellow " -+ "(RAI) detected on span %d but " -+ "debouncing for %d ms\n", -+ span + 1, -+ yelalarmdebounce); -+ } -+ ts->yelalarm_time = jiffies + -+ msecs_to_jiffies(yelalarmdebounce); -+ } else if (time_after(jiffies, ts->yelalarm_time)) { -+ alarms |= DAHDI_ALARM_YELLOW; -+ } -+ } else { -+ ts->yelalarm_time = 0; -+ } -+ -+ if (alarms) -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(100); -+ else -+ ts->alarmcheck_time = jiffies + msecs_to_jiffies(50); -+ -+ if (ts->span.mainttimer || ts->span.maintstat) -+ alarms |= DAHDI_ALARM_LOOPBACK; -+ ts->span.alarms = alarms; -+ -+ spin_unlock(&wc->reglock); -+ 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]; -+ -+ spin_lock(&wc->reglock); -+ if (ts->alarmtimer && (0 == (--ts->alarmtimer))) -+ ts->span.alarms &= ~(DAHDI_ALARM_RECOVER); -+ spin_unlock(&wc->reglock); -+ -+ t4_check_alarms(wc, 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->losalarm_time) { -+#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 >= ARRAY_SIZE(altab)) -+ wc->alarmpos = 0; -+ } -+#else -+ if (wc->blinktimer == 480) -+ wc->blinktimer = 0; -+#endif -+} -+ -+static inline void t4_framer_interrupt(struct t4 *wc, int span) -+{ -+ /* Check interrupts for a given span */ -+ unsigned char gis, isr0, isr1, isr2, isr3, isr4; -+ int readsize = -1; -+ struct t4_span *ts = wc->tspans[span]; -+ struct dahdi_chan *sigchan; -+ unsigned long flags; -+ bool recheck_sigbits = false; -+ -+ -+ /* 1st gen cards isn't used interrupts */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ } -+ -+ /* 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); -+ if (DAHDI_RXSIG_INITIAL == ts->span.chans[0]->rxhooksig) -+ recheck_sigbits = true; -+ } -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ /* Collect errored second counter once per second */ -+ if (isr3 & ISR3_ES) { -+ ts->span.count.errsec += 1; -+ } -+ -+ if (isr0 & 0x08 || recheck_sigbits) -+ t4_check_sigbits(wc, span); -+ -+ if (E1 == ts->linemode) { -+ /* 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]; -+ unsigned char rsis_reg = t4_framer_in(wc, span, FRMR_RSIS); -+ -+ ++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); -+ } -+ } 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; -+ -+ /* 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 (status & 0x3) { -+ t4_receiveprep(wc, status); -+ t4_transmitprep(wc, status); -+ } -+ -+ 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); -+} -+ -+DAHDI_IRQ_HANDLER(t4_interrupt) -+{ -+ irqreturn_t ret; -+ unsigned long flags; -+ local_irq_save(flags); -+ ret = _t4_interrupt(irq, dev_id); -+ local_irq_restore(flags); -+ return ret; -+} -+#endif -+ -+static int t4_allocate_buffers(struct t4 *wc, int numbufs, -+ void **oldalloc, dma_addr_t *oldwritedma) -+{ -+ void *alloc; -+ dma_addr_t writedma; -+ -+ /* 32 channels, Double-buffer, Read/Write, 4 spans */ -+ alloc = pci_alloc_consistent(wc->dev, numbufs * T4_BASE_SIZE(wc) * 2, -+ &writedma); -+ -+ if (!alloc) { -+ dev_notice(&wc->dev->dev, "D115: Unable to allocate " -+ "DMA-able memory\n"); -+ 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(wc) * numbufs) / 4; -+ -+ /* Same thing but in bytes... */ -+ wc->readdma = wc->writedma + (T4_BASE_SIZE(wc) * numbufs); -+ -+ wc->numbufs = numbufs; -+ -+ /* Initialize Write/Buffers to all blank data */ -+ memset(wc->writechunk, 0x00, T4_BASE_SIZE(wc) * numbufs); -+ memset(wc->readchunk, 0xff, T4_BASE_SIZE(wc) * numbufs); -+ -+ if (debug) { -+ dev_notice(&wc->dev->dev, "DMA memory base of size %d at " \ -+ "%p. Read: %p and Write %p\n", -+ numbufs * T4_BASE_SIZE(wc) * 2, wc->writechunk, -+ wc->readchunk, wc->writechunk); -+ } -+ -+ return 0; -+} -+ -+static void t4_increase_latency(struct t4 *wc, int newlatency) -+{ -+ unsigned long flags; -+ void *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(wc) * oldbufs * 2, -+ oldalloc, oldaddr); -+ -+ dev_info(&wc->dev->dev, "Increased latency to %d\n", newlatency); -+ -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -+static void t4_work_func(void *data) -+{ -+ struct t4 *wc = data; -+#else -+static void t4_work_func(struct work_struct *work) -+{ -+ struct t4 *wc = container_of(work, struct t4, bh_work); -+#endif -+ -+ 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)) { -+ /* 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_vpm(wc); -+ } -+ } -+#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->devtype->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) { -+ dev_info(&wc->dev->dev, "Need to increase " -+ "latency. Estimated latency should " -+ "be %d\n", needed_latency); -+ 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; -+ } -+ -+#ifdef DEBUG -+ if (unlikely((wc->intcount < 20))) -+ dev_dbg(&wc->dev->dev, "2G: Got interrupt, status = %08x, " -+ "CIS = %04x\n", status, t4_framer_in(wc, 0, FRMR_CIS)); -+#endif -+ -+ 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); -+ if (wc->tspans[1]->span.flags & DAHDI_FLAG_RUNNING) -+ t4_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) -+ t4_queue_work(wc->workq, &wc->tspans[2]->swork, 2 % cpus); -+ else -+ atomic_dec(&wc->worklist); -+ if (wc->tspans[3]->span.flags & DAHDI_FLAG_RUNNING) -+ t4_queue_work(wc->workq, &wc->tspans[3]->swork, 3 % cpus); -+ else -+ atomic_dec(&wc->worklist); -+ } -+#else -+ unsigned int reg5 = __t4_pci_in(wc, 5); -+ -+#ifdef DEBUG -+ if (wc->intcount < 20) -+ dev_info(&wc->dev->dev, "Reg 5 is %08x\n", reg5); -+#endif -+ -+ if (wc->devtype->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 (is_octal(wc)) { -+ if (cis & FRMR_CIS_GIS5) -+ t4_framer_interrupt(wc, 4); -+ if (cis & FRMR_CIS_GIS6) -+ t4_framer_interrupt(wc, 5); -+ if (cis & FRMR_CIS_GIS7) -+ t4_framer_interrupt(wc, 6); -+ if (cis & FRMR_CIS_GIS8) -+ t4_framer_interrupt(wc, 7); -+ } -+ } -+ -+#ifdef VPM_SUPPORT -+ if (wc->vpm && vpmdtmfsupport) { -+ /* 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); -+ } -+#endif -+ -+ 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))) -+ schedule_work(&wc->bh_work); -+ -+#ifndef ENABLE_WORKQUEUES -+ __t4_pci_out(wc, WC_INTR, 0); -+#endif -+ -+ return IRQ_RETVAL(1); -+} -+ -+DAHDI_IRQ_HANDLER(t4_interrupt_gen2) -+{ -+ irqreturn_t ret; -+ unsigned long flags; -+ local_irq_save(flags); -+ ret = _t4_interrupt_gen2(irq, dev_id); -+ local_irq_restore(flags); -+ return ret; -+} -+ -+#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) ? T4_VPM_PRESENT : 0); -+#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_init(struct t4 *wc) -+{ -+ int laws[8] = { 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 void _binary_dahdi_fw_oct6114_256_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[]; -+ extern u8 _binary_dahdi_fw_oct6114_256_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"; -+ static const char oct256_firmware[] = "dahdi-fw-oct6114-256.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); -+ __t4_raw_oct_in(wc, 0x0004); -+ __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; -+ } -+ -+ vpm_capacity = get_vpm450m_capacity(&wc->dev->dev); -+ if (vpm_capacity != wc->numspans * 32) { -+ dev_info(&wc->dev->dev, "Disabling VPMOCT%03d. D115"\ -+ " requires a VPMOCT%03d", vpm_capacity, -+ wc->numspans*32); -+ return; -+ } -+ -+ switch (vpm_capacity) { -+ 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; -+ case 256: -+#if defined(HOTPLUG_FIRMWARE) -+ if ((request_firmware(&firmware, oct256_firmware, &wc->dev->dev) != 0) || -+ !firmware) { -+ dev_notice(&wc->dev->dev, "VPM450: firmware %s not " -+ "available from userspace\n", oct256_firmware); -+ return; -+ } -+#else -+ embedded_firmware.data = _binary_dahdi_fw_oct6114_256_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_256_bin_size; -+#endif -+ break; -+ default: -+ dev_notice(&wc->dev->dev, "Unsupported channel capacity found " -+ "on VPM module (%d).\n", vpm_capacity); -+ return; -+ } -+ -+ wc->vpm = init_vpm450m(&wc->dev->dev, laws, wc->numspans, firmware); -+ if (!wc->vpm) { -+ 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_info(&wc->dev->dev, "VPM450: hardware DTMF disabled.\n"); -+ vpmdtmfsupport = 0; -+ } -+ -+ dev_info(&wc->dev->dev, "VPM450: Present and operational servicing %d " -+ "span(s)\n", wc->numspans); -+ -+} -+#endif /* VPM_SUPPORT */ -+ -+static void t4_tsi_reset(struct t4 *wc) -+{ -+ int x; -+ if (is_octal(wc)) { -+ for (x = 0; x < 256; x++) { -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= (0x00004000 | ((x & 0x7f) << 7) | ((x >> 7) << 15)); -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } -+ wc->dmactrl &= ~0x0001ffff; -+ } else { -+ 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 (!has_e1_span(wc)) { -+ fromts += 4; -+ tots += 4; -+ } -+ spin_lock_irqsave(&wc->reglock, flags); -+ if (is_octal(wc)) { -+ int fromts_b = fromts & 0x7f; -+ int fromts_t = fromts >> 7; -+ int tots_b = tots & 0x7f; -+ int tots_t = tots >> 7; -+ -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= ((fromts_t << 16) | (tots_t << 15) | 0x00004000 | (tots_b << 7) | (fromts_b)); -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ wc->dmactrl &= ~0x0001ffff; -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } else { -+ 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 (!has_e1_span(wc)) -+ tots += 4; -+ spin_lock_irqsave(&wc->reglock, flags); -+ if (is_octal(wc)) { -+ int tots_b = tots & 0x7f; -+ int tots_t = tots >> 7; -+ -+ wc->dmactrl &= ~0x0001ffff; -+ wc->dmactrl |= ((tots_t << 15) | 0x00004000 | (tots_b << 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 &= ~0x0001ffff; -+ __t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ } else { -+ 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); -+} -+ -+#ifndef CONFIG_NOEXTENDED_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 -+ -+#define SPI_CS (0) -+#define SPI_CLK (1) -+#define SPI_IO0 (2) -+#define SPI_IO1 (3) -+#define SPI_IO3 (4) -+#define SPI_IO2 (5) -+#define SPI_IN (0) -+#define SPI_OUT (1) -+#define ESPI_REG 13 -+ -+static void t8_clear_bit(struct t4 *wc, int whichb) -+{ -+ wc->st.wrreg &= ~(1 << whichb); -+} -+ -+static void t8_set_bit(struct t4 *wc, int whichb, int val) -+{ -+ t8_clear_bit(wc, whichb); -+ wc->st.wrreg |= (val << whichb); -+} -+ -+static int t8_get_bit(struct t4 *wc, int whichb) -+{ -+ return (wc->st.rdreg >> whichb) & 1; -+} -+ -+static void set_iodir(struct t4 *wc, int whichb, int dir) -+{ -+ whichb += 16; -+ t8_clear_bit(wc, whichb); -+ t8_set_bit(wc, whichb, dir); -+} -+ -+static void write_hwreg(struct t4 *wc) -+{ -+ t4_pci_out(wc, ESPI_REG, wc->st.wrreg); -+} -+ -+static void read_hwreg(struct t4 *wc) -+{ -+ wc->st.rdreg = t4_pci_in(wc, ESPI_REG); -+} -+ -+static void set_cs(struct t4 *wc, int state) -+{ -+ t8_set_bit(wc, SPI_CS, state); -+ write_hwreg(wc); -+} -+ -+static void set_clk(struct t4 *wc, int clk) -+{ -+ t8_set_bit(wc, SPI_CLK, clk); -+ write_hwreg(wc); -+} -+ -+static void clk_bit_out(struct t4 *wc, int val) -+{ -+ t8_set_bit(wc, SPI_IO0, val & 1); -+ set_clk(wc, 0); -+ set_clk(wc, 1); -+} -+ -+static void shift_out(struct t4 *wc, int val) -+{ -+ int i; -+ for (i = 7; i >= 0; i--) -+ clk_bit_out(wc, (val >> i) & 1); -+} -+ -+static int clk_bit_in(struct t4 *wc) -+{ -+ int ret; -+ set_clk(wc, 0); -+ read_hwreg(wc); -+ ret = t8_get_bit(wc, SPI_IO1); -+ set_clk(wc, 1); -+ return ret; -+} -+ -+static int shift_in(struct t4 *wc) -+{ -+ int ret = 0; -+ int i; -+ int bit; -+ -+ for (i = 7; i >= 0; i--) { -+ bit = clk_bit_in(wc); -+ ret |= ((bit & 1) << i); -+ } -+ return ret; -+} -+ -+static void write_enable(struct t4 *wc) -+{ -+ int cmd = 0x06; -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ set_cs(wc, 1); -+} -+ -+static int read_sr1(struct t4 *wc) -+{ -+ int cmd = 0x05; -+ int ret; -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ ret = shift_in(wc); -+ set_cs(wc, 1); -+ return ret; -+} -+ -+static void clear_busy(struct t4 *wc) -+{ -+ static const int SR1_BUSY = (1 << 0); -+ unsigned long stop; -+ -+ stop = jiffies + 2*HZ; -+ while (read_sr1(wc) & SR1_BUSY) { -+ if (time_after(jiffies, stop)) { -+ if (printk_ratelimit()) { -+ dev_err(&wc->dev->dev, -+ "Lockup in %s\n", __func__); -+ } -+ break; -+ } -+ cond_resched(); -+ } -+} -+ -+static void sector_erase(struct t4 *wc, uint32_t addr) -+{ -+ int cmd = 0x20; -+ write_enable(wc); -+ set_cs(wc, 0); -+ shift_out(wc, cmd); -+ shift_out(wc, (addr >> 16) & 0xff); -+ shift_out(wc, (addr >> 8) & 0xff); -+ shift_out(wc, (addr >> 0) & 0xff); -+ set_cs(wc, 1); -+ clear_busy(wc); -+} -+ -+static void erase_half(struct t4 *wc) -+{ -+ uint32_t addr = 0x00080000; -+ uint32_t i; -+ -+ dev_info(&wc->dev->dev, "Erasing octal firmware\n"); -+ -+ for (i = addr; i < (addr + 0x80000); i += 4096) -+ sector_erase(wc, i); -+} -+ -+ -+#define T8_FLASH_PAGE_SIZE 256UL -+ -+static void t8_update_firmware_page(struct t4 *wc, u32 address, -+ const u8 *page_data, size_t size) -+{ -+ int i; -+ -+ write_enable(wc); -+ set_cs(wc, 0); -+ shift_out(wc, 0x02); -+ shift_out(wc, (address >> 16) & 0xff); -+ shift_out(wc, (address >> 8) & 0xff); -+ shift_out(wc, (address >> 0) & 0xff); -+ -+ for (i = 0; i < size; ++i) -+ shift_out(wc, page_data[i]); -+ -+ set_cs(wc, 1); -+ clear_busy(wc); -+} -+ -+static int t8_update_firmware(struct t4 *wc, const struct firmware *fw, -+ const char *t8_firmware) -+{ -+ int res; -+ size_t offset = 0; -+ const u32 BASE_ADDRESS = 0x00080000; -+ const u8 *data, *end; -+ size_t size = 0; -+ -+ /* Erase flash */ -+ erase_half(wc); -+ -+ dev_info(&wc->dev->dev, -+ "Uploading %s. This can take up to 30 seconds.\n", t8_firmware); -+ -+ data = &fw->data[sizeof(struct t8_firm_header)]; -+ end = &fw->data[fw->size]; -+ -+ while (data < end) { -+ /* Calculate the tail end of data that's shorter than a page */ -+ size = min(T8_FLASH_PAGE_SIZE, (unsigned long)(end - data)); -+ -+ t8_update_firmware_page(wc, BASE_ADDRESS + offset, -+ data, size); -+ data += T8_FLASH_PAGE_SIZE; -+ offset += T8_FLASH_PAGE_SIZE; -+ -+ cond_resched(); -+ } -+ -+ /* Reset te820 fpga after loading firmware */ -+ dev_info(&wc->dev->dev, "Firmware load complete. Reseting device.\n"); -+ res = pci_save_state(wc->dev); -+ if (res) -+ goto error_exit; -+ /* Set the fpga reset bits and clobber the remainder of the -+ * register, device will be reset anyway */ -+ t4_pci_out(wc, WC_LEDS, 0xe0000000); -+ msleep(1000); -+ -+ pci_restore_state(wc->dev); -+ -+ /* Signal the driver to restart initialization. -+ * This will back out all initialization so far and -+ * restart the driver load process */ -+ return -EAGAIN; -+ -+error_exit: -+ return res; -+} -+ -+static char read_flash_byte(struct t4 *wc, unsigned int addr) -+{ -+ int cmd = 0x03; -+ char data; -+ -+ set_cs(wc, 0); -+ -+ shift_out(wc, cmd); -+ -+ shift_out(wc, (addr >> 16) & 0xff); -+ shift_out(wc, (addr >> 8) & 0xff); -+ shift_out(wc, (addr >> 0) & 0xff); -+ -+ data = shift_in(wc) & 0xff; -+ -+ set_cs(wc, 1); -+ -+ return data; -+} -+ -+/** -+ * t8_read_serial - Returns the serial number of the board. -+ * @wc: The board whos serial number we are reading. -+ * -+ * The buffer returned is dynamically allocated and must be kfree'd by the -+ * caller. If memory could not be allocated, NULL is returned. -+ * -+ * Must be called in process context. -+ * -+ */ -+static char *t8_read_serial(struct t4 *wc) -+{ -+ int i; -+ static const int MAX_SERIAL = 14; -+ static const u32 base_addr = 0x00080000-256; -+ unsigned char c; -+ unsigned char *serial = kzalloc(MAX_SERIAL + 1, GFP_KERNEL); -+ -+ if (!serial) -+ return NULL; -+ -+ for (i = 0; i < MAX_SERIAL; ++i) { -+ c = read_flash_byte(wc, base_addr+i); -+ if ((c >= 'a' && c <= 'z') || -+ (c >= 'A' && c <= 'Z') || -+ (c >= '0' && c <= '9')) -+ serial[i] = c; -+ else -+ break; -+ -+ } -+ -+ if (!i) { -+ kfree(serial); -+ serial = NULL; -+ } -+ -+ return serial; -+} -+ -+static void setup_spi(struct t4 *wc) -+{ -+ wc->st.rdreg = wc->st.wrreg = 0; -+ -+ set_iodir(wc, SPI_IO0, SPI_OUT); -+ set_iodir(wc, SPI_IO1, SPI_IN); -+ set_iodir(wc, SPI_CS, SPI_OUT); -+ set_iodir(wc, SPI_CLK, SPI_OUT); -+ -+ t8_set_bit(wc, SPI_CS, 1); -+ t8_set_bit(wc, SPI_CLK, 1); -+ -+ write_hwreg(wc); -+} -+ -+static int t8_check_firmware(struct t4 *wc, unsigned int version) -+{ -+ const struct firmware *fw; -+ static const char t8_firmware[] = "dahdi-fw-te820.bin"; -+ const struct t8_firm_header *header; -+ int res = 0; -+ u32 crc; -+ -+ res = request_firmware(&fw, t8_firmware, &wc->dev->dev); -+ if (res) { -+ dev_info(&wc->dev->dev, "firmware %s not " -+ "available from userspace\n", t8_firmware); -+ goto cleanup; -+ } -+ -+ header = (const struct t8_firm_header *)fw->data; -+ -+ /* Check the crc before anything else */ -+ crc = crc32(~0, &fw->data[10], fw->size - 10) ^ ~0; -+ if (memcmp("DIGIUM", header->header, sizeof(header->header)) || -+ (le32_to_cpu(header->chksum) != crc)) { -+ dev_info(&wc->dev->dev, -+ "%s is invalid. Please reinstall.\n", t8_firmware); -+ goto cleanup; -+ } -+ -+ /* Spi struct must be setup before any access to flash memory */ -+ setup_spi(wc); -+ -+ /* Check the two firmware versions */ -+ if (le32_to_cpu(header->version) == version) -+ goto cleanup; -+ -+ dev_info(&wc->dev->dev, "%s Version: %08x available for flash\n", -+ t8_firmware, header->version); -+ -+ res = t8_update_firmware(wc, fw, t8_firmware); -+ if (res && res != -EAGAIN) { -+ dev_info(&wc->dev->dev, "Failed to load firmware %s\n", -+ t8_firmware); -+ } -+ -+cleanup: -+ release_firmware(fw); -+ return res; -+} -+ -+static int -+__t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, bool first_time) -+{ -+ unsigned int version; -+ int res; -+ -+ version = t4_pci_in(wc, WC_VERSION); -+ if (is_octal(wc) && first_time) { -+ dev_info(&wc->dev->dev, "Firmware Version: %01x.%02x\n", -+ (version & 0xf00) >> 8, -+ version & 0xff); -+ } else if (first_time) { -+ dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version); -+ } -+ if (debug) { -+ 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 -+ } -+ -+ /* Check the field updatable firmware for the wcte820 */ -+ if (is_octal(wc)) { -+ res = t8_check_firmware(wc, version); -+ if (res) -+ return res; -+ -+ wc->ddev->hardware_id = t8_read_serial(wc); -+ } -+ -+#if defined(CONFIG_FORCE_EXTENDED_RESET) -+ t4_extended_reset(wc); -+#elif !defined(CONFIG_NOEXTENDED_RESET) -+ if (wc->devtype->flags & FLAG_EXPRESS) -+ 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 (first_time) { -+ if (!strcasecmp("auto", default_linemode)) { -+ if (-1 == t1e1override) { -+ wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & -+ 0x0f00) >> 8); -+ wc->t1e1 &= 0xf; -+ if (is_octal(wc)) { -+ wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) & -+ 0x0f00) >> 4; -+ } -+ } else { -+ dev_warn(&wc->dev->dev, -+ "'t1e1override' is deprecated. Please use 'default_linemode'.\n"); -+ wc->t1e1 = t1e1override & 0xf; -+ } -+ } else if (!strcasecmp("t1", default_linemode)) { -+ wc->t1e1 = 0; -+ } else if (!strcasecmp("e1", default_linemode)) { -+ wc->t1e1 = 0xff; -+ } else if (!strcasecmp("j1", default_linemode)) { -+ wc->t1e1 = 0; -+ j1mode = 1; -+ } else { -+ dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n", -+ default_linemode); -+ wc->t1e1 = 0; -+ } -+ } -+ -+ wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28; -+ order_index[wc->order]++; -+ -+ /* TE820 Auth Check */ -+ if (is_octal(wc)) { -+ unsigned long stop = jiffies + HZ; -+ uint32_t donebit; -+ -+ t4_pci_out(wc, WC_LEDS2, WC_SET_AUTH); -+ donebit = t4_pci_in(wc, WC_LEDS2); -+ while (!(donebit & WC_GET_AUTH)) { -+ if (time_after(jiffies, stop)) { -+ /* Encryption check failed, stop operation */ -+ dev_info(&wc->dev->dev, -+ "Failed encryption check. " -+ "Unloading driver.\n"); -+ return -EIO; -+ } -+ msleep(20); -+ donebit = t4_pci_in(wc, WC_LEDS2); -+ } -+ } -+ -+ return 0; -+} -+ -+static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags) -+{ -+ return __t4_hardware_init_1(wc, cardflags, true); -+} -+ -+static int __t4_hardware_init_2(struct t4 *wc, bool first_time) -+{ -+ int x; -+ unsigned int regval; -+ unsigned long flags; -+ -+ if (t4_pci_in(wc, WC_VERSION) >= 0xc01a0165) { -+ wc->tspans[0]->spanflags |= FLAG_OCTOPT; -+ } -+ /* Setup LEDS, take out of reset */ -+ t4_pci_out(wc, WC_LEDS, 0x000000ff); -+ udelay(100); -+ t4_activate(wc); -+ udelay(100); -+ -+ /* In order to find out the QFALC framer version, we have to -+ * temporarily turn off compat mode and take a peak at VSTR. We turn -+ * compat back on when we are done. -+ * -+ */ -+ spin_lock_irqsave(&wc->reglock, flags); -+ regval = __t4_framer_in(wc, 0, 0xd6); -+ if (is_octal(wc)) -+ regval |= (1 << 4); /* SSI16 - For 16 MHz multiplex mode with comp = 1 */ -+ else -+ regval |= (1 << 5); /* set COMP_DIS*/ -+ -+ __t4_framer_out(wc, 0, 0xd6, regval); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (!is_octal(wc)) { -+ regval = t4_framer_in(wc, 0, 0x4a); -+ if (first_time && regval == 0x05) { -+ dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or " -+ "earlier\n"); -+ } else if (regval == 0x20) { -+ if (first_time) -+ dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n"); -+ wc->falc31 = 1; -+ } else if (first_time) { -+ dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " -+ "(VSTR = 0x%02x)\n", regval); -+ } -+ } -+ -+ spin_lock_irqsave(&wc->reglock, flags); -+ 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); -+ spin_unlock_irqrestore(&wc->reglock, flags); -+ -+ if (debug) { -+ 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)); -+ } -+ } -+ -+ 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)); -+ -+ return 0; -+} -+ -+static int t4_hardware_init_2(struct t4 *wc) -+{ -+ return __t4_hardware_init_2(wc, true); -+} -+ -+static int __devinit t4_launch(struct t4 *wc) -+{ -+ int x; -+ int res; -+ -+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) -+ return 0; -+ -+ if (debug) { -+ dev_info(&wc->dev->dev, -+ "opvxd115: Launching card: %d\n", -+ wc->order); -+ } -+ -+ wc->ddev->manufacturer = "OpenVox"; -+ if (!ignore_rotary && (1 == order_index[wc->order])) { -+ wc->ddev->location = kasprintf(GFP_KERNEL, -+ "Board ID Switch %d", wc->order); -+ } else { -+ bool express = ((wc->tspans[0]->spanflags & FLAG_EXPRESS) > 0); -+ wc->ddev->location = kasprintf(GFP_KERNEL, -+ "PCI%s Bus %02d Slot %02d", -+ (express) ? " Express" : "", -+ wc->dev->bus->number, -+ PCI_SLOT(wc->dev->devfn) + 1); -+ } -+ -+ if (!wc->ddev->location) -+ return -ENOMEM; -+ -+ for (x = 0; x < wc->numspans; ++x) { -+ list_add_tail(&wc->tspans[x]->span.device_node, -+ &wc->ddev->spans); -+ } -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -+ INIT_WORK(&wc->bh_work, t4_work_func, wc); -+#else -+ INIT_WORK(&wc->bh_work, t4_work_func); -+#endif -+ -+ res = dahdi_register_device(wc->ddev, &wc->dev->dev); -+ if (res) { -+ dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n"); -+ return res; -+ } -+ -+ return 0; -+} -+ -+/** -+ * wct4xxp_sort_cards - Sort the cards in card array by rotary switch settings. -+ * -+ */ -+static void wct4xxp_sort_cards(void) -+{ -+ int x; -+ -+ /* 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; -+ } -+ } -+} -+ -+static int __devinit -+t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ struct t4 *wc; -+ unsigned int x; -+ int init_latency; -+ -+ if (pci_enable_device(pdev)) { -+ return -EIO; -+ } -+ -+ wc = kzalloc(sizeof(*wc), GFP_KERNEL); -+ if (!wc) -+ return -ENOMEM; -+ -+ wc->ddev = dahdi_create_device(); -+ if (!wc->ddev) { -+ kfree(wc); -+ return -ENOMEM; -+ } -+ -+ spin_lock_init(&wc->reglock); -+ wc->devtype = (const struct devtype *)(ent->driver_data); -+ -+#ifdef CONFIG_WCT4XXP_DISABLE_ASPM -+ if (is_pcie(wc)) { -+ pci_disable_link_state(pdev->bus->self, PCIE_LINK_STATE_L0S | -+ PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); -+ }; -+#endif -+ -+ if (is_octal(wc)) -+ wc->numspans = 8; -+ else if (wc->devtype->flags & FLAG_1PORT) -+ wc->numspans = 1; -+ else if (wc->devtype->flags & FLAG_2PORT) -+ wc->numspans = 2; -+ else -+ wc->numspans = 4; -+ -+ wc->membase = pci_iomap(pdev, 0, 0); -+ /* This rids of the Double missed interrupt message after loading */ -+ wc->last0 = 1; -+ if (pci_request_regions(pdev, wc->devtype->desc)) -+ dev_info(&pdev->dev, "D115: Unable to request regions\n"); -+ -+ if (debug) -+ dev_info(&pdev->dev, "Found OPVXD115\n"); -+ -+ wc->dev = pdev; -+ -+ /* Enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Keep track of which device we are */ -+ pci_set_drvdata(pdev, wc); -+ -+ if (wc->devtype->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->devtype->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 */ -+ res = t4_hardware_init_1(wc, wc->devtype->flags); -+ if (res) { -+ /* If this function returns -EAGAIN, we expect -+ * to attempt another driver load. Clean everything -+ * up first */ -+ pci_iounmap(wc->dev, wc->membase); -+ pci_release_regions(wc->dev); -+ pci_free_consistent(wc->dev, T4_BASE_SIZE(wc) * wc->numbufs * 2, -+ wc->writechunk, wc->writedma); -+ pci_set_drvdata(wc->dev, NULL); -+ free_wc(wc); -+ return res; -+ } -+ -+ 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->devtype->flags & FLAG_2NDGEN) { -+ char tmp[20]; -+ -+ sprintf(tmp, "te%dxxp[%d]", wc->numspans, wc->num); -+ wc->workq = create_workqueue(tmp); -+ } -+#endif -+ -+ /* Allocate pieces we need here */ -+ for (x = 0; x < ports_on_framer(wc); x++) { -+ struct t4_span *ts; -+ enum linemode linemode; -+ -+ ts = kzalloc(sizeof(*ts), GFP_KERNEL); -+ if (!ts) { -+ free_wc(wc); -+ return -ENOMEM; -+ } -+ wc->tspans[x] = ts; -+ -+#ifdef ENABLE_WORKQUEUES -+ INIT_WORK(&ts->swork, workq_handlespan, ts); -+#endif -+ ts->spanflags |= wc->devtype->flags; -+ linemode = (wc->t1e1 & (1 << x)) ? E1 : ((j1mode) ? J1 : T1); -+ t4_alloc_channels(wc, wc->tspans[x], linemode); -+ } -+ -+ /* Continue hardware intiialization */ -+ t4_hardware_init_2(wc); -+ -+#ifdef SUPPORT_GEN1 -+ if (request_irq(pdev->irq, (wc->devtype->flags & FLAG_2NDGEN) ? -+ t4_interrupt_gen2 : t4_interrupt, -+ DAHDI_IRQ_SHARED, -+ (wc->numspans == 8) ? "wct8xxp" : -+ (wc->numspans == 1) ? "opvxd115" : -+ "wct4xxp", -+ wc)) { -+#else -+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) { -+ dev_notice(&wc->dev->dev, "This driver does not " -+ "support 1st gen modules\n"); -+ free_wc(wc); -+ return -ENODEV; -+ } -+ -+ if (request_irq(pdev->irq, t4_interrupt_gen2, -+ DAHDI_IRQ_SHARED, "t4xxp", wc)) { -+#endif -+ dev_notice(&wc->dev->dev, "Unable to request IRQ %d\n", -+ pdev->irq); -+ free_wc(wc); -+ return -EIO; -+ } -+ -+ init_spans(wc); -+ -+ if (!ignore_rotary) -+ wct4xxp_sort_cards(); -+ -+ if (wc->ddev->hardware_id) { -+ dev_info(&wc->dev->dev, -+ "Found a Wildcard: %s (SN: %s)\n", wc->devtype->desc, -+ wc->ddev->hardware_id); -+ } else { -+ dev_info(&wc->dev->dev, -+ "Found a Wildcard: %s\n", wc->devtype->desc); -+ } -+ -+#ifdef VPM_SUPPORT -+ if (!wc->vpm) { -+ t4_vpm_init(wc); -+ wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0; -+ t4_pci_out(wc, WC_DMACTRL, wc->dmactrl); -+ if (wc->vpm) -+ set_span_devicetype(wc); -+ } -+#endif -+ -+ create_sysfs_files(wc); -+ -+ res = 0; -+ if (ignore_rotary) -+ res = t4_launch(wc); -+ -+ return res; -+} -+ -+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); -+ -+ if (debug) { -+ dev_notice(&wc->dev->dev, "Stopped D115, Turned off DMA\n"); -+ } -+ return 0; -+} -+ -+static int __devinit -+t4_init_one_retry(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ res = t4_init_one(pdev, ent); -+ -+ /* If the driver was reset by a firmware load, -+ * try to load once again */ -+ if (-EAGAIN == res) { -+ res = t4_init_one(pdev, ent); -+ if (-EAGAIN == res) { -+ dev_err(&pdev->dev, "Failed to update firmware.\n"); -+ res = -EIO; -+ } -+ } -+ -+ return res; -+} -+ -+static void _t4_remove_one(struct t4 *wc) -+{ -+ int basesize; -+ -+ if (!wc) -+ return; -+ -+ dahdi_unregister_device(wc->ddev); -+ -+ remove_sysfs_files(wc); -+ -+ /* Stop hardware */ -+ t4_hardware_stop(wc); -+ -+#ifdef VPM_SUPPORT -+ /* Release vpm */ -+ if (wc->vpm) -+ release_vpm450m(wc->vpm); -+ wc->vpm = NULL; -+#endif -+ /* Unregister spans */ -+ -+ basesize = DAHDI_MAX_CHUNKSIZE * 32 * 4; -+ if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) -+ basesize = basesize * 2; -+ -+#ifdef ENABLE_WORKQUEUES -+ if (wc->workq) { -+ flush_workqueue(wc->workq); -+ destroy_workqueue(wc->workq); -+ } -+#endif -+ -+ free_irq(wc->dev->irq, wc); -+ -+ if (wc->membase) -+ pci_iounmap(wc->dev, wc->membase); -+ -+ pci_release_regions(wc->dev); -+ -+ /* Immediately free resources */ -+ pci_free_consistent(wc->dev, T4_BASE_SIZE(wc) * wc->numbufs * 2, -+ wc->writechunk, wc->writedma); -+ -+ order_index[wc->order]--; -+ -+ cards[wc->num] = NULL; -+ pci_set_drvdata(wc->dev, NULL); -+ free_wc(wc); -+} -+ -+static void __devexit t4_remove_one(struct pci_dev *pdev) -+{ -+ struct t4 *wc = pci_get_drvdata(pdev); -+ if (!wc) -+ return; -+ -+ _t4_remove_one(wc); -+} -+ -+ -+static DEFINE_PCI_DEVICE_TABLE(t4_pci_tbl) = -+{ -+ { 0x1b74, 0x0115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&opvxd115p2 }, /* OpenVox D115P/D115E */ -+ { 0x1b74, 0xd130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&opvxd130p5 }, /* OpenVox D130P/D130E */ -+ { 0, } -+}; -+ -+static void _t4_shutdown(struct pci_dev *pdev) -+{ -+ struct t4 *wc = pci_get_drvdata(pdev); -+ t4_hardware_stop(wc); -+} -+ -+static int t4_suspend(struct pci_dev *pdev, pm_message_t state) -+{ -+ return -ENOSYS; -+} -+ -+static struct pci_driver t4_driver = { -+ .name = "opvxd115", -+ .probe = t4_init_one_retry, -+ .remove = __devexit_p(t4_remove_one), -+ .shutdown = _t4_shutdown, -+ .suspend = t4_suspend, -+ .id_table = t4_pci_tbl, -+}; -+ -+static int __init t4_init(void) -+{ -+ int i; -+ int res; -+ -+ if (-1 != t1e1override) { -+ pr_info("'t1e1override' module parameter is deprecated. " -+ "Please use 'default_linemode' instead.\n"); -+ } -+ -+ res = dahdi_pci_module(&t4_driver); -+ if (res) -+ return -ENODEV; -+ -+ /* If we're ignoring the rotary switch settings, then we've already -+ * registered in the context of .probe */ -+ if (!ignore_rotary) { -+ -+ /* 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 (i = 0; cards[i]; i++) { -+ /* warn the user of duplicate ident values it is -+ * probably unintended */ -+ if (debug && res < 15 && cards[i+1] && -+ cards[res]->order == cards[i+1]->order) { -+ printk(KERN_NOTICE "opvxd115: Duplicate ident " -+ "value found (%d)\n", cards[i]->order); -+ } -+ res = t4_launch(cards[i]); -+ if (res) { -+ int j; -+ for (j = 0; j < i; ++j) -+ _t4_remove_one(cards[j]); -+ break; -+ } -+ } -+ } -+ return res; -+} -+ -+static void __exit t4_cleanup(void) -+{ -+ pci_unregister_driver(&t4_driver); -+} -+ -+MODULE_AUTHOR("OpenVox Incorporated <support@openvox.cn>"); -+MODULE_DESCRIPTION("OpenVox Single port Digital Card Driver"); -+MODULE_ALIAS("opvxd115"); -+MODULE_LICENSE("GPL v2"); -+ -+module_param(debug, int, 0600); -+module_param(noburst, int, 0600); -+module_param(timingcable, int, 0600); -+module_param(t1e1override, int, 0400); -+module_param(default_linemode, charp, S_IRUGO); -+MODULE_PARM_DESC(default_linemode, "\"auto\"(default), \"e1\", \"t1\", " -+ "or \"j1\". \"auto\" will use the value from any hardware " -+ "jumpers."); -+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); -+module_param(ignore_rotary, int, 0400); -+MODULE_PARM_DESC(ignore_rotary, "Set to > 0 to ignore the rotary switch when " \ -+ "registering with DAHDI."); -+ -+#ifdef VPM_SUPPORT -+module_param(vpmsupport, int, 0600); -+module_param(vpmdtmfsupport, int, 0600); -+#endif -+ -+MODULE_DEVICE_TABLE(pci, t4_pci_tbl); -+ -+module_init(t4_init); -+module_exit(t4_cleanup); ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/opvxd115-diag.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/opvxd115-diag.c 2015-02-10 14:19:03.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 "wct4xxp.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: wct4xxp-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); -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/opvxd115.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/opvxd115.h 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,144 @@ -+/* -+ * Wildcard T400P FXS Interface Driver for DAHDI Telephony interface -+ * -+ * Written by Mark Spencer <markster@linux-support.net> -+ * -+ * 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/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 -+/* OctalFALC Only */ -+#define FRMR_CMR4 0x41 -+#define FRMR_CMR5 0x42 -+#define FRMR_CMR6 0x43 -+#define FRMR_GPC2 0x8a -+/* End Octal */ -+#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 -+ -+/* CIS - Octal falc bits */ -+#define FRMR_CIS_GIS5 0x10 -+#define FRMR_CIS_GIS6 0x20 -+#define FRMR_CIS_GIS7 0x40 -+#define FRMR_CIS_GIS8 0x80 -+ -+#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]; -+}; -+ -+struct t4_reg { -+ unsigned int reg; -+ unsigned int val; -+}; -+ -+#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) -+#define WCT4_GET_REG _IOW(DAHDI_CODE, 61, struct t4_reg) -+#define WCT4_SET_REG _IOW(DAHDI_CODE, 62, struct t4_reg) -+ ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/vpm450m.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/vpm450m.c 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,623 @@ -+/* -+ * Copyright (C) 2005-2012 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. -+ */ -+ -+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/string.h> -+#include <linux/time.h> -+#include <linux/version.h> -+ -+#include <dahdi/kernel.h> -+#include <stdbool.h> -+ -+#include "vpm450m.h" -+#include <oct612x.h> -+ -+static int wct4xxp_oct612x_write(struct oct612x_context *context, -+ u32 address, u16 value) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ oct_set_reg(wc, address, value); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_read(struct oct612x_context *context, u32 address, -+ u16 *value) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ *value = (u16)oct_get_reg(wc, address); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_write_smear(struct oct612x_context *context, -+ u32 address, u16 value, size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ oct_set_reg(wc, address + (i << 1), value); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_write_burst(struct oct612x_context *context, -+ u32 address, const u16 *buffer, -+ size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ oct_set_reg(wc, address + (i << 1), buffer[i]); -+ return 0; -+} -+ -+static int wct4xxp_oct612x_read_burst(struct oct612x_context *context, -+ u32 address, u16 *buffer, size_t count) -+{ -+ struct t4 *wc = dev_get_drvdata(context->dev); -+ int i; -+ for (i = 0; i < count; ++i) -+ buffer[i] = oct_get_reg(wc, address + (i << 1)); -+ return 0; -+} -+ -+static const struct oct612x_ops wct4xxp_oct612x_ops = { -+ .write = wct4xxp_oct612x_write, -+ .read = wct4xxp_oct612x_read, -+ .write_smear = wct4xxp_oct612x_write_smear, -+ .write_burst = wct4xxp_oct612x_write_burst, -+ .read_burst = wct4xxp_oct612x_read_burst, -+}; -+ -+#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; -+ struct oct612x_context context; -+ UINT32 aulEchoChanHndl[256]; -+ int chanflags[256]; -+ int ecmode[256]; -+ int numchans; -+}; -+ -+#define FLAG_DTMF (1 << 0) -+#define FLAG_MUTE (1 << 1) -+#define FLAG_ECHO (1 << 2) -+#define FLAG_ALAW (1 << 3) -+ -+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, -+}; -+ -+void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, int channel, -+ bool alaw) -+{ -+ tOCT6100_CHANNEL_MODIFY *modify; -+ UINT32 ulResult; -+ UINT32 law_to_use = (alaw) ? cOCT6100_PCM_A_LAW : -+ cOCT6100_PCM_U_LAW; -+ -+ if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ /* If we're already in this companding mode, no need to do anything. */ -+ if (alaw == ((vpm450m->chanflags[channel] & FLAG_ALAW) > 0)) -+ return; -+ -+ modify = kzalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); -+ if (!modify) { -+ pr_notice("Unable to allocate memory for setec!\n"); -+ return; -+ } -+ -+ Oct6100ChannelModifyDef(modify); -+ modify->ulChannelHndl = vpm450m->aulEchoChanHndl[channel]; -+ modify->fTdmConfigModified = TRUE; -+ modify->TdmConfig.ulSinPcmLaw = law_to_use; -+ modify->TdmConfig.ulRinPcmLaw = law_to_use; -+ modify->TdmConfig.ulSoutPcmLaw = law_to_use; -+ modify->TdmConfig.ulRoutPcmLaw = law_to_use; -+ ulResult = Oct6100ChannelModify(vpm450m->pApiInstance, modify); -+ if (ulResult != GENERIC_OK) { -+ pr_notice("Failed to apply echo can changes on channel %d %d %08x!\n", -+ vpm450m->aulEchoChanHndl[channel], channel, ulResult); -+ } else { -+ if (debug) { -+ pr_info("Changed companding on channel %d to %s.\n", -+ channel, (alaw) ? "alaw" : "ulaw"); -+ } -+ if (alaw) -+ vpm450m->chanflags[channel] |= FLAG_ALAW; -+ else -+ vpm450m->chanflags[channel] &= ~(FLAG_ALAW); -+ } -+ kfree(modify); -+} -+ -+static void vpm450m_setecmode(struct vpm450m *vpm450m, int channel, int mode) -+{ -+ tOCT6100_CHANNEL_MODIFY *modify; -+ UINT32 ulResult; -+ -+ if (vpm450m->ecmode[channel] == mode) -+ return; -+ modify = kzalloc(sizeof(*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 %08x!\n", channel, ulResult); -+ } 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; -+ -+ if (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ -+ modify = kzalloc(sizeof(*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 (channel >= ARRAY_SIZE(vpm450m->chanflags)) { -+ pr_err("Channel out of bounds in %s\n", __func__); -+ return; -+ } -+ -+ 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; -+ -+ Oct6100EventGetToneDef(&tonesearch); -+ tonesearch.pToneEvent = &tonefound; -+ tonesearch.ulMaxToneEvent = 1; -+ 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(struct device *device) -+{ -+ struct oct612x_context context; -+ UINT32 ulResult; -+ -+ tOCT6100_API_GET_CAPACITY_PINS CapacityPins; -+ -+ context.dev = device; -+ context.ops = &wct4xxp_oct612x_ops; -+ -+ Oct6100ApiGetCapacityPinsDef(&CapacityPins); -+ CapacityPins.pProcessContext = &context; -+ 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(struct device *device, int *isalaw, -+ int numspans, const struct firmware *firmware) -+{ -+ tOCT6100_CHIP_OPEN *ChipOpen; -+ tOCT6100_GET_INSTANCE_SIZE InstanceSize; -+ tOCT6100_CHANNEL_OPEN *ChannelOpen; -+ UINT32 ulResult; -+ const unsigned int mask = (8 == numspans) ? 0x7 : 0x3; -+ unsigned int sout_stream, rout_stream; -+ struct vpm450m *vpm450m; -+ int x,y,law; -+ -+ vpm450m = kzalloc(sizeof(*vpm450m), GFP_KERNEL); -+ if (!vpm450m) -+ return NULL; -+ -+ vpm450m->context.dev = device; -+ vpm450m->context.ops = &wct4xxp_oct612x_ops; -+ -+ ChipOpen = kzalloc(sizeof(*ChipOpen), GFP_KERNEL); -+ if (!ChipOpen) { -+ kfree(vpm450m); -+ kfree(vpm450m); -+ return NULL; -+ } -+ -+ ChannelOpen = kzalloc(sizeof(*ChannelOpen), GFP_KERNEL); -+ if (!ChannelOpen) { -+ kfree(vpm450m); -+ kfree(ChipOpen); -+ return NULL; -+ } -+ -+ for (x = 0; x < ARRAY_SIZE(vpm450m->ecmode); 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 = &vpm450m->context; -+ -+ 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->aulTdmStreamFreqs[0] = cOCT6100_TDM_STREAM_FREQ_8MHZ; -+ ChipOpen->ulMaxFlexibleConfParticipants = 0; -+ ChipOpen->ulMaxConfBridges = 0; -+ ChipOpen->ulMaxRemoteDebugSessions = 0; -+ ChipOpen->fEnableChannelRecording = FALSE; -+ ChipOpen->ulSoftToneEventsBufSize = 64; -+ -+ if (vpm450m->numchans <= 128) { -+ ChipOpen->ulMaxTdmStreams = 4; -+ ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_FALLING_EDGE; -+ } else { -+ ChipOpen->ulMaxTdmStreams = 32; -+ ChipOpen->fEnableFastH100Mode = TRUE; -+ ChipOpen->ulTdmSampling = cOCT6100_TDM_SAMPLE_AT_RISING_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; -+ } -+ -+ ulResult = Oct6100ChipOpen(vpm450m->pApiInstance, ChipOpen); -+ if (ulResult != cOCT6100_ERR_OK) { -+ printk(KERN_NOTICE "Failed to open chip, code %08x!\n", ulResult); -+ vfree(vpm450m->pApiInstance); -+ kfree(vpm450m); -+ kfree(ChipOpen); -+ kfree(ChannelOpen); -+ return NULL; -+ } -+ -+ sout_stream = (8 == numspans) ? 29 : 2; -+ rout_stream = (8 == numspans) ? 24 : 3; -+ -+ for (x = 0; x < ((8 == numspans) ? 256 : 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 & 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; -+ vpm450m->chanflags[x] |= FLAG_ALAW; -+ } else { -+ law = cOCT6100_PCM_U_LAW; -+ vpm450m->chanflags[x] &= ~(FLAG_ALAW); -+ } -+ 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 = sout_stream; -+ ChannelOpen->TdmConfig.ulSoutTimeslot = x; -+#if 1 -+ ChannelOpen->TdmConfig.ulRoutPcmLaw = law; -+ ChannelOpen->TdmConfig.ulRoutStream = rout_stream; -+ ChannelOpen->TdmConfig.ulRoutTimeslot = x; -+#endif -+ 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 %x!\n", x, ulResult); -+ continue; -+ } -+ for (y = 0; y < ARRAY_SIZE(tones); 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); -+ } -+ } -+ } -+ -+ 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); -+} ---- dahdi-linux-2.10.0.1/drivers/dahdi/opvxd115/vpm450m.h 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/opvxd115/vpm450m.h 2015-02-10 14:19:03.000000000 +0100 -@@ -0,0 +1,49 @@ -+/* -+ * 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 t4; -+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(struct device *device, int *isalaw, -+ int numspans, const struct firmware *firmware); -+unsigned int get_vpm450m_capacity(struct device *device); -+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); -+void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, -+ int channel, bool alaw); -+ -+extern int debug; -+ -+#endif ---- dahdi-linux-2.10.0.1/drivers/dahdi/wct4xxp/base.c 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/wct4xxp/base.c 2015-02-10 14:19:03.000000000 +0100 -@@ -40,7 +40,6 @@ - #include <linux/delay.h> - #include <linux/moduleparam.h> - #include <linux/crc32.h> --#include <linux/slab.h> - - #include <stdbool.h> - #include <dahdi/kernel.h> -@@ -213,6 +212,7 @@ - - static int ms_per_irq = 1; - static int ignore_rotary; -+static int compatible = 0; - - #ifdef FANCY_ALARM - static int altab[] = { -@@ -371,14 +371,9 @@ - dma_addr_t writedma; - void __iomem *membase; /* Base address of card */ - --#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 -+ /* Flags for our bottom half */ - unsigned long checkflag; -- struct work_struct bh_work; -+ struct tasklet_struct t4_tlet; - /* Latency related additions */ - unsigned char rxident; - unsigned char lastindex; -@@ -554,6 +549,8 @@ - - #define MAX_T4_CARDS 64 - -+static void t4_isr_bh(unsigned long data); -+ - static struct t4 *cards[MAX_T4_CARDS]; - - struct t8_firm_header { -@@ -687,6 +684,8 @@ - - val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; - writel(val, wc_laddr); -+ if(!compatible) -+ { - readl(wc_version); - writel(val | WC_LFRMR_CS | WC_LREAD, wc_laddr); - readl(wc_version); -@@ -694,6 +693,15 @@ - writel(val, wc_laddr); - readl(wc_version); - return ret; -+ } -+ else -+ { -+ writel(val | WC_LFRMR_CS | WC_LREAD, wc_laddr); -+ writel(0,wc_version); -+ ret = readb(wc_ldata); -+ writel(val, wc_laddr); -+ return ret; -+ } - } - - static unsigned int -@@ -718,6 +726,8 @@ - - val = ((unit & 0x3) << 8) | (addr & 0xff) | haddr; - writel(val, wc_laddr); -+ if(!compatible) -+ { - readl(wc_version); - writel(value, wc_ldata); - readl(wc_version); -@@ -725,6 +735,14 @@ - readl(wc_version); - writel(val, wc_laddr); - readl(wc_version); -+ } -+ else -+ { -+ writel(value, wc_ldata); -+ writel(val | WC_LFRMR_CS | WC_LWRITE, wc_laddr); -+ writel(0,wc_version); -+ writel(val, wc_laddr); -+ } - } - - static void t4_framer_out(struct t4 *wc, int unit, -@@ -1125,11 +1143,16 @@ - 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; - const bool alaw = (chan->span->deflaw == 2); - - if (!vpmsupport || !wc->vpm) - return -ENODEV; - -+ ops = &vpm_ec_ops; -+ features = &vpm_ec_features; -+ - if (ecp->param_count > 0) { - dev_warn(&wc->dev->dev, "%s echo canceller does not support " - "parameters; failing request\n", -@@ -1138,8 +1161,8 @@ - } - - *ec = tspan->ec[chan->chanpos - 1]; -- (*ec)->ops = &vpm_ec_ops; -- (*ec)->features = vpm_ec_features; -+ (*ec)->ops = ops; -+ (*ec)->features = *features; - - channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4; - -@@ -1832,6 +1855,16 @@ - return 0; - } - -+static int t4_open(struct dahdi_chan *chan) -+{ -+ return 0; -+} -+ -+static int t4_close(struct dahdi_chan *chan) -+{ -+ return 0; -+} -+ - static int set_span_devicetype(struct t4 *wc) - { - #ifdef VPM_SUPPORT -@@ -2109,8 +2142,6 @@ - { - unsigned int x, y; - -- flush_scheduled_work(); -- - for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) { - if (!wc->tspans[x]) - continue; -@@ -2324,6 +2355,8 @@ - .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, - .assigned = t4_span_assigned, -@@ -2338,6 +2371,8 @@ - .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, -@@ -2710,7 +2745,7 @@ - if (lineconfig & DAHDI_CONFIG_AMI) { - line = "AMI"; - /* workaround for errata #2 in ES v3 09-10-16 */ -- fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0; -+ fmr0 = (wc->falc31) ? 0xb0 : 0xa0; - } else { - line = "B8ZS"; - fmr0 = 0xf0; -@@ -2809,7 +2844,7 @@ - if (lineconfig & DAHDI_CONFIG_AMI) { - line = "AMI"; - /* workaround for errata #2 in ES v3 09-10-16 */ -- fmr0 = (is_octal(wc) || wc->falc31) ? 0xb0 : 0xa0; -+ fmr0 = (wc->falc31) ? 0xb0 : 0xa0; - } else { - line = "HDB3"; - fmr0 = 0xf0; -@@ -3296,6 +3331,8 @@ - dev_notice(&wc->dev->dev, "Checking sigbits on span %d\n", - span + 1); - -+ if (!(ts->span.flags & DAHDI_FLAG_RUNNING)) -+ return; - if (E1 == ts->linemode) { - for (i = 0; i < 15; i++) { - a = t4_framer_in(wc, span, 0x71 + i); -@@ -3685,7 +3722,6 @@ - struct t4_span *ts = wc->tspans[span]; - struct dahdi_chan *sigchan; - unsigned long flags; -- bool recheck_sigbits = false; - - - /* 1st gen cards isn't used interrupts */ -@@ -3711,8 +3747,6 @@ - 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); -- if (DAHDI_RXSIG_INITIAL == ts->span.chans[0]->rxhooksig) -- recheck_sigbits = true; - } - spin_unlock_irqrestore(&wc->reglock, flags); - -@@ -3721,7 +3755,7 @@ - ts->span.count.errsec += 1; - } - -- if (isr0 & 0x08 || recheck_sigbits) -+ if (isr0) - t4_check_sigbits(wc, span); - - if (E1 == ts->linemode) { -@@ -4048,15 +4082,9 @@ - - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) --static void t4_work_func(void *data) -+static void t4_isr_bh(unsigned long data) - { -- struct t4 *wc = data; --#else --static void t4_work_func(struct work_struct *work) --{ -- struct t4 *wc = container_of(work, struct t4, bh_work); --#endif -+ struct t4 *wc = (struct t4 *)data; - - if (test_bit(T4_CHANGE_LATENCY, &wc->checkflag)) { - if (wc->needed_latency != wc->numbufs) { -@@ -4263,7 +4291,7 @@ - - out: - if (unlikely(test_bit(T4_CHANGE_LATENCY, &wc->checkflag) || test_bit(T4_CHECK_VPM, &wc->checkflag))) -- schedule_work(&wc->bh_work); -+ tasklet_schedule(&wc->t4_tlet); - - #ifndef ENABLE_WORKQUEUES - __t4_pci_out(wc, WC_INTR, 0); -@@ -5038,7 +5066,7 @@ - - static int __t4_hardware_init_2(struct t4 *wc, bool first_time) - { -- int x; -+ int x, temp_var; - unsigned int regval; - unsigned long flags; - -@@ -5067,18 +5095,30 @@ - spin_unlock_irqrestore(&wc->reglock, flags); - - if (!is_octal(wc)) { -+ for(temp_var = 0; temp_var < 5; temp_var++) -+ { - regval = t4_framer_in(wc, 0, 0x4a); - if (first_time && regval == 0x05) { - dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or " - "earlier\n"); -+ break; - } else if (regval == 0x20) { - if (first_time) - dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n"); - wc->falc31 = 1; -+ break; - } else if (first_time) { -+ if (temp_var == 4){ - dev_info(&wc->dev->dev, "FALC Framer Version: Unknown " - "(VSTR = 0x%02x)\n", regval); -+ break; -+ } else if (temp_var == 3){ -+ compatible = 0; -+ } else { -+ compatible = 1; -+ } - } -+ } - } - - spin_lock_irqsave(&wc->reglock, flags); -@@ -5144,11 +5184,7 @@ - &wc->ddev->spans); - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -- INIT_WORK(&wc->bh_work, t4_work_func, wc); --#else -- INIT_WORK(&wc->bh_work, t4_work_func); --#endif -+ tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc); - - res = dahdi_register_device(wc->ddev, &wc->dev->dev); - if (res) { -@@ -5499,6 +5535,11 @@ - - static DEFINE_PCI_DEVICE_TABLE(t4_pci_tbl) = - { -+ { 0x1b74, 0xd210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p5 }, /* OpenVox D210E/D115E */ -+ { 0x1b74, 0x1420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp }, /* OpenVox D420x */ -+ { 0x1b74, 0xd230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct210p5 }, /* OpenVox D230P/D230E */ -+ { 0x1b74, 0xd410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp }, /* OpenVox D410x */ -+ { 0x1b74, 0xd430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp }, /* OpenVox D430x */ - { 0x10ee, 0x0314, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct4xxp }, - - { 0xd161, 0x1820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wct820p5 }, -@@ -5622,6 +5663,7 @@ - module_param(ignore_rotary, int, 0400); - MODULE_PARM_DESC(ignore_rotary, "Set to > 0 to ignore the rotary switch when " \ - "registering with DAHDI."); -+module_param(compatible, int, 0600); - - #ifdef VPM_SUPPORT - module_param(vpmsupport, int, 0600); ---- dahdi-linux-2.10.0.1/drivers/dahdi/wct4xxp/vpm450m.c 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/wct4xxp/vpm450m.c 2015-02-10 14:19:03.000000000 +0100 -@@ -239,7 +239,7 @@ - - if (vpm450m->ecmode[channel] == mode) - return; -- modify = kzalloc(sizeof(*modify), GFP_ATOMIC); -+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_ATOMIC); - if (!modify) { - printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setec!\n"); - return; -@@ -269,7 +269,7 @@ - return; - } - -- modify = kzalloc(sizeof(*modify), GFP_KERNEL); -+ modify = kmalloc(sizeof(tOCT6100_CHANNEL_MODIFY), GFP_KERNEL); - if (!modify) { - printk(KERN_NOTICE "wct4xxp: Unable to allocate memory for setdtmf!\n"); - return; -@@ -454,27 +454,28 @@ - struct vpm450m *vpm450m; - int x,y,law; - -- vpm450m = kzalloc(sizeof(*vpm450m), GFP_KERNEL); -- if (!vpm450m) -+ if (!(vpm450m = kmalloc(sizeof(struct vpm450m), GFP_KERNEL))) - return NULL; - -+ memset(vpm450m, 0, sizeof(struct vpm450m)); - vpm450m->context.dev = device; - vpm450m->context.ops = &wct4xxp_oct612x_ops; - -- ChipOpen = kzalloc(sizeof(*ChipOpen), GFP_KERNEL); -- if (!ChipOpen) { -- kfree(vpm450m); -+ if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) { - kfree(vpm450m); - return NULL; - } - -- ChannelOpen = kzalloc(sizeof(*ChannelOpen), GFP_KERNEL); -- if (!ChannelOpen) { -+ 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 < ARRAY_SIZE(vpm450m->ecmode); x++) - vpm450m->ecmode[x] = -1; - ---- dahdi-linux-2.10.0.1/drivers/dahdi/wct4xxp/wct4xxp.h 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-openvox/drivers/dahdi/wct4xxp/wct4xxp.h 2015-02-10 14:19:03.000000000 +0100 -@@ -131,6 +131,13 @@ - unsigned int val; - }; - -+#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) - #define WCT4_GET_REG _IOW(DAHDI_CODE, 61, struct t4_reg) - #define WCT4_SET_REG _IOW(DAHDI_CODE, 62, struct t4_reg) diff --git a/dahdi-linux-2.10.1-yeastar.patch b/dahdi-linux-2.10.1-yeastar.patch deleted file mode 100644 index 207b2bceda07..000000000000 --- a/dahdi-linux-2.10.1-yeastar.patch +++ /dev/null @@ -1,6269 +0,0 @@ -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/Kbuild dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/Kbuild ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kbuild 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/Kbuild 2015-02-10 15:33:19.353714552 +0100 -@@ -14,6 +14,9 @@ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/ - obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE13XP) += wcte13xp.o - -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_YSTDM8XX) += ystdm8xx.o -+obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_YSTDM16XX) += ystdm16xx.o -+ - wcte13xp-objs := wcte13xp-base.o wcxb_spi.o wcxb.o wcxb_flash.o - CFLAGS_wcte13xp-base.o += -I$(src)/oct612x -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api - ifeq ($(HOTPLUG_FIRMWARE),yes) -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/Kconfig dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/Kconfig ---- dahdi-linux-2.10.0.1/drivers/dahdi/Kconfig 2014-09-22 20:40:19.000000000 +0200 -+++ dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/Kconfig 2015-02-10 15:33:19.353714552 +0100 -@@ -291,4 +291,28 @@ - - If unsure, say Y. - -+config DAHDI_YSTDM8XX -+ -+ tristate "Yeastar YSTDM8xx Support" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ This driver provides support for the Yeastar YSTDM8xx. -+ To compile this driver as a module, choose M here: the -+ module will be called ystdm8xx. -+ -+ If unsure, say Y. -+ -+config DAHDI_YSTDM16XX -+ -+ tristate "Yeastar YSTDM16xx Support" -+ depends on DAHDI && PCI -+ default DAHDI -+ ---help--- -+ This driver provides support for the Yeastar YSTDM16xx. -+ To compile this driver as a module, choose M here: the -+ module will be called ystdm16xx. -+ -+ If unsure, say Y. -+ - source "drivers/dahdi/xpp/Kconfig" -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/ystdm16xx.c dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/ystdm16xx.c ---- dahdi-linux-2.10.0.1/drivers/dahdi/ystdm16xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/ystdm16xx.c 2015-02-10 15:33:19.357047652 +0100 -@@ -0,0 +1,3151 @@ -+/* -+ * Yeastar YSTDM16xx TDM FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Derived from wctdm.c written by Mark Spencer <markster@linux-support.net> -+ * Matthew Fredrickson <creslin@linux-support.net> -+ * -+ * Copyright (C) 2006, Yeastar Technology Co.,Ltd. <support@yeastar.com> -+ * Copyright (C) 2001, Linux Support Services, Inc. -+ * -+ * All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/errno.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+#include <linux/ioctl.h> -+#include <asm/io.h> -+#include "proslic.h" -+/* -+ * 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; -+#define POLARITY_XOR (\ -+ (reversepolarity != 0) ^ (fxs->reversepolarity != 0) ^\ -+ (fxs->vmwi_lrev != 0) ^\ -+ ((fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) != 0)) -+ -+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",0x4000}, // playback volume set lower -+{27,14,"XMIT_DIGITAL_GAIN",0x3000}, -+//{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 "fxo_modes.h" -+ -+ -+#define NUM_FXO_REGS 60 -+ -+#define WC_MAX_IFACES 128 -+ -+#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_SYNC 0x0 -+#define WC_TEST 0x1 -+#define WC_CS 0x2 -+#define WC_CS1 0x6 -+#define WC_VER 0x3 -+#define YS_SLC 0x4 -+#define YS_DCH 0x7 -+#define YS_E0H 0x8 -+ -+#define BIT_SYNC (1 << 0) -+#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 -+ -+/* the constants below control the 'debounce' periods enforced by the -+ check_hook routines; these routines are called once every 4 interrupts -+ (the interrupt cycles around the four modules), so the periods are -+ specified in _4 millisecond_ increments -+*/ -+#define DEFAULT_RING_DEBOUNCE 32 /* Ringer Debounce (32 ms) */ -+ -+#define POLARITY_DEBOUNCE 32 /* Polarity debounce (32 ms) */ -+ -+#define OHT_TIMER 6000 /* How long after RING to retain OHT */ -+ -+/* NEON MWI pulse width - Make larger for longer period time -+ * For more information on NEON MWI generation using the proslic -+ * refer to Silicon Labs App Note "AN33-SI321X NEON FLASHING" -+ * RNGY = RNGY 1/2 * Period * 8000 -+ */ -+#define NEON_MWI_RNGY_PULSEWIDTH 0x3e8 /*=> period of 250 mS */ -+ -+#define FLAG_3215 (1 << 0) -+ -+#define NUM_CARDS 16 -+ -+#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, -+}; -+ -+#define NUM_REGS 109 -+#define NUM_INDIRECT_REGS 105 -+ -+struct ystdm_stats { -+ int tipvolt; /* TIP voltage (mV) */ -+ int ringvolt; /* RING voltage (mV) */ -+ int batvolt; /* VBAT voltage (mV) */ -+}; -+ -+struct ystdm_regs { -+ unsigned char direct[NUM_REGS]; -+ unsigned short indirect[NUM_INDIRECT_REGS]; -+}; -+ -+struct ystdm_regop { -+ int indirect; -+ unsigned char reg; -+ unsigned short val; -+}; -+ -+struct ystdm_echo_coefs { -+ unsigned char acim; -+ unsigned char coef1; -+ unsigned char coef2; -+ unsigned char coef3; -+ unsigned char coef4; -+ unsigned char coef5; -+ unsigned char coef6; -+ unsigned char coef7; -+ unsigned char coef8; -+}; -+ -+#define WCTDM_GET_STATS _IOR (DAHDI_CODE, 60, struct ystdm_stats) -+#define WCTDM_GET_REGS _IOR (DAHDI_CODE, 61, struct ystdm_regs) -+#define WCTDM_SET_REG _IOW (DAHDI_CODE, 62, struct ystdm_regop) -+#define WCTDM_SET_ECHOTUNE _IOW (DAHDI_CODE, 63, struct ystdm_echo_coefs) -+ -+struct ystdm { -+ 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[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; -+ int readcid; -+ unsigned int cidtimer; -+ } fxo; -+ struct fxs { -+ int oldrxhook; -+ int debouncehook; -+ int lastrxhook; -+ int debounce; -+ int ohttimer; -+ int idletxhookstate; /* IDLE changing hook state */ -+ int lasttxhook; -+ int palarms; -+ int reversepolarity; /* Reverse Line */ -+ int mwisendtype; -+ struct dahdi_vmwi_info vmwisetting; -+ int vmwi_active_messages; -+ u32 vmwi_lrev:1; /* MWI Line Reversal*/ -+ u32 vmwi_hvdc:1; /* MWI High Voltage DC Idle line */ -+ u32 vmwi_hvac:1; /* MWI Neon High Voltage AC Idle line */ -+ u32 neonringing:1; /* Ring Generator is set for NEON */ -+ struct calregs calregs; -+ } fxs; -+ } mod[NUM_CARDS]; -+ -+ /* Receive hook state and debouncing */ -+ int modtype[NUM_CARDS]; -+ unsigned char reg0shadow[NUM_CARDS]; -+ unsigned char reg1shadow[NUM_CARDS]; -+ -+ 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[NUM_CARDS]; -+ struct dahdi_chan *chans[NUM_CARDS]; -+}; -+ -+ -+struct ystdm_desc { -+ char *name; -+ int flags; -+}; -+ -+static struct ystdm_desc ystdme = { "YSTDM16xx REV E", 0 }; -+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; -+ -+static struct ystdm *ifaces[WC_MAX_IFACES]; -+ -+static void ystdm_release(struct ystdm *wc); -+ -+static unsigned int fxovoltage; -+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 dtmf = 0; -+static int fastpickup = 0; -+static int fxotxgain = 0; -+static int fxorxgain = 0; -+static int fxstxgain = 0; -+static int fxsrxgain = 0; -+ -+static int ystdm_init_proslic(struct ystdm *wc, int card, int fast , int manual, int sane); -+static int ystdm_init_ring_generator_mode(struct ystdm *wc, int card); -+static int ystdm_set_ring_generator_mode(struct ystdm *wc, int card, int mode); -+ -+static inline void ystdm_transmitprep(struct ystdm *wc, unsigned char ints) -+{ -+ volatile unsigned int *writechunk; -+ int x; -+ if (ints & 0x01) -+ /* Write is at interrupt address. Start writing from normal offset */ -+ writechunk = wc->writechunk; -+ else -+ writechunk = wc->writechunk + DAHDI_CHUNKSIZE * (NUM_CARDS / 4); -+ /* Calculate Transmission */ -+ dahdi_transmit(&wc->span); -+ -+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { -+ /* Send a sample, as a 32-bit word */ -+ writechunk[4 * x] = 0; -+ writechunk[4 * x + 1] = 0; -+ writechunk[4 * x + 2] = 0; -+ writechunk[4 * x + 3] = 0; -+#ifdef __BIG_ENDIAN -+ if (wc->cardflag & (1 << 15)) -+ writechunk[4 * x + 3] |= (wc->chans[15]->writechunk[x]); -+ if (wc->cardflag & (1 << 14)) -+ writechunk[4 * x + 3] |= (wc->chans[14]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 13)) -+ writechunk[4 * x + 3] |= (wc->chans[13]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 12)) -+ writechunk[4 * x + 3] |= (wc->chans[12]->writechunk[x] << 24); -+ -+ if (wc->cardflag & (1 << 11)) -+ writechunk[4 * x + 2] |= (wc->chans[11]->writechunk[x]); -+ if (wc->cardflag & (1 << 10)) -+ writechunk[4 * x + 2] |= (wc->chans[10]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 9)) -+ writechunk[4 * x + 2] |= (wc->chans[9]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 8)) -+ writechunk[4 * x + 2] |= (wc->chans[8]->writechunk[x] << 24); -+ -+ if (wc->cardflag & (1 << 7)) -+ writechunk[4 * x + 1] |= (wc->chans[7]->writechunk[x]); -+ if (wc->cardflag & (1 << 6)) -+ writechunk[4 * x + 1] |= (wc->chans[6]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 5)) -+ writechunk[4 * x + 1] |= (wc->chans[5]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 4)) -+ writechunk[4 * x + 1] |= (wc->chans[4]->writechunk[x] << 24); -+ -+ if (wc->cardflag & (1 << 3)) -+ writechunk[4 * x + 0] |= (wc->chans[3]->writechunk[x]); -+ if (wc->cardflag & (1 << 2)) -+ writechunk[4 * x + 0] |= (wc->chans[2]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 1)) -+ writechunk[4 * x + 0] |= (wc->chans[1]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 0)) -+ writechunk[4 * x + 0] |= (wc->chans[0]->writechunk[x] << 24); -+#else -+ if (wc->cardflag & (1 << 15)) -+ writechunk[4 * x + 3] |= (wc->chans[15]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 14)) -+ writechunk[4 * x + 3] |= (wc->chans[14]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 13)) -+ writechunk[4 * x + 3] |= (wc->chans[13]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 12)) -+ writechunk[4 * x + 3] |= (wc->chans[12]->writechunk[x]); -+ -+ if (wc->cardflag & (1 << 11)) -+ writechunk[4 * x + 2] |= (wc->chans[11]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 10)) -+ writechunk[4 * x + 2] |= (wc->chans[10]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 9)) -+ writechunk[4 * x + 2] |= (wc->chans[9]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 8)) -+ writechunk[4 * x + 2] |= (wc->chans[8]->writechunk[x]); -+ -+ if (wc->cardflag & (1 << 7)) -+ writechunk[4 * x + 1] |= (wc->chans[7]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 6)) -+ writechunk[4 * x + 1] |= (wc->chans[6]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 5)) -+ writechunk[4 * x + 1] |= (wc->chans[5]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 4)) -+ writechunk[4 * x + 1] |= (wc->chans[4]->writechunk[x]); -+ -+ if (wc->cardflag & (1 << 3)) -+ writechunk[4 * x + 0] |= (wc->chans[3]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 2)) -+ writechunk[4 * x + 0] |= (wc->chans[2]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 1)) -+ writechunk[4 * x + 0] |= (wc->chans[1]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 0)) -+ writechunk[4 * x + 0] |= (wc->chans[0]->writechunk[x]); -+#endif -+ } -+ -+} -+ -+#ifdef AUDIO_RINGCHECK -+static inline void ring_check(struct ystdm *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("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("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("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; -+ wc->mod[card].fxo.readcid = 1; -+ } -+ if (wc->mod[card].fxo.ring && !wc->mod[card].fxo.pegcount) { -+ /* No more ring */ -+ if (debug) -+ printk("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; -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ wc->mod[card].fxo.readcid = 0; -+ } -+ } -+} -+#endif -+static inline void ystdm_dtmfcheck_fakepolarity(struct ystdm *wc, int card, int x) -+{ -+ int sample; -+ /* only look for sound on the line if dtmf flag is on, it is an fxo card and line is onhook */ -+ if (!dtmf || !(wc->cardflag & (1 << card)) || !(wc->modtype[card] == MOD_TYPE_FXO) || wc->mod[card].fxo.offhook ) -+ return; -+ -+ /* don't look for noise if we're already processing it, or there is a ringing tone */ -+ if(!wc->mod[card].fxo.readcid && !wc->mod[card].fxo.wasringing && -+ wc->intcount > wc->mod[card].fxo.cidtimer + 400 ) { -+ sample = DAHDI_XLAW(wc->chans[card]->readchunk[x], (wc->chans[card])); -+ if (sample > 16000 || sample < -16000) { -+ wc->mod[card].fxo.readcid = 1; -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ if (debug) printk("DTMF CLIP on %i\n",card+1); -+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY); -+ } -+ } else if(wc->mod[card].fxo.readcid && wc->intcount > wc->mod[card].fxo.cidtimer + 2000) { -+ /* reset flags if it's been a while */ -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ wc->mod[card].fxo.readcid = 0; -+ } -+} -+static inline void ystdm_receiveprep(struct ystdm *wc, unsigned char ints) -+{ -+ volatile unsigned int *readchunk; -+ int x; -+ int y; -+ -+ if (ints & 0x08) -+ readchunk = wc->readchunk + DAHDI_CHUNKSIZE * (NUM_CARDS / 4); -+ else -+ /* Read is at interrupt address. Valid data is available at normal offset */ -+ readchunk = wc->readchunk; -+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { -+#ifdef __BIG_ENDIAN -+ if (wc->cardflag & (1 << 15)) -+ wc->chans[15]->readchunk[x] = (readchunk[4 * x]) & 0xff; -+ if (wc->cardflag & (1 << 14)) -+ wc->chans[14]->readchunk[x] = (readchunk[4 * x] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 13)) -+ wc->chans[13]->readchunk[x] = (readchunk[4 * x] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 12)) -+ wc->chans[12]->readchunk[x] = (readchunk[4 * x] >> 24) & 0xff; -+ -+ if (wc->cardflag & (1 << 11)) -+ wc->chans[11]->readchunk[x] = (readchunk[4 * x + 3]) & 0xff; -+ if (wc->cardflag & (1 << 10)) -+ wc->chans[10]->readchunk[x] = (readchunk[4 * x + 3] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 9)) -+ wc->chans[9]->readchunk[x] = (readchunk[4 * x + 3] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 8)) -+ wc->chans[8]->readchunk[x] = (readchunk[4 * x + 3] >> 24) & 0xff; -+ -+ if (wc->cardflag & (1 << 7)) -+ wc->chans[7]->readchunk[x] = (readchunk[4 * x + 2]) & 0xff; -+ if (wc->cardflag & (1 << 6)) -+ wc->chans[6]->readchunk[x] = (readchunk[4 * x + 2] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 5)) -+ wc->chans[5]->readchunk[x] = (readchunk[4 * x + 2] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 4)) -+ wc->chans[4]->readchunk[x] = (readchunk[4 * x + 2] >> 24) & 0xff; -+ -+ if (wc->cardflag & (1 << 3)) -+ wc->chans[3]->readchunk[x] = (readchunk[4 * x + 1]) & 0xff; -+ if (wc->cardflag & (1 << 2)) -+ wc->chans[2]->readchunk[x] = (readchunk[4 * x + 1] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 1)) -+ wc->chans[1]->readchunk[x] = (readchunk[4 * x + 1] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 0)) -+ wc->chans[0]->readchunk[x] = (readchunk[4 * x + 1] >> 24) & 0xff; -+#else -+ if (wc->cardflag & (1 << 15)) -+ wc->chans[15]->readchunk[x] = (readchunk[4 * x] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 14)) -+ wc->chans[14]->readchunk[x] = (readchunk[4 * x] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 13)) -+ wc->chans[13]->readchunk[x] = (readchunk[4 * x] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 12)) -+ wc->chans[12]->readchunk[x] = (readchunk[4 * x]) & 0xff; -+ -+ if (wc->cardflag & (1 << 11)) -+ wc->chans[11]->readchunk[x] = (readchunk[4 * x + 3] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 10)) -+ wc->chans[10]->readchunk[x] = (readchunk[4 * x + 3] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 9)) -+ wc->chans[9]->readchunk[x] = (readchunk[4 * x + 3] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 8)) -+ wc->chans[8]->readchunk[x] = (readchunk[4 * x + 3]) & 0xff; -+ -+ if (wc->cardflag & (1 << 7)) -+ wc->chans[7]->readchunk[x] = (readchunk[4 * x + 2] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 6)) -+ wc->chans[6]->readchunk[x] = (readchunk[4 * x + 2] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 5)) -+ wc->chans[5]->readchunk[x] = (readchunk[4 * x + 2] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 4)) -+ wc->chans[4]->readchunk[x] = (readchunk[4 * x + 2]) & 0xff; -+ -+ if (wc->cardflag & (1 << 3)) -+ wc->chans[3]->readchunk[x] = (readchunk[4 * x + 1] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 2)) -+ wc->chans[2]->readchunk[x] = (readchunk[4 * x + 1] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 1)) -+ wc->chans[1]->readchunk[x] = (readchunk[4 * x + 1] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 0)) -+ wc->chans[0]->readchunk[x] = (readchunk[4 * x + 1]) & 0xff; -+ -+#endif -+ for(y = 0; y < NUM_CARDS; y ++) -+ ystdm_dtmfcheck_fakepolarity(wc,y,x); -+ } -+#ifdef AUDIO_RINGCHECK -+ for (x=0;x<wc->cards;x++) -+ ring_check(wc, x); -+#endif -+ /* XXX We're wasting 8 taps. We should get closer :( */ -+ for (x = 0; x < 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 ystdm_stop_dma(struct ystdm *wc); -+static void ystdm_reset_tdm(struct ystdm *wc); -+static void ystdm_restart_dma(struct ystdm *wc); -+ -+static inline void __write_8bits(struct ystdm *wc, unsigned char bits) -+{ -+/* Out BIT_CS --\________________________________/---- */ -+/* Out BIT_SCLK ---\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/------ */ -+/* Out BIT_SDI ---\___/---\___/---\___/---\___/-------- */ -+/* Data Bit 7 6 5 4 3 2 1 0 */ -+/* Data written 0 1 0 1 0 1 0 1 */ -+ /* Drop chip select */ -+ int x; -+ 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); -+ -+} -+ -+static inline void __reset_spi(struct ystdm *wc) -+{ -+ /* 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); -+ -+} -+ -+static inline unsigned char __read_8bits(struct ystdm *wc) -+{ -+/* Out BIT_CS --\________________________________________/----*/ -+/* Out BIT_SCLK ---\_/--\_/--\_/--\_/--\_/--\_/--\_/--\_/-------*/ -+/* In BIT_SDO ????/1111\0000/1111\0000/1111\0000/1111\0000/???*/ -+/* Data bit 7 6 5 4 3 2 1 0 */ -+/* Data Read 1 0 1 0 1 0 1 0 */ -+ -+/* Note: Clock High time is 2x Low time, due to input read */ -+ -+ unsigned char res=0, c; -+ int x; -+ /* Drop chip select */ -+ wc->ios &= ~BIT_CS; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ for (x=0;x<8;x++) { -+ res <<= 1; -+ /* Drop SCLK */ -+ wc->ios &= ~BIT_SCLK; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ /* Now raise SCLK high again */ -+ 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; -+ } -+ /* Finally raise CS back high again */ -+ wc->ios |= BIT_CS; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ -+ /* And return our result */ -+ return res; -+} -+ -+static void __ystdm_setcreg(struct ystdm *wc, unsigned char reg, unsigned char val) -+{ -+ outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); -+} -+ -+static unsigned char __ystdm_getcreg(struct ystdm *wc, unsigned char reg) -+{ -+ return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); -+} -+ -+static inline void __ystdm_setcard(struct ystdm *wc, int card) -+{ -+ if (wc->curcard == card) -+ return; -+ if (card < NUM_CARDS/2) { -+ __ystdm_setcreg(wc, WC_CS1, 0); -+ __ystdm_setcreg(wc, WC_CS, (1 << card)); -+ } else { -+ __ystdm_setcreg(wc, WC_CS, 0); -+ __ystdm_setcreg(wc, WC_CS1, (1 << (card-8))); -+ } -+ wc->curcard = card; -+} -+ -+static void __ystdm_setreg(struct ystdm *wc, int card, unsigned char reg, unsigned char value) -+{ -+ __ystdm_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 ystdm_setreg(struct ystdm *wc, int card, unsigned char reg, unsigned char value) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc->lock, flags); -+ __ystdm_setreg(wc, card, reg, value); -+ spin_unlock_irqrestore(&wc->lock, flags); -+} -+ -+static unsigned char __ystdm_getreg(struct ystdm *wc, int card, unsigned char reg) -+{ -+ __ystdm_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 ystdm *wc, int card) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc->lock, flags); -+ __ystdm_setcard(wc, card); -+ __reset_spi(wc); -+ __reset_spi(wc); -+ spin_unlock_irqrestore(&wc->lock, flags); -+} -+ -+static unsigned char ystdm_getreg(struct ystdm *wc, int card, unsigned char reg) -+{ -+ unsigned long flags; -+ unsigned char res; -+ spin_lock_irqsave(&wc->lock, flags); -+ res = __ystdm_getreg(wc, card, reg); -+ spin_unlock_irqrestore(&wc->lock, flags); -+ return res; -+} -+ -+static int __wait_access(struct ystdm *wc, int card) -+{ -+ unsigned char data = 0; -+ -+ int count = 0; -+ -+ #define MAX 6000 /* attempts */ -+ -+ /* Wait for indirect access */ -+ while (count++ < MAX) -+ { -+ data = __ystdm_getreg(wc, card, I_STATUS); -+ -+ if (!data) -+ return 0; -+ -+ } -+ -+ if(count > (MAX-1)) printk(" ##### 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 ystdm_proslic_setreg_indirect(struct ystdm *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)) { -+ __ystdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF)); -+ __ystdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); -+ __ystdm_setreg(wc, card, IAA,address); -+ res = 0; -+ }; -+ spin_unlock_irqrestore(&wc->lock, flags); -+ return res; -+} -+ -+static int ystdm_proslic_getreg_indirect(struct ystdm *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)) { -+ __ystdm_setreg(wc, card, IAA, address); -+ if (!__wait_access(wc, card)) { -+ unsigned char data1, data2; -+ data1 = __ystdm_getreg(wc, card, IDA_LO); -+ data2 = __ystdm_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(p); -+ return res; -+} -+ -+static int ystdm_proslic_init_indirect_regs(struct ystdm *wc, int card) -+{ -+ unsigned char i; -+ -+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) -+ { -+ if(ystdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int ystdm_proslic_verify_indirect_regs(struct ystdm *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 = ystdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { -+ printk("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("!!!!!!! %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("Init Indirect Registers completed successfully.\n"); -+ } else { -+ printk(" !!!!! Init Indirect Registers UNSUCCESSFULLY.\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+static inline void ystdm_proslic_recheck_sanity(struct ystdm *wc, int card) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ int res; -+ /* Check loopback */ -+ res = wc->reg1shadow[card]; -+ if (!res && (res != fxs->lasttxhook)) { -+ res = ystdm_getreg(wc, card, 8); -+ if (res) { -+ printk(KERN_NOTICE "Ouch, part reset, quickly restoring reality (%d)\n", card); -+ ystdm_init_proslic(wc, card, 1, 0, 1); -+ } else { -+ if (fxs->palarms++ < MAX_ALARMS) { -+ printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1); -+ if (fxs->lasttxhook == SLIC_LF_RINGING) -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ ystdm_setreg(wc, card, 64, fxs->lasttxhook); -+ } else { -+ if (fxs->palarms == MAX_ALARMS) -+ printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1); -+ } -+ } -+ } -+} -+ -+static inline void ystdm_voicedaa_check_hook(struct ystdm *wc, int card) -+{ -+#define MS_PER_CHECK_HOOK 16 -+ -+#ifndef AUDIO_RINGCHECK -+ unsigned char res; -+#endif -+ signed char b; -+ int poopy = 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("Poopy (%02x) on card %d!\n", b, card + 1); -+ poopy++; -+ } -+ b &= 0x9b; -+ if (fxo->offhook) { -+ if (b != 0x9) -+ ystdm_setreg(wc, card, 5, 0x9); -+ } else { -+ if (b != 0x8) -+ ystdm_setreg(wc, card, 5, 0x8); -+ } -+ if (poopy) -+ return; -+ if (!fxo->offhook) { -+ if (fwringdetect) { -+ res = wc->reg0shadow[card] & 0x60; -+ if (fxo->ringdebounce--) { -+ if (res && (res != fxo->lastrdtx) && -+ (fxo->battery == BATTERY_PRESENT)) { -+ if (!fxo->wasringing) { -+ fxo->wasringing = 1; -+ if (debug) -+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1); -+ 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("NO RING on %d/%d!\n", wc->span.spanno, card + 1); -+ 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; -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_RING); -+ if (debug) -+ printk("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; -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); -+ if (debug) -+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1); -+ } -+ fxo->ringdebounce = 0; -+ } -+ } -+ } -+ } -+ -+ b = wc->reg1shadow[card]; -+ -+ if (fxovoltage) { -+ static int count = 0; -+ if (!(count++ % 100)) { -+ printk(KERN_DEBUG "Card %d: Voltage: %d Debounce %d\n", card + 1, b, fxo->battdebounce); -+ } -+ } -+ -+ if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) { -+ /* -+ * dahdi-base will set DAHDI_RXSIG_INITIAL after a -+ * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events -+ * will be queued on the channel with the current received -+ * hook state. Channels that use robbed-bit signalling always -+ * report the current received state via the dahdi_rbsbits -+ * call. Since we only call dahdi_hooksig when we've detected -+ * a change to report, let's forget our current state in order -+ * to force us to report it again via dahdi_hooksig. -+ * -+ */ -+ fxo->battery = BATTERY_UNKNOWN; -+ } -+ -+if (DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig) { -+ /* If we've been set to the initial state, let's reset the -+ * battery state to unknown so that we will reset the -+ * current state of the battery and call dahdi_hooksig. */ -+ fxo->battery = BATTERY_UNKNOWN; -+ } /* add by David at 2009.09.10 */ -+ -+ 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("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("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("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("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 ? DAHDI_ALARM_NONE : DAHDI_ALARM_RED); -+ } -+ } -+ -+ if (fxo->polaritydebounce) { -+ if (--fxo->polaritydebounce == 0) { -+ if (fxo->lastpol != fxo->polarity) { -+ if (debug) -+ printk("%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 void ystdm_fxs_hooksig(struct ystdm *wc, const int card, enum dahdi_txsig txsig) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ switch (txsig) { -+ case DAHDI_TXSIG_ONHOOK: -+ switch (wc->span.chans[card]->sig) { -+ case DAHDI_SIG_FXOKS: -+ case DAHDI_SIG_FXOLS: -+ /* Can't change Ring Generator during OHT */ -+ if (!fxs->ohttimer) { -+ ystdm_set_ring_generator_mode(wc, -+ card, fxs->vmwi_hvac); -+ fxs->lasttxhook = fxs->vmwi_hvac ? -+ SLIC_LF_RINGING : -+ fxs->idletxhookstate; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ break; -+ case DAHDI_SIG_EM: -+ fxs->lasttxhook = fxs->idletxhookstate; -+ break; -+ case DAHDI_SIG_FXOGS: -+ fxs->lasttxhook = SLIC_LF_TIP_OPEN; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_OFFHOOK: -+ switch (wc->span.chans[card]->sig) { -+ case DAHDI_SIG_EM: -+ fxs->lasttxhook = SLIC_LF_ACTIVE_REV; -+ break; -+ default: -+ fxs->lasttxhook = fxs->idletxhookstate; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_START: -+ /* Set ringer mode */ -+ ystdm_set_ring_generator_mode(wc, card, 0); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ break; -+ case DAHDI_TXSIG_KEWL: -+ fxs->lasttxhook = SLIC_LF_OPEN; -+ break; -+ default: -+ printk(KERN_NOTICE "ystdm: Can't set tx state to %d\n", txsig); -+ return; -+ } -+ if (debug) { -+ printk(KERN_DEBUG -+ "Setting FXS hook state to %d (%02x)\n", -+ txsig, fxs->lasttxhook); -+ } -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+} -+ -+static inline void ystdm_proslic_check_hook(struct ystdm *wc, int card) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ char res; -+ int hook; -+ -+ /* For some reason we have to debounce the -+ hook detector. */ -+ -+ res = wc->reg0shadow[card]; -+ hook = (res & 1); -+ if (hook != fxs->lastrxhook) { -+ /* Reset the debounce (must be multiple of 4ms) */ -+ fxs->debounce = dialdebounce * 4; -+#if 0 -+ printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", -+ card, hook, fxs->debounce); -+#endif -+ } else { -+ if (fxs->debounce > 0) { -+ fxs->debounce -= 16 * DAHDI_CHUNKSIZE; -+#if 0 -+ printk(KERN_DEBUG "Sustaining hook %d, %d\n", -+ hook, fxs->debounce); -+#endif -+ if (!fxs->debounce) { -+#if 0 -+ printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook); -+#endif -+ fxs->debouncehook = hook; -+ } -+ if (!fxs->oldrxhook && fxs->debouncehook) { -+ /* Off hook */ -+#if 1 -+ if (debug) -+#endif -+ printk(KERN_DEBUG "ystdm: Card %d Going off hook\n", card); -+ -+ switch (fxs->lasttxhook) { -+ case SLIC_LF_RINGING: -+ case SLIC_LF_OHTRAN_FWD: -+ case SLIC_LF_OHTRAN_REV: -+ /* just detected OffHook, during -+ * Ringing or OnHookTransfer */ -+ fxs->idletxhookstate = -+ POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ break; -+ } -+ -+ ystdm_fxs_hooksig(wc, card, DAHDI_TXSIG_OFFHOOK); -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); -+ if (robust) -+ ystdm_init_proslic(wc, card, 1, 0, 1); -+ fxs->oldrxhook = 1; -+ -+ } else if (fxs->oldrxhook && !fxs->debouncehook) { -+ /* On hook */ -+#if 1 -+ if (debug) -+#endif -+ printk(KERN_DEBUG "ystdm: Card %d Going on hook\n", card); -+ ystdm_fxs_hooksig(wc, card, DAHDI_TXSIG_ONHOOK); -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); -+ fxs->oldrxhook = 0; -+ } -+ } -+ } -+ fxs->lastrxhook = hook; -+} -+ -+DAHDI_IRQ_HANDLER(ystdm_interrupt) -+{ -+ struct ystdm *wc = dev_id; -+ unsigned char ints; -+ int x; -+ int mode; -+ -+ ints = inb(wc->ioaddr + WC_INTSTAT); -+ outb(ints, wc->ioaddr + WC_INTSTAT); -+ -+ if (!ints) -+ return IRQ_NONE; -+ -+ outb(ints, wc->ioaddr + WC_INTSTAT); -+ -+ if (ints & 0x10) { -+ /* Stop DMA, wait for watchdog */ -+ printk("TDM PCI Master abort\n"); -+ ystdm_stop_dma(wc); -+ -+ return IRQ_RETVAL(1); -+ -+ } -+ -+ if (ints & 0x20) { -+ printk("PCI Target abort\n"); -+ return IRQ_RETVAL(1); -+ } -+ -+ for (x=0;x<NUM_CARDS;x++) { -+ if (wc->cardflag & (1 << x) && -+ (wc->modtype[x] == MOD_TYPE_FXS)) { -+ struct fxs *const fxs = &wc->mod[x].fxs; -+ if (fxs->lasttxhook == SLIC_LF_RINGING && -+ !fxs->neonringing) { -+ /* RINGing, prepare for OHT */ -+ fxs->ohttimer = OHT_TIMER << 3; -+ -+ /* logical XOR 3 variables -+ module parameter 'reversepolarity', global reverse all FXS lines. -+ ioctl channel variable fxs 'reversepolarity', Line Reversal Alert Signal if required. -+ ioctl channel variable fxs 'vmwi_lrev', VMWI pending. -+ */ -+ -+ /* OHT mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR ? -+ SLIC_LF_OHTRAN_REV : -+ SLIC_LF_OHTRAN_FWD; -+ } else if (fxs->ohttimer) { -+ /* check if still OnHook */ -+ if (!fxs->oldrxhook) { -+ fxs->ohttimer -= DAHDI_CHUNKSIZE; -+ if (!fxs->ohttimer) { -+ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; /* Switch to Active, Rev or Fwd */ -+ /* if currently OHT */ -+ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) || (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) { -+ if (fxs->vmwi_hvac) { -+ /* force idle polarity Forward if ringing */ -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ /* Set ring generator for neon */ -+ ystdm_set_ring_generator_mode(wc, x, 1); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ /* Apply the change as appropriate */ -+ ystdm_setreg(wc, x, LINE_STATE, fxs->lasttxhook); -+ } -+ } -+ } else { -+ fxs->ohttimer = 0; -+ /* Switch to Active, Rev or Fwd */ -+ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ } -+ } -+ } -+ } -+ -+ if (ints & 0x0f) { -+ wc->intcount++; -+ x = wc->intcount & 0xf; -+ mode = wc->intcount & 0x30; -+ if (wc->cardflag & (1 << x)) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 16: -+ /* Read first shadow reg */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) -+ wc->reg0shadow[x] = ystdm_getreg(wc, x, 68); -+ else if (wc->modtype[x] == MOD_TYPE_FXO) -+ wc->reg0shadow[x] = ystdm_getreg(wc, x, 5); -+ break; -+ case 32: -+ /* Read second shadow reg */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) -+ wc->reg1shadow[x] = ystdm_getreg(wc, x, LINE_STATE); -+ else if (wc->modtype[x] == MOD_TYPE_FXO) -+ wc->reg1shadow[x] = ystdm_getreg(wc, x, 29); -+ break; -+ case 48: -+ /* Perform processing */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) { -+ ystdm_proslic_check_hook(wc, x); -+ if (!(wc->intcount & 0xf0)) { -+ ystdm_proslic_recheck_sanity(wc, x); -+ } -+ } else if (wc->modtype[x] == MOD_TYPE_FXO) { -+ ystdm_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ if (!(wc->intcount % 10000)) { -+ /* Accept an alarm once per 10 seconds */ -+ for (x=0;x<NUM_CARDS;x++) -+ if (wc->modtype[x] == MOD_TYPE_FXS) { -+ if (wc->mod[x].fxs.palarms) -+ wc->mod[x].fxs.palarms--; -+ } -+ } -+ ystdm_receiveprep(wc, ints); -+ ystdm_transmitprep(wc, ints); -+ } -+ return IRQ_RETVAL(1); -+ -+} -+ -+static int ystdm_voicedaa_insane(struct ystdm *wc, int card) -+{ -+ int blah; -+ blah = ystdm_getreg(wc, card, 2); -+ if (blah != 0x3) -+ return -2; -+ blah = ystdm_getreg(wc, card, 11); -+ if (debug) -+ printk("VoiceDAA System: %02x\n", blah & 0xf); -+ return 0; -+} -+ -+static int ystdm_proslic_insane(struct ystdm *wc, int card) -+{ -+ int blah,insane_report; -+ insane_report=0; -+ -+ blah = ystdm_getreg(wc, card, 0); -+ if (debug) -+ printk("ProSLIC on module %d, product %d, version %d\n", card, (blah & 0x30) >> 4, (blah & 0xf)); -+ -+#if 0 -+ if ((blah & 0x30) >> 4) { -+ printk("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("ProSLIC 3210 version %d is too old\n", blah & 0xf); -+ return -1; -+ } -+ if ((blah & 0xf) == 2) { -+ /* ProSLIC 3215, not a 3210 */ -+ wc->flags[card] |= FLAG_3215; -+ } -+ blah = ystdm_getreg(wc, card, 8); -+ if (blah != 0x2) { -+ printk("ProSLIC on module %d insane (1) %d should be 2\n", card, blah); -+ return -1; -+ } else if ( insane_report) -+ printk("ProSLIC on module %d Reg 8 Reads %d Expected is 0x2\n",card,blah); -+ -+ blah = ystdm_getreg(wc, card, 64); -+ if (blah != 0x0) { -+ printk("ProSLIC on module %d insane (2)\n", card); -+ return -1; -+ } else if ( insane_report) -+ printk("ProSLIC on module %d Reg 64 Reads %d Expected is 0x0\n",card,blah); -+ -+ blah = ystdm_getreg(wc, card, 11); -+ if (blah != 0x33) { -+ printk("ProSLIC on module %d insane (3)\n", card); -+ return -1; -+ } else if ( insane_report) -+ printk("ProSLIC on module %d Reg 11 Reads %d Expected is 0x33\n",card,blah); -+ -+ /* Just be sure it's setup right. */ -+ ystdm_setreg(wc, card, 30, 0); -+ -+ if (debug) -+ printk("ProSLIC on module %d seems sane.\n", card); -+ return 0; -+} -+ -+static int ystdm_proslic_powerleak_test(struct ystdm *wc, int card) -+{ -+ unsigned long origjiffies; -+ unsigned char vbat; -+ -+ /* Turn off linefeed */ -+ ystdm_setreg(wc, card, 64, 0); -+ -+ /* Power down */ -+ ystdm_setreg(wc, card, 14, 0x10); -+ -+ /* Wait for one second */ -+ origjiffies = jiffies; -+ -+ while((vbat = ystdm_getreg(wc, card, 82)) > 0x6) { -+ if ((jiffies - origjiffies) >= (HZ/2)) -+ break;; -+ } -+ -+ if (vbat < 0x06) { -+ printk("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("Post-leakage voltage: %d volts\n", 376 * vbat / 1000); -+ } -+ return 0; -+} -+ -+static int ystdm_powerup_proslic(struct ystdm *wc, int card, int fast) -+{ -+ unsigned char vbat; -+ unsigned long origjiffies; -+ int lim; -+ -+ /* Set period of DC-DC converter to 1/64 khz */ -+ ystdm_setreg(wc, card, 92, 0xff /* was 0xff */); -+ -+ /* Wait for VBat to powerup */ -+ origjiffies = jiffies; -+ -+ /* Disable powerdown */ -+ ystdm_setreg(wc, card, 14, 0); -+ -+ /* If fast, don't bother checking anymore */ -+ if (fast) -+ return 0; -+ -+ while((vbat = ystdm_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("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 YSTDM16xx??\n", -+ card, (int)(((jiffies - origjiffies) * 1000 / HZ)), -+ vbat * 375); -+ wc->proslic_power = PROSLIC_POWER_WARNED; -+ return -1; -+ } else if (debug) { -+ printk("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("Loop current out of range! Setting to default 20mA!\n"); -+ } -+ else if (debug) -+ printk("Loop current set to %dmA!\n",(lim*3)+20); -+ ystdm_setreg(wc,card,LOOP_I_LIMIT,lim); -+ -+ /* Engage DC-DC converter */ -+ ystdm_setreg(wc, card, 93, 0x19 /* was 0x19 */); -+#if 0 -+ origjiffies = jiffies; -+ while(0x80 & ystdm_getreg(wc, card, 93)) { -+ if ((jiffies - origjiffies) > 2 * HZ) { -+ printk("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 = ystdm_getreg(wc, card, 82); -+ printk("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 ystdm_proslic_manual_calibrate(struct ystdm *wc, int card){ -+ unsigned long origjiffies; -+ unsigned char i; -+ -+ ystdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 64, 0);//(0) -+ -+ ystdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. -+ ystdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM -+ -+ origjiffies=jiffies; -+ while( ystdm_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); -+ ystdm_proslic_setreg_indirect(wc, card, 88,0); -+ ystdm_proslic_setreg_indirect(wc, card, 89,0); -+ ystdm_proslic_setreg_indirect(wc, card, 90,0); -+ ystdm_proslic_setreg_indirect(wc, card, 91,0); -+ ystdm_proslic_setreg_indirect(wc, card, 92,0); -+ ystdm_proslic_setreg_indirect(wc, card, 93,0); -+ -+ ystdm_setreg(wc, card, 98, 0x10); // This is necessary if the calibration occurs other than at reset time -+ ystdm_setreg(wc, card, 99, 0x10); -+ -+ for ( i=0x1f; i>0; i--) -+ { -+ ystdm_setreg(wc, card, 98, i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((ystdm_getreg(wc, card, 88)) == 0) -+ break; -+ } // for -+ -+ for ( i=0x1f; i>0; i--) -+ { -+ ystdm_setreg(wc, card, 99, i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((ystdm_getreg(wc, card, 89)) == 0) -+ break; -+ }//for -+ -+/*******************************The preceding is the manual gain mismatch calibration****************************/ -+/**********************************The following is the longitudinal Balance Cal***********************************/ -+ ystdm_setreg(wc,card,64,1); -+ while((jiffies-origjiffies)<10); // Sleep 100? -+ -+ ystdm_setreg(wc, card, 64, 0); -+ ystdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal -+ ystdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration -+ ystdm_setreg(wc, card, 96, 0x40); -+ -+ ystdm_getreg(wc, card, 96); /* Read Reg 96 just cause */ -+ -+ ystdm_setreg(wc, card, 21, 0xFF); -+ ystdm_setreg(wc, card, 22, 0xFF); -+ ystdm_setreg(wc, card, 23, 0xFF); -+ -+ /**The preceding is the longitudinal Balance Cal***/ -+ return(0); -+ -+} -+#if 1 -+static int ystdm_proslic_calibrate(struct ystdm *wc, int card) -+{ -+ unsigned long origjiffies; -+ int x; -+ /* Perform all calibrations */ -+ ystdm_setreg(wc, card, 97, 0x1f); -+ -+ /* Begin, no speedup */ -+ ystdm_setreg(wc, card, 96, 0x5f); -+ -+ /* Wait for it to finish */ -+ origjiffies = jiffies; -+ while(ystdm_getreg(wc, card, 96)) { -+ if ((jiffies - origjiffies) > 2 * HZ) { -+ printk("Timeout waiting for calibration of module %d\n", card); -+ return -1; -+ } -+ } -+ -+ if (debug) { -+ /* Print calibration parameters */ -+ printk("Calibration Vector Regs 98 - 107: \n"); -+ for (x=98;x<108;x++) { -+ printk("%d: %02x\n", x, ystdm_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 ystdm_set_hwgain(struct ystdm *wc, int card, __s32 gain, __u32 tx) -+{ -+ if (!(wc->modtype[card] == MOD_TYPE_FXO)) { -+ printk("Cannot adjust gain. Unsupported module type!\n"); -+ return -1; -+ } -+ if (tx) { -+ if (debug) -+ printk("setting FXO tx gain for card=%d to %d\n", card, gain); -+ if (gain >= -150 && gain <= 0) { -+ ystdm_setreg(wc, card, 38, 16 + (gain/-10)); -+ ystdm_setreg(wc, card, 40, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ ystdm_setreg(wc, card, 38, gain/10); -+ ystdm_setreg(wc, card, 40, (gain%10)); -+ } else { -+ printk("FXO tx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } else { /* rx */ -+ if (debug) -+ printk("setting FXO rx gain for card=%d to %d\n", card, gain); -+ if (gain >= -150 && gain <= 0) { -+ ystdm_setreg(wc, card, 39, 16+ (gain/-10)); -+ ystdm_setreg(wc, card, 41, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ ystdm_setreg(wc, card, 39, gain/10); -+ ystdm_setreg(wc, card, 41, (gain%10)); -+ } else { -+ printk("FXO rx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int set_vmwi(struct ystdm * wc, int chan_idx) -+{ -+ struct fxs *const fxs = &wc->mod[chan_idx].fxs; -+ if (fxs->vmwi_active_messages) { -+ fxs->vmwi_lrev = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV) ? 1 : 0; -+ fxs->vmwi_hvdc = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVDC) ? 1 : 0; -+ fxs->vmwi_hvac = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) ? 1 : 0; -+ } else { -+ fxs->vmwi_lrev = 0; -+ fxs->vmwi_hvdc = 0; -+ fxs->vmwi_hvac = 0; -+ } -+ -+ if (debug) { -+ printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, " -+ "lrev=%d, hvdc=%d, hvac=%d\n", -+ chan_idx, -+ fxs->vmwi_active_messages, -+ fxs->vmwi_lrev, -+ fxs->vmwi_hvdc, -+ fxs->vmwi_hvac -+ ); -+ } -+ if (fxs->vmwi_hvac) { -+ /* Can't change ring generator while in On Hook Transfer mode*/ -+ if (!fxs->ohttimer) { -+ if (POLARITY_XOR) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ /* Set ring generator for neon */ -+ ystdm_set_ring_generator_mode(wc, chan_idx, 1); -+ /* Activate ring to send neon pulses */ -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ ystdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ } else { -+ if (fxs->neonringing) { -+ /* Set ring generator for normal ringer */ -+ ystdm_set_ring_generator_mode(wc, chan_idx, 0); -+ /* ACTIVE, polarity determined later */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ } else if ((fxs->lasttxhook == SLIC_LF_RINGING) || -+ (fxs->lasttxhook == SLIC_LF_OPEN)) { -+ /* Can't change polarity while ringing or when open, -+ set idlehookstate instead */ -+ if (POLARITY_XOR) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ -+ printk(KERN_DEBUG "Unable to change polarity on channel" -+ "%d, lasttxhook=0x%X\n", -+ chan_idx, -+ fxs->lasttxhook -+ ); -+ return 0; -+ } -+ if (POLARITY_XOR) { -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ fxs->lasttxhook |= SLIC_LF_REVMASK; -+ } else { -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ fxs->lasttxhook &= ~SLIC_LF_REVMASK; -+ } -+ ystdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ return 0; -+} -+ -+ -+static int ystdm_init_voicedaa(struct ystdm *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 && ystdm_voicedaa_insane(wc, card)) -+ return -2; -+ -+ /* Software reset */ -+ ystdm_setreg(wc, card, 1, 0x80); -+ -+ /* Wait just a bit */ -+ wait_just_a_bit(HZ/10); -+ -+ /* Enable PCM, ulaw */ -+ if (alawoverride){ -+ ystdm_setreg(wc, card, 33, 0x20); -+ } else { -+ ystdm_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); -+ ystdm_setreg(wc, card, 16, reg16); -+ -+ if(fwringdetect) { -+ /* Enable ring detector full-wave rectifier mode */ -+ ystdm_setreg(wc, card, 18, 2); -+ ystdm_setreg(wc, card, 24, 0); -+ } else { -+ /* Set to the device defaults */ -+ ystdm_setreg(wc, card, 18, 0); -+ ystdm_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); -+ ystdm_setreg(wc, card, 26, reg26); -+ -+ /* Set AC Impedence */ -+ reg30 = (fxo_modes[_opermode].acim); -+ ystdm_setreg(wc, card, 30, reg30); -+ -+ /* Misc. DAA parameters */ -+ if (fastpickup) -+ reg31 = 0xe3; -+ else -+ reg31 = 0xa3; -+ -+ reg31 |= (fxo_modes[_opermode].ohs2 << 3); -+ ystdm_setreg(wc, card, 31, reg31); -+ -+ /* Set Transmit/Receive timeslot */ -+ if (card < NUM_CARDS/4) { -+ ystdm_setreg(wc, card, 34, (3-card) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (3-card) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } else if (card < NUM_CARDS/2) { -+ ystdm_setreg(wc, card, 34, (15-card) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (15-card) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } else if (card < (NUM_CARDS*3)/4) { -+ ystdm_setreg(wc, card, 34, (27-card) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (27-card) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } else { -+ ystdm_setreg(wc, card, 34, (39-card) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (39-card) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } -+ -+ /* Enable ISO-Cap */ -+ ystdm_setreg(wc, card, 6, 0x00); -+ if (fastpickup) -+ ystdm_setreg(wc, card, 17, ystdm_getreg(wc, card, 17) | 0x20); -+ -+ /* Wait 1000ms for ISO-cap to come up */ -+ newjiffies = jiffies; -+ newjiffies += 2 * HZ; -+ while((jiffies < newjiffies) && !(ystdm_getreg(wc, card, 11) & 0xf0)) -+ wait_just_a_bit(HZ/10); -+ -+ if (!(ystdm_getreg(wc, card, 11) & 0xf0)) { -+ printk("VoiceDAA did not bring up ISO link properly!\n"); -+ return -1; -+ } -+ if (debug) -+ printk("ISO-Cap is now up, line side: %02x rev %02x\n", -+ ystdm_getreg(wc, card, 11) >> 4, -+ (ystdm_getreg(wc, card, 13) >> 2) & 0xf); -+ /* Enable on-hook line monitor */ -+ ystdm_setreg(wc, card, 5, 0x08); -+ /* Take values for fxotxgain and fxorxgain and apply them to module */ -+ if (fxotxgain) -+ ystdm_set_hwgain(wc, card, fxotxgain, 1); -+ else -+ ystdm_set_hwgain(wc, card, 0, 1); -+ if (fxorxgain) -+ ystdm_set_hwgain(wc, card, fxorxgain, 0); -+ else -+ ystdm_set_hwgain(wc, card, 20, 0); -+ -+ /* NZ -- crank the tx gain up by 7 dB */ -+ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) { -+ printk("Adjusting gain\n"); -+ ystdm_set_hwgain(wc, card, 7, 1); -+ -+ } -+ /* KR -- crank the rv gain up by 9 dB */ -+ if (!strcmp(fxo_modes[_opermode].name, "SOUTHKOREA")) { -+ printk("Adjusting gain\n"); -+ ystdm_setreg(wc, card, 39, 0x9); -+ } -+ if(debug) -+ printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (ystdm_getreg(wc, card, 38)/16)?-(ystdm_getreg(wc, card, 38) - 16) : ystdm_getreg(wc, card, 38), (ystdm_getreg(wc, card, 40)/16)? -(ystdm_getreg(wc, card, 40) - 16):ystdm_getreg(wc, card, 40), (ystdm_getreg(wc, card, 39)/16)? -(ystdm_getreg(wc, card, 39) - 16) : ystdm_getreg(wc, card, 39),(ystdm_getreg(wc, card, 41)/16)?-(ystdm_getreg(wc, card, 41) - 16):ystdm_getreg(wc, card, 41)); -+ -+ return 0; -+ -+} -+ -+static int ystdm_init_proslic(struct ystdm *wc, int card, int fast, int manual, int sane) -+{ -+ -+ unsigned short tmp[5]; -+ unsigned char r19,r9; -+ int x; -+ int fxsmode=0; -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ -+ /* Sanity check the ProSLIC */ -+ if (!sane && ystdm_proslic_insane(wc, card)) -+ return -2; -+ -+ /* default messages to none and method to FSK */ -+ memset(&fxs->vmwisetting, 0, sizeof(fxs->vmwisetting)); -+ fxs->vmwi_lrev = 0; -+ fxs->vmwi_hvdc = 0; -+ fxs->vmwi_hvac = 0; -+ -+ /* By default, don't send on hook */ -+ if (!reversepolarity != !fxs->reversepolarity) -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_REV; -+ else -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ -+ /* Sanity check the ProSLIC */ -+ -+ if (sane) { -+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ -+ ystdm_setreg(wc, card, 14, 0x10); -+ } -+ -+ if (ystdm_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 */ -+ ystdm_proslic_setreg_indirect(wc, card, 97,0); -+ -+ /* Clear digital loopback */ -+ ystdm_setreg(wc, card, 8, 0); -+ -+ /* Revision C optimization */ -+ ystdm_setreg(wc, card, 108, 0xeb); -+ -+ /* Disable automatic VBat switching for safety to prevent -+ Q7 from accidently turning on and burning out. */ -+ ystdm_setreg(wc, card, 67, 0x07); -+ -+ /* Turn off Q7 */ -+ ystdm_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] = ystdm_proslic_getreg_indirect(wc, card, x + 35); -+ ystdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000); -+ } -+ -+ /* Power up the DC-DC converter */ -+ if (ystdm_powerup_proslic(wc, card, fast)) { -+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+ -+ if (!fast) { -+ -+ /* Check for power leaks */ -+ if (ystdm_proslic_powerleak_test(wc, card)) { -+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); -+ } -+ /* Power up again */ -+ if (ystdm_powerup_proslic(wc, card, fast)) { -+ printk("Unable to do FINAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+#ifndef NO_CALIBRATION -+ /* Perform calibration */ -+ if(manual) { -+ if (ystdm_proslic_manual_calibrate(wc, card)) { -+ //printk("Proslic failed on Manual Calibration\n"); -+ if (ystdm_proslic_manual_calibrate(wc, card)) { -+ printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); -+ return -1; -+ } -+ printk("Proslic Passed Manual Calibration on Second Attempt\n"); -+ } -+ } -+ else { -+ if(ystdm_proslic_calibrate(wc, card)) { -+ //printk("ProSlic died on Auto Calibration.\n"); -+ if (ystdm_proslic_calibrate(wc, card)) { -+ printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); -+ return -1; -+ } -+ printk("Proslic Passed Auto Calibration on Second Attempt\n"); -+ } -+ } -+ /* Perform DC-DC calibration */ -+ ystdm_setreg(wc, card, 93, 0x99); -+ r19 = ystdm_getreg(wc, card, 107); -+ if ((r19 < 0x2) || (r19 > 0xd)) { -+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); -+ ystdm_setreg(wc, card, 107, 0x8); -+ } -+ -+ /* Save calibration vectors */ -+ for (x=0;x<NUM_CAL_REGS;x++) -+ fxs->calregs.vals[x] = ystdm_getreg(wc, card, 96 + x); -+#endif -+ -+ } else { -+ /* Restore calibration registers */ -+ for (x=0;x<NUM_CAL_REGS;x++) -+ ystdm_setreg(wc, card, 96 + x, fxs->calregs.vals[x]); -+ } -+ /* Calibration complete, restore original values */ -+ for (x=0;x<5;x++) { -+ ystdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); -+ } -+ -+ if (ystdm_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" */ -+ ystdm_setreg(wc, card, 67, 0x0e); -+ blah = ystdm_getreg(wc, card, 67); -+#endif -+ -+#if 0 -+ if (ystdm_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) -+ ystdm_setreg(wc, card, 1, 0x20); -+ else -+ ystdm_setreg(wc, card, 1, 0x28); -+ // U-Law 8-bit interface -+ if (card < NUM_CARDS/4) { -+ ystdm_setreg(wc, card, 2, (3-card) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (3-card) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } else if (card < NUM_CARDS/2) { -+ ystdm_setreg(wc, card, 2, (15-card) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (15-card) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } else if (card < (NUM_CARDS*3)/4) { -+ ystdm_setreg(wc, card, 2, (27-card) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (27-card) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } else { -+ ystdm_setreg(wc, card, 2, (39-card) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (39-card) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } -+ ystdm_setreg(wc, card, 18, 0xff); // clear all interrupt -+ ystdm_setreg(wc, card, 19, 0xff); -+ ystdm_setreg(wc, card, 20, 0xff); -+ ystdm_setreg(wc, card, 73, 0x04); -+ if (fxshonormode) { -+ fxsmode = acim2tiss[fxo_modes[_opermode].acim]; -+ ystdm_setreg(wc, card, 10, 0x08 | fxsmode); -+ } -+ if (lowpower) -+ ystdm_setreg(wc, card, 72, 0x10); -+ -+#if 0 -+ ystdm_setreg(wc, card, 21, 0x00); // enable interrupt -+ ystdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt -+ ystdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt -+#endif -+ -+#if 0 -+ /* Enable loopback */ -+ ystdm_setreg(wc, card, 8, 0x2); -+ ystdm_setreg(wc, card, 14, 0x0); -+ ystdm_setreg(wc, card, 64, 0x0); -+ ystdm_setreg(wc, card, 1, 0x08); -+#endif -+ if (ystdm_init_ring_generator_mode(wc, card)) { -+ return -1; -+ } -+ if(fxstxgain || fxsrxgain) { -+ r9 = ystdm_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; -+ } -+ ystdm_setreg(wc,card,9,r9); -+ } -+ -+ if(debug) -+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n",((ystdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((ystdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((ystdm_getreg(wc, card, 9)/2) == 1)?"3.5":((ystdm_getreg(wc,card,9)%2)?"-3.5":"0.0")); -+ -+ fxs->lasttxhook = fxs->idletxhookstate; -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+ -+ /* Analog Transmit Path Gain = 3.5dB; Analog Receive Path Gain = 3.5dB. */ -+ /* ystdm_setreg(wc, card, 9, 0x0a); */ -+ return 0; -+} -+ -+static int ystdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) -+{ -+ struct ystdm_stats stats; -+ struct ystdm_regs regs; -+ struct ystdm_regop regop; -+ struct ystdm_echo_coefs echoregs; -+ struct dahdi_hwgain hwgain; -+ struct ystdm *wc = chan->pvt; -+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; -+ 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; -+ fxs->ohttimer = x << 3; -+ -+ /* Active mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ if (fxs->neonringing) { -+ /* keep same Forward polarity */ -+ fxs->lasttxhook = SLIC_LF_OHTRAN_FWD; -+ printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", -+ chan->chanpos - 1); -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ } else if (fxs->lasttxhook == SLIC_LF_ACTIVE_FWD || -+ fxs->lasttxhook == SLIC_LF_ACTIVE_REV) { -+ /* Apply the change if appropriate */ -+ fxs->lasttxhook = POLARITY_XOR ? -+ SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; -+ printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", -+ chan->chanpos - 1); -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ } -+ break; -+ case DAHDI_SETPOLARITY: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (get_user(x, (__user int *) data)) -+ return -EFAULT; -+ /* Can't change polarity while ringing or when open */ -+ if ((fxs->lasttxhook == SLIC_LF_RINGING) || -+ (fxs->lasttxhook == SLIC_LF_OPEN)) -+ return -EINVAL; -+ -+ fxs->reversepolarity = x; -+ if (POLARITY_XOR) { -+ fxs->lasttxhook |= SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Reverse Polarity, card %d\n", -+ chan->chanpos - 1); -+ } -+ else { -+ fxs->lasttxhook &= ~SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Normal Polarity, card %d\n", -+ chan->chanpos - 1); -+ } -+ -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ break; -+ case DAHDI_VMWI_CONFIG: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (copy_from_user(&(fxs->vmwisetting), (__user void *) data, -+ sizeof(fxs->vmwisetting))) -+ return -EFAULT; -+ set_vmwi(wc, chan->chanpos - 1); -+ break; -+ case DAHDI_VMWI: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (get_user(x, (__user int *) data)) -+ return -EFAULT; -+ if (0 > x) -+ return -EFAULT; -+ fxs->vmwi_active_messages = x; -+ set_vmwi(wc, chan->chanpos - 1); -+ break; -+ case WCTDM_GET_STATS: -+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ stats.tipvolt = ystdm_getreg(wc, chan->chanpos - 1, 80) * -376; -+ stats.ringvolt = ystdm_getreg(wc, chan->chanpos - 1, 81) * -376; -+ stats.batvolt = ystdm_getreg(wc, chan->chanpos - 1, 82) * -376; -+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { -+ stats.tipvolt = (signed char)ystdm_getreg(wc, chan->chanpos - 1, 29) * 1000; -+ stats.ringvolt = (signed char)ystdm_getreg(wc, chan->chanpos - 1, 29) * 1000; -+ stats.batvolt = (signed char)ystdm_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] = ystdm_proslic_getreg_indirect(wc, chan->chanpos -1, x); -+ for (x=0;x<NUM_REGS;x++) -+ regs.direct[x] = ystdm_getreg(wc, chan->chanpos - 1, x); -+ } else { -+ memset(®s, 0, sizeof(regs)); -+ for (x=0;x<NUM_FXO_REGS;x++) -+ regs.direct[x] = ystdm_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("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); -+ ystdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); -+ } else { -+ regop.val &= 0xff; -+ printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); -+ ystdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); -+ } -+ break; -+ case WCTDM_SET_ECHOTUNE: -+ printk("-- 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 */ -+ ystdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim); -+ -+ /* Set the digital echo canceller registers */ -+ ystdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1); -+ ystdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2); -+ ystdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3); -+ ystdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4); -+ ystdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5); -+ ystdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6); -+ ystdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7); -+ ystdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8); -+ -+ printk("-- 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; -+ -+ ystdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx); -+ -+ if (debug) -+ printk("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 ystdm_open(struct dahdi_chan *chan) -+{ -+ struct ystdm *wc = chan->pvt; -+ if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) -+ return -ENODEV; -+ if (wc->dead) -+ return -ENODEV; -+ wc->usecount++; -+ return 0; -+} -+ -+static inline struct ystdm *ystdm_from_span(struct dahdi_span *span) -+{ -+ return container_of(span, struct ystdm, span); -+} -+ -+static int ystdm_watchdog(struct dahdi_span *span, int event) -+{ -+ printk("TDM: Restarting DMA\n"); -+ ystdm_restart_dma(ystdm_from_span(span)); -+ return 0; -+} -+ -+static int ystdm_close(struct dahdi_chan *chan) -+{ -+ struct ystdm *wc = chan->pvt; -+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; -+ wc->usecount--; -+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ int idlehookstate; -+ idlehookstate = POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ fxs->idletxhookstate = idlehookstate; -+ } -+ /* If we're dead, release us now */ -+ if (!wc->usecount && wc->dead) -+ ystdm_release(wc); -+ return 0; -+} -+ -+static int ystdm_init_ring_generator_mode(struct ystdm *wc, int card) -+{ -+ ystdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ -+ -+ /* neon trapezoid timers */ -+ ystdm_setreg(wc, card, 48, 0xe0); /* Active Timer low byte */ -+ ystdm_setreg(wc, card, 49, 0x01); /* Active Timer high byte */ -+ ystdm_setreg(wc, card, 50, 0xF0); /* Inactive Timer low byte */ -+ ystdm_setreg(wc, card, 51, 0x05); /* Inactive Timer high byte */ -+ -+ ystdm_set_ring_generator_mode(wc, card, 0); -+ -+ return 0; -+} -+ -+static int ystdm_set_ring_generator_mode(struct ystdm *wc, int card, int mode) -+{ -+ int reg20, reg21, reg74; /* RCO, RNGX, VBATH */ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ -+ fxs->neonringing = mode; /* track ring generator mode */ -+ -+ if (mode) { /* Neon */ -+ if (debug) -+ printk(KERN_DEBUG "NEON ring on chan %d, " -+ "lasttxhook was 0x%x\n", card, fxs->lasttxhook); -+ /* Must be in FORWARD ACTIVE before setting ringer */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+ -+ ystdm_proslic_setreg_indirect(wc, card, 22, -+ NEON_MWI_RNGY_PULSEWIDTH); -+ ystdm_proslic_setreg_indirect(wc, card, 21, -+ 0x7bef); /* RNGX (91.5Vpk) */ -+ ystdm_proslic_setreg_indirect(wc, card, 20, -+ 0x009f); /* RCO (RNGX, t rise)*/ -+ -+ ystdm_setreg(wc, card, 34, 0x19); /* Ringing Osc. Control */ -+ ystdm_setreg(wc, card, 74, 0x3f); /* VBATH 94.5V */ -+ ystdm_proslic_setreg_indirect(wc, card, 29, 0x4600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the VM led */ -+ } else { -+ ystdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ -+ /* RNGY Initial Phase */ -+ ystdm_proslic_setreg_indirect(wc, card, 22, 0x0000); -+ ystdm_proslic_setreg_indirect(wc, card, 29, 0x3600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the ringer */ -+ -+ if (fastringer) { -+ /* Speed up Ringer */ -+ reg20 = 0x7e6d; -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x0247; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Boosting fast ringer" -+ " on chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x014b; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Reducing fast ring " -+ "power on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: fast " -+ "ring_x power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x01b9; -+ if (debug) -+ printk(KERN_DEBUG "Speeding up ringer " -+ "on chan %d (25Hz)\n", -+ card); -+ } -+ /* VBATH */ -+ ystdm_setreg(wc, card, 74, reg74); -+ /*RCO*/ -+ ystdm_proslic_setreg_indirect(wc, card, 20, reg20); -+ /*RNGX*/ -+ ystdm_proslic_setreg_indirect(wc, card, 21, reg21); -+ -+ } else { -+ /* Ringer Speed */ -+ if (fxshonormode && fxo_modes[_opermode].ring_osc) { -+ reg20 = fxo_modes[_opermode].ring_osc; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: " -+ "ring_osc speed on chan %d\n", -+ card); -+ } else { -+ reg20 = 0x7ef0; /* Default */ -+ } -+ -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x1d1; -+ if (debug) -+ printk(KERN_DEBUG "Boosting ringer on " -+ "chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x108; -+ if (debug) -+ printk(KERN_DEBUG "Reducing ring power " -+ "on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: ring_x" -+ " power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x160; -+ if (debug) -+ printk(KERN_DEBUG "Normal ring power on" -+ " chan %d\n", -+ card); -+ } -+ /* VBATH */ -+ ystdm_setreg(wc, card, 74, reg74); -+ /* RCO */ -+ ystdm_proslic_setreg_indirect(wc, card, 20, reg20); -+ /* RNGX */ -+ ystdm_proslic_setreg_indirect(wc, card, 21, reg21); -+ } -+ } -+ return 0; -+} -+ -+static int ystdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) -+{ -+ struct ystdm *wc = chan->pvt; -+ int chan_entry = chan->chanpos - 1; -+ if (wc->modtype[chan_entry] == MOD_TYPE_FXO) { -+ /* XXX Enable hooksig for FXO XXX */ -+ switch(txsig) { -+ case DAHDI_TXSIG_START: -+ case DAHDI_TXSIG_OFFHOOK: -+ wc->mod[chan_entry].fxo.offhook = 1; -+ ystdm_setreg(wc, chan_entry, 5, 0x9); -+ break; -+ case DAHDI_TXSIG_ONHOOK: -+ wc->mod[chan_entry].fxo.offhook = 0; -+ ystdm_setreg(wc, chan_entry, 5, 0x8); -+ break; -+ default: -+ printk("wcfxo: Can't set tx state to %d\n", txsig); -+ } -+ } else { -+ ystdm_fxs_hooksig(wc, chan_entry, txsig); -+ } -+ return 0; -+} -+ -+static const struct dahdi_span_ops ystdm_span_ops = { -+ .owner = THIS_MODULE, -+ .hooksig = ystdm_hooksig, -+ .open = ystdm_open, -+ .close = ystdm_close, -+ .ioctl = ystdm_ioctl, -+ .watchdog = ystdm_watchdog, -+}; -+ -+static int ystdm_initialize(struct ystdm *wc) -+{ -+ int x; -+ -+ wc->ddev = dahdi_create_device(); -+ if (!wc->ddev) -+ return -ENOMEM; -+ -+ /* Zapata stuff */ -+ sprintf(wc->span.name, "WCTDM/%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 = "YEASTAR"; -+ wc->ddev->devicetype = wc->variety; -+ -+ if (alawoverride) { -+ printk("ALAW override parameter detected. Device will be operating in ALAW\n"); -+ wc->span.deflaw = DAHDI_LAW_ALAW; -+ } else { -+ wc->span.deflaw = DAHDI_LAW_MULAW; -+ } -+ for (x = 0; x < NUM_CARDS; x++) { -+ sprintf(wc->chans[x]->name, "WCTDM/%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; -+ } -+ -+ wc->span.chans = wc->chans; -+ wc->span.channels = NUM_CARDS; -+ wc->span.flags = DAHDI_FLAG_RBS; -+ wc->span.ops = &ystdm_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 span with DAHDI\n"); -+ kfree(wc->ddev->location); -+ dahdi_free_device(wc->ddev); -+ wc->ddev = NULL; -+ return -1; -+ } -+ return 0; -+} -+ -+static void ystdm_post_initialize(struct ystdm *wc) -+{ -+ int x; -+ /* Finalize signalling */ -+ for (x = 0; x < 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 ystdm_hardware_init(struct ystdm *wc) -+{ -+ /* Hardware stuff */ -+ unsigned char ver; -+ unsigned char x,y; -+ unsigned char ol = 0, sl = 0; -+ unsigned char ol2 = 0, sl2 = 0; -+ int failed; -+ -+ /* Signal Reset */ -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ -+ /* Check Freshmaker chip */ -+ x=inb(wc->ioaddr + WC_CNTL); -+ ver = __ystdm_getcreg(wc, WC_VER); -+ failed = 0; -+ if (ver != 0x59) { -+ printk("Freshmaker version: %02x\n", ver); -+ for (x=0;x<255;x++) { -+ /* Test registers */ -+ if (ver >= 0x70) { -+ __ystdm_setcreg(wc, WC_CS, x); -+ y = __ystdm_getcreg(wc, WC_CS); -+ } else { -+ __ystdm_setcreg(wc, WC_TEST, x); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ } -+ if (x != y) { -+ printk("%02x != %02x\n", x, y); -+ failed++; -+ } -+ } -+ if (!failed) { -+ printk("Freshmaker passed register test\n"); -+ } else { -+ printk("Freshmaker failed register test\n"); -+ return -1; -+ } -+ } else { -+ printk("No freshmaker chip\n"); -+ } -+ -+ /* 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 | BIT_SYNC; -+ -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ -+ /* Set all to outputs except AUX 5, which is an input */ -+ outb(0xdf, wc->ioaddr + WC_AUXC); -+ -+ /* 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); -+ -+ /* 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(0x0, wc->ioaddr + WC_FSCDELAY); -+ -+ /* Setup DMA Addresses */ -+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ -+ outl(wc->writedma + DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ -+ outl(wc->writedma + 2 * DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMAWE); /* End */ -+ -+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ -+ outl(wc->readdma + DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ -+ outl(wc->readdma + 2 * DAHDI_CHUNKSIZE * NUM_CARDS - 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 < NUM_CARDS; x++) { -+ int sane=0,ret=0,readi=0; -+#if 1 -+ /* Init with Auto Calibration */ -+ if (!(ret=ystdm_init_proslic(wc, x, 0, 0, sane))) { -+ wc->cardflag |= (1 << x); -+ if(x < 8) -+ sl |= (1 << x); -+ else -+ sl2 |= (1 << (x - 8)); -+ if (debug) { -+ readi = ystdm_getreg(wc,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x,((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- AUTO FXS/DPO\n",x); -+ } else { -+ if(ret!=-2) { -+ sane=1; -+ /* Init with Manual Calibration */ -+ if (!ystdm_init_proslic(wc, x, 0, 1, sane)) { -+ wc->cardflag |= (1 << x); -+ if(x < 8) -+ sl |= (1 << x); -+ else -+ sl2 |= (1 << (x - 8)); -+ if (debug) { -+ readi = ystdm_getreg(wc,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x,((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- MANUAL FXS\n",x); -+ } else { -+ printk("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 = ystdm_init_voicedaa(wc, x, 0, 0, sane))) { -+ wc->cardflag |= (1 << x); -+ if(x < 8) -+ ol |= (1 << x); -+ else -+ ol2 |= (1 << (x - 8)); -+ printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); -+ } else -+ printk("Module %d: Not installed\n", x); -+ } -+#endif -+ } -+ -+ /* Return error if nothing initialized okay. */ -+ if (!wc->cardflag && !timingonly) -+ return -1; -+ if(ver == 0x88) -+ __ystdm_setcreg(wc, WC_SYNC, wc->cardflag); -+ else{ -+ __ystdm_setcreg(wc, WC_SYNC, sl); -+ __ystdm_setcreg(wc, YS_SLC, ol); -+ __ystdm_setcreg(wc, YS_DCH, sl2); -+ __ystdm_setcreg(wc, YS_E0H, ol2); -+ } -+ return 0; -+} -+ -+static void ystdm_enable_interrupts(struct ystdm *wc) -+{ -+ /* Enable interrupts (we care about all of them) */ -+ outb(0x3f, wc->ioaddr + WC_MASK0); -+ /* No external interrupts */ -+ outb(0x00, wc->ioaddr + WC_MASK1); -+} -+ -+static void ystdm_restart_dma(struct ystdm *wc) -+{ -+ /* Reset Master and TDM */ -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ outb(0x01, wc->ioaddr + WC_OPER); -+} -+ -+static void ystdm_start_dma(struct ystdm *wc) -+{ -+ /* Reset Master and TDM */ -+ unsigned char x,y; -+ outb(0x0f, wc->ioaddr + WC_CNTL); -+ wc->ios &= ~BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(1); -+ wc->ios |= BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ outb(0x01, wc->ioaddr + WC_OPER); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ x = y | 0x01; -+ __ystdm_setcreg(wc, WC_TEST, x); -+} -+ -+static void ystdm_stop_dma(struct ystdm *wc) -+{ -+ unsigned char x,y; -+ wc->ios &= ~BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ outb(0x00, wc->ioaddr + WC_OPER); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ x = y & 0xFE; -+ __ystdm_setcreg(wc, WC_TEST, x); -+} -+ -+static void ystdm_reset_tdm(struct ystdm *wc) -+{ -+ /* Reset TDM */ -+ outb(0x0f, wc->ioaddr + WC_CNTL); -+} -+ -+static void ystdm_disable_interrupts(struct ystdm *wc) -+{ -+ outb(0x00, wc->ioaddr + WC_MASK0); -+ outb(0x00, wc->ioaddr + WC_MASK1); -+} -+ -+static int __devinit ystdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ struct ystdm *wc; -+ struct ystdm_desc *d = (struct ystdm_desc *)ent->driver_data; -+ int x; -+ int y; -+ -+ -+ -+ for (x=0;x<WC_MAX_IFACES;x++) -+ if (!ifaces[x]) break; -+ if (x >= WC_MAX_IFACES) { -+ printk("Too many interfaces\n"); -+ return -EIO; -+ } -+ -+ if (pci_enable_device(pdev)) { -+ res = -EIO; -+ } else { -+ wc = kmalloc(sizeof(struct ystdm), GFP_KERNEL); -+ if (wc) { -+ int cardcount = 0; -+ -+ ifaces[x] = wc; -+ memset(wc, 0, sizeof(struct ystdm)); -+ 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->dev = pdev; -+ wc->pos = x; -+ wc->variety = d->name; -+ for (y=0;y<NUM_CARDS;y++) -+ wc->flags[y] = d->flags; -+ /* Keep track of whether we need to free the region */ -+ if (request_region(wc->ioaddr, 0xff, "ystdm")) -+ wc->freeregion = 1; -+ -+ /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses -+ 32 bits. Allocate an extra set just for control too */ -+ wc->writechunk = pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, &wc->writedma); -+ if (!wc->writechunk) { -+ printk("ystdm: Unable to allocate DMA-able memory\n"); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ return -ENOMEM; -+ } -+ -+ wc->readchunk = wc->writechunk + 2 * DAHDI_MAX_CHUNKSIZE * (NUM_CARDS / 4); /* in doublewords */ -+ wc->readdma = wc->writedma + 2 * DAHDI_MAX_CHUNKSIZE * (NUM_CARDS / 1); /* in bytes */ -+ -+ if (ystdm_initialize(wc)) { -+ printk("ystdm: 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) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ kfree(wc); -+ return -EIO; -+ } -+ -+ /* Enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Keep track of which device we are */ -+ pci_set_drvdata(pdev, wc); -+ -+ if (request_irq(pdev->irq, ystdm_interrupt, DAHDI_IRQ_SHARED, "ystdm", wc)) { -+ printk("ystdm: Unable to request IRQ %d\n", pdev->irq); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ pci_set_drvdata(pdev, NULL); -+ kfree(wc); -+ return -EIO; -+ } -+ -+ -+ if (ystdm_hardware_init(wc)) { -+ unsigned char x; -+ -+ /* 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) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (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; -+ -+ } -+ -+ ystdm_post_initialize(wc); -+ -+ /* Enable interrupts */ -+ ystdm_enable_interrupts(wc); -+ /* Initialize Write/Buffers to all blank data */ -+ memset((void *)wc->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * NUM_CARDS); -+ -+ /* Start DMA */ -+ ystdm_start_dma(wc); -+ -+ for (x = 0; x < NUM_CARDS; x++) { -+ if (wc->cardflag & (1 << x)) -+ cardcount++; -+ } -+ -+ printk("Found a YSTDM16xx: %s (%d modules)\n", wc->variety, cardcount); -+ res = 0; -+ } else -+ res = -ENOMEM; -+ } -+ return res; -+} -+ -+static void ystdm_release(struct ystdm *wc) -+{ -+ dahdi_unregister_device(wc->ddev); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ kfree(wc->ddev->location); -+ dahdi_free_device(wc->ddev); -+ kfree(wc); -+ printk("Freed a Wildcard\n"); -+} -+ -+static void __devexit ystdm_remove_one(struct pci_dev *pdev) -+{ -+ struct ystdm *wc = pci_get_drvdata(pdev); -+ if (wc) { -+ -+ /* Stop any DMA */ -+ ystdm_stop_dma(wc); -+ ystdm_reset_tdm(wc); -+ -+ /* In case hardware is still there */ -+ ystdm_disable_interrupts(wc); -+ -+ /* Immediately free resources */ -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ free_irq(pdev->irq, wc); -+ -+ /* Reset PCI chip and registers */ -+ outb(0x0e, wc->ioaddr + WC_CNTL); -+ -+ /* Release span, possibly delayed */ -+ if (!wc->usecount) -+ ystdm_release(wc); -+ else -+ wc->dead = 1; -+ } -+} -+ -+static DEFINE_PCI_DEVICE_TABLE(ystdm_pci_tbl) = { -+ { 0xe159, 0x0001, 0x6151, PCI_ANY_ID, 0, 0, (unsigned long) &ystdme }, -+ { 0 } -+}; -+ -+MODULE_DEVICE_TABLE(pci, ystdm_pci_tbl); -+ -+static int ystdm_suspend(struct pci_dev *pdev, pm_message_t state) -+{ -+ return -ENOSYS; -+} -+ -+static struct pci_driver ystdm_driver = { -+ .name = "ystdm16xx", -+ .probe = ystdm_init_one, -+ .remove = __devexit_p(ystdm_remove_one), -+ .suspend = ystdm_suspend, -+ .id_table = ystdm_pci_tbl, -+}; -+ -+static int __init ystdm_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("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(" %s\n", fxo_modes[x].name); -+ printk("Note this option is CASE SENSITIVE!\n"); -+ return -ENODEV; -+ } -+ if (!strcmp(opermode, "AUSTRALIA")) { -+ boostringer = 1; -+ fxshonormode = 1; -+ } -+ -+ /* for the voicedaa_check_hook defaults, if the user has not overridden -+ them by specifying them as module parameters, then get the values -+ from the selected operating mode -+ */ -+ 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 = dahdi_pci_module(&ystdm_driver); -+ if (res) -+ return -ENODEV; -+ return 0; -+} -+ -+static void __exit ystdm_cleanup(void) -+{ -+ pci_unregister_driver(&ystdm_driver); -+} -+ -+module_param(debug, int, 0600); -+module_param(fxovoltage, 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(battalarm, uint, 0600); -+module_param(battthresh, 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(dtmf, int, 0600); -+ -+MODULE_DESCRIPTION("YSTDM16xx Yeastar Driver"); -+MODULE_AUTHOR("yeastar <support@yeastar.com>"); -+MODULE_ALIAS("ystdm16xx"); -+#ifdef MODULE_LICENSE -+MODULE_LICENSE("GPL v2"); -+#endif -+ -+module_init(ystdm_init); -+module_exit(ystdm_cleanup); -diff -Nur dahdi-linux-2.10.0.1/drivers/dahdi/ystdm8xx.c dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/ystdm8xx.c ---- dahdi-linux-2.10.0.1/drivers/dahdi/ystdm8xx.c 1970-01-01 01:00:00.000000000 +0100 -+++ dahdi-linux-2.10.0.1-yeastar/drivers/dahdi/ystdm8xx.c 2015-02-10 15:33:19.363713850 +0100 -@@ -0,0 +1,3065 @@ -+/* -+ * Yeastar YSTDM8xx TDM FXS/FXO Interface Driver for Zapata Telephony interface -+ * -+ * Derived from wctdm.c written by Mark Spencer <markster@linux-support.net> -+ * Matthew Fredrickson <creslin@linux-support.net> -+ * -+ * Copyright (C) 2006, Yeastar Technology Co.,Ltd. <support@yeastar.com> -+ * Copyright (C) 2001, Linux Support Services, Inc. -+ * -+ * All rights reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/errno.h> -+#include <linux/module.h> -+#include <linux/init.h> -+ -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+#include <linux/moduleparam.h> -+#include <linux/sched.h> -+#include <linux/ioctl.h> -+#include <asm/io.h> -+#include "proslic.h" -+/* -+ * 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; -+#define POLARITY_XOR (\ -+ (reversepolarity != 0) ^ (fxs->reversepolarity != 0) ^\ -+ (fxs->vmwi_lrev != 0) ^\ -+ ((fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) != 0)) -+ -+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",0x4000}, // playback volume set lower -+{27,14,"XMIT_DIGITAL_GAIN",0x3000}, -+//{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 "fxo_modes.h" -+ -+#define NUM_FXO_REGS 60 -+ -+#define WC_MAX_IFACES 128 -+ -+#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_SYNC 0x0 -+#define WC_TEST 0x1 -+#define WC_CS 0x2 -+#define WC_VER 0x3 -+#define YS_SLC 0x4 -+ -+#define BIT_SYNC (1 << 0) -+#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 -+ -+/* the constants below control the 'debounce' periods enforced by the -+ check_hook routines; these routines are called once every 4 interrupts -+ (the interrupt cycles around the four modules), so the periods are -+ specified in _4 millisecond_ increments -+*/ -+#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 */ -+ -+/* NEON MWI pulse width - Make larger for longer period time -+ * For more information on NEON MWI generation using the proslic -+ * refer to Silicon Labs App Note "AN33-SI321X NEON FLASHING" -+ * RNGY = RNGY 1/2 * Period * 8000 -+ */ -+#define NEON_MWI_RNGY_PULSEWIDTH 0x3e8 /*=> period of 250 mS */ -+ -+#define FLAG_3215 (1 << 0) -+ -+#define NUM_CARDS 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, -+}; -+ -+#define NUM_REGS 109 -+#define NUM_INDIRECT_REGS 105 -+ -+struct ystdm_stats { -+ int tipvolt; /* TIP voltage (mV) */ -+ int ringvolt; /* RING voltage (mV) */ -+ int batvolt; /* VBAT voltage (mV) */ -+}; -+ -+struct ystdm_regs { -+ unsigned char direct[NUM_REGS]; -+ unsigned short indirect[NUM_INDIRECT_REGS]; -+}; -+ -+struct ystdm_regop { -+ int indirect; -+ unsigned char reg; -+ unsigned short val; -+}; -+ -+struct ystdm_echo_coefs { -+ unsigned char acim; -+ unsigned char coef1; -+ unsigned char coef2; -+ unsigned char coef3; -+ unsigned char coef4; -+ unsigned char coef5; -+ unsigned char coef6; -+ unsigned char coef7; -+ unsigned char coef8; -+}; -+ -+#define WCTDM_GET_STATS _IOR (DAHDI_CODE, 60, struct ystdm_stats) -+#define WCTDM_GET_REGS _IOR (DAHDI_CODE, 61, struct ystdm_regs) -+#define WCTDM_SET_REG _IOW (DAHDI_CODE, 62, struct ystdm_regop) -+#define WCTDM_SET_ECHOTUNE _IOW (DAHDI_CODE, 63, struct ystdm_echo_coefs) -+ -+struct ystdm { -+ 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[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; -+ int readcid; -+ unsigned int cidtimer; -+ } fxo; -+ struct fxs { -+ int oldrxhook; -+ int debouncehook; -+ int lastrxhook; -+ int debounce; -+ int ohttimer; -+ int idletxhookstate; /* IDLE changing hook state */ -+ int lasttxhook; -+ int palarms; -+ int reversepolarity; /* Reverse Line */ -+ int mwisendtype; -+ struct dahdi_vmwi_info vmwisetting; -+ int vmwi_active_messages; -+ u32 vmwi_lrev:1; /* MWI Line Reversal*/ -+ u32 vmwi_hvdc:1; /* MWI High Voltage DC Idle line */ -+ u32 vmwi_hvac:1; /* MWI Neon High Voltage AC Idle line */ -+ u32 neonringing:1; /* Ring Generator is set for NEON */ -+ struct calregs calregs; -+ } fxs; -+ } mod[NUM_CARDS]; -+ -+ /* Receive hook state and debouncing */ -+ int modtype[NUM_CARDS]; -+ unsigned char reg0shadow[NUM_CARDS]; -+ unsigned char reg1shadow[NUM_CARDS]; -+ -+ 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[NUM_CARDS]; -+ struct dahdi_chan *chans[NUM_CARDS]; -+}; -+ -+ -+struct ystdm_desc { -+ char *name; -+ int flags; -+}; -+ -+static struct ystdm_desc ystdme = { "YSTDM8xx REV E", 0 }; -+static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; -+ -+static struct ystdm *ifaces[WC_MAX_IFACES]; -+ -+static void ystdm_release(struct ystdm *wc); -+ -+static unsigned int fxovoltage; -+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 dtmf = 0; -+static int fastpickup = 0; -+static int fxotxgain = 0; -+static int fxorxgain = 0; -+static int fxstxgain = 0; -+static int fxsrxgain = 0; -+ -+static int ystdm_init_proslic(struct ystdm *wc, int card, int fast , int manual, int sane); -+static int ystdm_init_ring_generator_mode(struct ystdm *wc, int card); -+static int ystdm_set_ring_generator_mode(struct ystdm *wc, int card, int mode); -+ -+static inline void ystdm_transmitprep(struct ystdm *wc, unsigned char ints) -+{ -+ volatile unsigned int *writechunk; -+ int x; -+ if (ints & 0x01) -+ /* Write is at interrupt address. Start writing from normal offset */ -+ writechunk = wc->writechunk; -+ else -+ writechunk = wc->writechunk + DAHDI_CHUNKSIZE * (NUM_CARDS / 4); -+ /* Calculate Transmission */ -+ dahdi_transmit(&wc->span); -+ -+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { -+ /* Send a sample, as a 32-bit word */ -+ writechunk[2 * x] = 0; -+ writechunk[2 * x + 1] = 0; -+#ifdef __BIG_ENDIAN -+ if (wc->cardflag & (1 << 7)) -+ writechunk[2 * x] |= (wc->chans[7]->writechunk[x]); -+ if (wc->cardflag & (1 << 6)) -+ writechunk[2 * x] |= (wc->chans[6]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 5)) -+ writechunk[2 * x] |= (wc->chans[5]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 4)) -+ writechunk[2 * x] |= (wc->chans[4]->writechunk[x] << 24); -+ -+ if (wc->cardflag & (1 << 3)) -+ writechunk[2 * x + 1] |= (wc->chans[3]->writechunk[x]); -+ if (wc->cardflag & (1 << 2)) -+ writechunk[2 * x + 1] |= (wc->chans[2]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 1)) -+ writechunk[2 * x + 1] |= (wc->chans[1]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 0)) -+ writechunk[2 * x + 1] |= (wc->chans[0]->writechunk[x] << 24); -+#else -+ if (wc->cardflag & (1 << 7)) -+ writechunk[2 * x] |= (wc->chans[7]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 6)) -+ writechunk[2 * x] |= (wc->chans[6]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 5)) -+ writechunk[2 * x] |= (wc->chans[5]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 4)) -+ writechunk[2 * x] |= (wc->chans[4]->writechunk[x]); -+ -+ if (wc->cardflag & (1 << 3)) -+ writechunk[2 * x + 1] |= (wc->chans[3]->writechunk[x] << 24); -+ if (wc->cardflag & (1 << 2)) -+ writechunk[2 * x + 1] |= (wc->chans[2]->writechunk[x] << 16); -+ if (wc->cardflag & (1 << 1)) -+ writechunk[2 * x + 1] |= (wc->chans[1]->writechunk[x] << 8); -+ if (wc->cardflag & (1 << 0)) -+ writechunk[2 * x + 1] |= (wc->chans[0]->writechunk[x]); -+#endif -+ } -+ -+} -+ -+#ifdef AUDIO_RINGCHECK -+static inline void ring_check(struct ystdm *wc, int card) -+{ -+ int x; -+ short sample; -+ if (wc->modtype[card] != MOD_TYPE_FXO) -+ return;< if (fxovoltage) { -+< static int count = 0; -+< if (!(count++ % 100)) { -+< printk(KERN_DEBUG "Card %d: Voltage: %d Debounce %d\n", card + 1, b, fxo->battdebounce); -+< } -+< } -+ -+ 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; -+ wc->mod[card].fxo.readcid = 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; -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ wc->mod[card].fxo.readcid = 0; -+ } -+ } -+} -+#endif -+static inline void ystdm_dtmfcheck_fakepolarity(struct ystdm *wc, int card, int x) -+{ -+ int sample; -+ /* only look for sound on the line if dtmf flag is on, it is an fxo card and line is onhook */ -+ if (!dtmf || !(wc->cardflag & (1 << card)) || !(wc->modtype[card] == MOD_TYPE_FXO) || wc->mod[card].fxo.offhook ) -+ return; -+ -+ /* don't look for noise if we're already processing it, or there is a ringing tone */ -+ if(!wc->mod[card].fxo.readcid && !wc->mod[card].fxo.wasringing && -+ wc->intcount > wc->mod[card].fxo.cidtimer + 400 ) { -+ sample = DAHDI_XLAW(wc->chans[card]->readchunk[x], (wc->chans[card])); -+ if (sample > 16000 || sample < -16000) { -+ wc->mod[card].fxo.readcid = 1; -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ if (debug) printk("DTMF CLIP on %i\n",card+1); -+ dahdi_qevent_lock(wc->chans[card], DAHDI_EVENT_POLARITY); -+ } -+ } else if(wc->mod[card].fxo.readcid && wc->intcount > wc->mod[card].fxo.cidtimer + 2000) { -+ /* reset flags if it's been a while */ -+ wc->mod[card].fxo.cidtimer = wc->intcount; -+ wc->mod[card].fxo.readcid = 0; -+ } -+} -+static inline void ystdm_receiveprep(struct ystdm *wc, unsigned char ints) -+{ -+ volatile unsigned int *readchunk; -+ int x; -+ -+ if (ints & 0x08) -+ readchunk = wc->readchunk + DAHDI_CHUNKSIZE * (NUM_CARDS / 4); -+ else -+ /* Read is at interrupt address. Valid data is available at normal offset */ -+ readchunk = wc->readchunk; -+ for (x=0;x<DAHDI_CHUNKSIZE;x++) { -+#ifdef __BIG_ENDIAN -+ if (wc->cardflag & (1 << 7)) -+ wc->chans[7]->readchunk[x] = (readchunk[2 * x + 1]) & 0xff; -+ if (wc->cardflag & (1 << 6)) -+ wc->chans[6]->readchunk[x] = (readchunk[2 * x + 1] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 5)) -+ wc->chans[5]->readchunk[x] = (readchunk[2 * x + 1] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 4)) -+ wc->chans[4]->readchunk[x] = (readchunk[2 * x + 1] >> 24) & 0xff; -+ -+ if (wc->cardflag & (1 << 3)) -+ wc->chans[3]->readchunk[x] = (readchunk[2 * x]) & 0xff; -+ if (wc->cardflag & (1 << 2)) -+ wc->chans[2]->readchunk[x] = (readchunk[2 * x] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 1)) -+ wc->chans[1]->readchunk[x] = (readchunk[2 * x] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 0)) -+ wc->chans[0]->readchunk[x] = (readchunk[2 * x] >> 24) & 0xff; -+#else -+ if (wc->cardflag & (1 << 7)) -+ wc->chans[7]->readchunk[x] = (readchunk[2 * x + 1] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 6)) -+ wc->chans[6]->readchunk[x] = (readchunk[2 * x + 1] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 5)) -+ wc->chans[5]->readchunk[x] = (readchunk[2 * x + 1] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 4)) -+ wc->chans[4]->readchunk[x] = (readchunk[2 * x + 1]) & 0xff; -+ -+ if (wc->cardflag & (1 << 3)) -+ wc->chans[3]->readchunk[x] = (readchunk[2 * x] >> 24) & 0xff; -+ if (wc->cardflag & (1 << 2)) -+ wc->chans[2]->readchunk[x] = (readchunk[2 * x] >> 16) & 0xff; -+ if (wc->cardflag & (1 << 1)) -+ wc->chans[1]->readchunk[x] = (readchunk[2 * x] >> 8) & 0xff; -+ if (wc->cardflag & (1 << 0)) -+ wc->chans[0]->readchunk[x] = (readchunk[2 * x]) & 0xff; -+#endif -+ -+ /*ystdm_dtmfcheck_fakepolarity(wc,0,x); -+ ystdm_dtmfcheck_fakepolarity(wc,1,x); -+ ystdm_dtmfcheck_fakepolarity(wc,2,x); -+ ystdm_dtmfcheck_fakepolarity(wc,3,x); -+ ystdm_dtmfcheck_fakepolarity(wc,4,x); -+ ystdm_dtmfcheck_fakepolarity(wc,5,x); -+ ystdm_dtmfcheck_fakepolarity(wc,6,x); -+ ystdm_dtmfcheck_fakepolarity(wc,7,x);*/ -+ } -+#ifdef AUDIO_RINGCHECK -+ for (x=0;x<wc->cards;x++) -+ ring_check(wc, x); -+#endif -+ /* XXX We're wasting 8 taps. We should get closer :( */ -+ for (x = 0; x < 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 ystdm_stop_dma(struct ystdm *wc); -+static void ystdm_reset_tdm(struct ystdm *wc); -+static void ystdm_restart_dma(struct ystdm *wc); -+ -+static inline void __write_8bits(struct ystdm *wc, unsigned char bits) -+{ -+/* Out BIT_CS --\________________________________/---- */ -+/* Out BIT_SCLK ---\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/------ */ -+/* Out BIT_SDI ---\___/---\___/---\___/---\___/-------- */ -+/* Data Bit 7 6 5 4 3 2 1 0 */ -+/* Data written 0 1 0 1 0 1 0 1 */ -+ -+ int x; -+ /* Drop chip select */ -+ 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); -+ -+} -+ -+static inline void __reset_spi(struct ystdm *wc) -+{ -+ /* 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); -+ -+} -+ -+static inline unsigned char __read_8bits(struct ystdm *wc) -+{ -+/* Out BIT_CS --\________________________________________/----*/ -+/* Out BIT_SCLK ---\_/--\_/--\_/--\_/--\_/--\_/--\_/--\_/-------*/ -+/* In BIT_SDO ????/1111\0000/1111\0000/1111\0000/1111\0000/???*/ -+/* Data bit 7 6 5 4 3 2 1 0 */ -+/* Data Read 1 0 1 0 1 0 1 0 */ -+ -+/* Note: Clock High time is 2x Low time, due to input read */ -+ -+ unsigned char res=0, c; -+ int x; -+ /* Drop chip select */ -+ wc->ios &= ~BIT_CS; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ for (x=0;x<8;x++) { -+ res <<= 1; -+ /* Drop SCLK */ -+ wc->ios &= ~BIT_SCLK; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ /* Now raise SCLK high again */ -+ 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; -+ } -+ /* Finally raise CS back high again */ -+ wc->ios |= BIT_CS; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ -+ /* And return our result */ -+ return res; -+} -+ -+static void __ystdm_setcreg(struct ystdm *wc, unsigned char reg, unsigned char val) -+{ -+ outb(val, wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); -+} -+ -+static unsigned char __ystdm_getcreg(struct ystdm *wc, unsigned char reg) -+{ -+ return inb(wc->ioaddr + WC_REGBASE + ((reg & 0xf) << 2)); -+} -+ -+static inline void __ystdm_setcard(struct ystdm *wc, int card) -+{ -+ if (wc->curcard != card) { -+ __ystdm_setcreg(wc, WC_CS, (1 << card)); -+ wc->curcard = card; -+ } -+} -+ -+static void __ystdm_setreg(struct ystdm *wc, int card, unsigned char reg, unsigned char value) -+{ -+ __ystdm_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 ystdm_setreg(struct ystdm *wc, int card, unsigned char reg, unsigned char value) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc->lock, flags); -+ __ystdm_setreg(wc, card, reg, value); -+ spin_unlock_irqrestore(&wc->lock, flags); -+} -+ -+static unsigned char __ystdm_getreg(struct ystdm *wc, int card, unsigned char reg) -+{ -+ __ystdm_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 ystdm *wc, int card) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&wc->lock, flags); -+ __ystdm_setcard(wc, card); -+ __reset_spi(wc); -+ __reset_spi(wc); -+ spin_unlock_irqrestore(&wc->lock, flags); -+} -+ -+static unsigned char ystdm_getreg(struct ystdm *wc, int card, unsigned char reg) -+{ -+ unsigned long flags; -+ unsigned char res; -+ spin_lock_irqsave(&wc->lock, flags); -+ res = __ystdm_getreg(wc, card, reg); -+ spin_unlock_irqrestore(&wc->lock, flags); -+ return res; -+} -+ -+static int __wait_access(struct ystdm *wc, int card) -+{ -+ unsigned char data = 0; -+ -+ int count = 0; -+ -+ #define MAX 6000 /* attempts */ -+ -+ -+ -+ /* Wait for indirect access */ -+ while (count++ < MAX) -+ { -+ data = __ystdm_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 ystdm_proslic_setreg_indirect(struct ystdm *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)) { -+ __ystdm_setreg(wc, card, IDA_LO,(unsigned char)(data & 0xFF)); -+ __ystdm_setreg(wc, card, IDA_HI,(unsigned char)((data & 0xFF00)>>8)); -+ __ystdm_setreg(wc, card, IAA,address); -+ res = 0; -+ }; -+ spin_unlock_irqrestore(&wc->lock, flags); -+ return res; -+} -+ -+static int ystdm_proslic_getreg_indirect(struct ystdm *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)) { -+ __ystdm_setreg(wc, card, IAA, address); -+ if (!__wait_access(wc, card)) { -+ unsigned char data1, data2; -+ data1 = __ystdm_getreg(wc, card, IDA_LO); -+ data2 = __ystdm_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 ystdm_proslic_init_indirect_regs(struct ystdm *wc, int card) -+{ -+ unsigned char i; -+ -+ for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) -+ { -+ if(ystdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int ystdm_proslic_verify_indirect_regs(struct ystdm *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 = ystdm_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 ystdm_proslic_recheck_sanity(struct ystdm *wc, int card) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ int res; -+ /* Check loopback */ -+ res = wc->reg1shadow[card]; -+ if (!res && (res != fxs->lasttxhook)) { -+ res = ystdm_getreg(wc, card, 8); -+ if (res) { -+ printk(KERN_NOTICE "Ouch, part reset, quickly restoring reality (%d)\n", card); -+ ystdm_init_proslic(wc, card, 1, 0, 1); -+ } else { -+ if (fxs->palarms++ < MAX_ALARMS) { -+ printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1); -+ if (fxs->lasttxhook == SLIC_LF_RINGING) -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ ystdm_setreg(wc, card, 64, fxs->lasttxhook); -+ } else { -+ if (fxs->palarms == MAX_ALARMS) -+ printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1); -+ } -+ } -+ } -+} -+ -+static inline void ystdm_voicedaa_check_hook(struct ystdm *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) -+ ystdm_setreg(wc, card, 5, 0x9); -+ } else { -+ if (b != 0x8) -+ ystdm_setreg(wc, card, 5, 0x8); -+ } -+ if (errors) -+ return; -+ if (!fxo->offhook) { -+ 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); -+ 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); -+ 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; -+ 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; -+ 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 (fxovoltage) { -+ static int count = 0; -+ if (!(count++ % 100)) { -+ printk(KERN_DEBUG "Card %d: Voltage: %d Debounce %d\n", card + 1, b, fxo->battdebounce); -+ } -+ } -+ -+ if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) { -+ /* -+ * dahdi-base will set DAHDI_RXSIG_INITIAL after a -+ * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events -+ * will be queued on the channel with the current received -+ * hook state. Channels that use robbed-bit signalling always -+ * report the current received state via the dahdi_rbsbits -+ * call. Since we only call dahdi_hooksig when we've detected -+ * a change to report, let's forget our current state in order -+ * to force us to report it again via dahdi_hooksig. -+ * -+ */ -+ fxo->battery = BATTERY_UNKNOWN; -+ } -+ -+if (DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig) { -+ /* If we've been set to the initial state, let's reset the -+ * battery state to unknown so that we will reset the -+ * current state of the battery and call dahdi_hooksig. */ -+ fxo->battery = BATTERY_UNKNOWN; -+ } /* add by David at 2009.09.10 */ -+ -+ -+ 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"); -+ dahdi_alarm_channel(&wc->chans[card], DAHDI_ALARM_RED); //add by david -+ -+#ifdef ZERO_BATT_RING -+ wc->onhook++; -+#endif -+ } -+#else -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); -+ dahdi_alarm_channel(wc->chans[card], DAHDI_ALARM_RED); //add by david -+ /* 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); -+ dahdi_alarm_channel(wc->chans[card], DAHDI_ALARM_NONE); //add by david -+ -+#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 void ystdm_fxs_hooksig(struct ystdm *wc, const int card, enum dahdi_txsig txsig) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ switch (txsig) { -+ case DAHDI_TXSIG_ONHOOK: -+ switch (wc->span.chans[card]->sig) { -+ case DAHDI_SIG_FXOKS: -+ case DAHDI_SIG_FXOLS: -+ /* Can't change Ring Generator during OHT */ -+ if (!fxs->ohttimer) { -+ ystdm_set_ring_generator_mode(wc, -+ card, fxs->vmwi_hvac); -+ fxs->lasttxhook = fxs->vmwi_hvac ? -+ SLIC_LF_RINGING : -+ fxs->idletxhookstate; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ break; -+ case DAHDI_SIG_EM: -+ fxs->lasttxhook = fxs->idletxhookstate; -+ break; -+ case DAHDI_SIG_FXOGS: -+ fxs->lasttxhook = SLIC_LF_TIP_OPEN; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_OFFHOOK: -+ switch (wc->span.chans[card]->sig) { -+ case DAHDI_SIG_EM: -+ fxs->lasttxhook = SLIC_LF_ACTIVE_REV; -+ break; -+ default: -+ fxs->lasttxhook = fxs->idletxhookstate; -+ break; -+ } -+ break; -+ case DAHDI_TXSIG_START: -+ /* Set ringer mode */ -+ ystdm_set_ring_generator_mode(wc, card, 0); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ break; -+ case DAHDI_TXSIG_KEWL: -+ fxs->lasttxhook = SLIC_LF_OPEN; -+ break; -+ default: -+ printk(KERN_NOTICE "ystdm: Can't set tx state to %d\n", txsig); -+ return; -+ } -+ if (debug) { -+ printk(KERN_DEBUG -+ "Setting FXS hook state to %d (%02x)\n", -+ txsig, fxs->lasttxhook); -+ } -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+} -+ -+ -+static inline void ystdm_proslic_check_hook(struct ystdm *wc, int card) -+{ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ char res; -+ int hook; -+ -+ /* For some reason we have to debounce the -+ hook detector. */ -+ -+ res = wc->reg0shadow[card]; -+ hook = (res & 1); -+ if (hook != fxs->lastrxhook) { -+ /* Reset the debounce (must be multiple of 4ms) */ -+ fxs->debounce = dialdebounce * 4; -+#if 0 -+ printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", -+ card, hook, fxs->debounce); -+#endif -+ } else { -+ if (fxs->debounce > 0) { -+ fxs->debounce -= 16 * DAHDI_CHUNKSIZE; -+#if 0 -+ printk(KERN_DEBUG "Sustaining hook %d, %d\n", -+ hook, fxs->debounce); -+#endif -+ if (!fxs->debounce) { -+#if 0 -+ printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook); -+#endif -+ fxs->debouncehook = hook; -+ } -+ if (!fxs->oldrxhook && fxs->debouncehook) { -+ /* Off hook */ -+#if 1 -+ if (debug) -+#endif -+ printk(KERN_DEBUG "ystdm: Card %d Going off hook\n", card); -+ -+ switch (fxs->lasttxhook) { -+ case SLIC_LF_RINGING: -+ case SLIC_LF_OHTRAN_FWD: -+ case SLIC_LF_OHTRAN_REV: -+ /* just detected OffHook, during -+ * Ringing or OnHookTransfer */ -+ fxs->idletxhookstate = -+ POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ break; -+ } -+ -+ ystdm_fxs_hooksig(wc, card, DAHDI_TXSIG_OFFHOOK); -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); -+ if (robust) -+ ystdm_init_proslic(wc, card, 1, 0, 1); -+ fxs->oldrxhook = 1; -+ -+ } else if (fxs->oldrxhook && !fxs->debouncehook) { -+ /* On hook */ -+#if 1 -+ if (debug) -+#endif -+ printk(KERN_DEBUG "ystdm: Card %d Going on hook\n", card); -+ ystdm_fxs_hooksig(wc, card, DAHDI_TXSIG_ONHOOK); -+ dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); -+ fxs->oldrxhook = 0; -+ } -+ } -+ } -+ fxs->lastrxhook = hook; -+} -+ -+DAHDI_IRQ_HANDLER(ystdm_interrupt) -+{ -+ struct ystdm *wc = dev_id; -+ unsigned char ints; -+ int x; -+ int mode; -+ -+ ints = inb(wc->ioaddr + WC_INTSTAT); -+ outb(ints, 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"); -+ ystdm_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<NUM_CARDS;x++) { -+ if (wc->cardflag & (1 << x) && -+ (wc->modtype[x] == MOD_TYPE_FXS)) { -+ struct fxs *const fxs = &wc->mod[x].fxs; -+ if (fxs->lasttxhook == SLIC_LF_RINGING && -+ !fxs->neonringing) { -+ /* RINGing, prepare for OHT */ -+ fxs->ohttimer = OHT_TIMER << 3; -+ -+ /* logical XOR 3 variables -+ module parameter 'reversepolarity', global reverse all FXS lines. -+ ioctl channel variable fxs 'reversepolarity', Line Reversal Alert Signal if required. -+ ioctl channel variable fxs 'vmwi_lrev', VMWI pending. -+ */ -+ -+ /* OHT mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR ? -+ SLIC_LF_OHTRAN_REV : -+ SLIC_LF_OHTRAN_FWD; -+ } else if (fxs->ohttimer) { -+ /* check if still OnHook */ -+ if (!fxs->oldrxhook) { -+ fxs->ohttimer -= DAHDI_CHUNKSIZE; -+ if (!fxs->ohttimer) { -+ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; /* Switch to Active, Rev or Fwd */ -+ /* if currently OHT */ -+ if ((fxs->lasttxhook == SLIC_LF_OHTRAN_FWD) || (fxs->lasttxhook == SLIC_LF_OHTRAN_REV)) { -+ if (fxs->vmwi_hvac) { -+ /* force idle polarity Forward if ringing */ -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ /* Set ring generator for neon */ -+ ystdm_set_ring_generator_mode(wc, x, 1); -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ } else { -+ fxs->lasttxhook = fxs->idletxhookstate; -+ } -+ /* Apply the change as appropriate */ -+ ystdm_setreg(wc, x, LINE_STATE, fxs->lasttxhook); -+ } -+ } -+ } else { -+ fxs->ohttimer = 0; -+ /* Switch to Active, Rev or Fwd */ -+ fxs->idletxhookstate = POLARITY_XOR ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ } -+ } -+ } -+ } -+ -+ if (ints & 0x0f) { -+ wc->intcount++; -+ x = wc->intcount & 0x7; -+ mode = wc->intcount & 0x18; -+ if (wc->cardflag & (1 << x)) { -+ switch(mode) { -+ case 0: -+ /* Rest */ -+ break; -+ case 8: -+ /* Read first shadow reg */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) -+ wc->reg0shadow[x] = ystdm_getreg(wc, x, 68); -+ else if (wc->modtype[x] == MOD_TYPE_FXO) -+ wc->reg0shadow[x] = ystdm_getreg(wc, x, 5); -+ break; -+ case 16: -+ /* Read second shadow reg */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) -+ wc->reg1shadow[x] = ystdm_getreg(wc, x, LINE_STATE); -+ else if (wc->modtype[x] == MOD_TYPE_FXO) -+ wc->reg1shadow[x] = ystdm_getreg(wc, x, 29); -+ break; -+ case 24: -+ /* Perform processing */ -+ if (wc->modtype[x] == MOD_TYPE_FXS) { -+ ystdm_proslic_check_hook(wc, x); -+ if (!(wc->intcount & 0xf0)) { -+ ystdm_proslic_recheck_sanity(wc, x); -+ } -+ } else if (wc->modtype[x] == MOD_TYPE_FXO) { -+ ystdm_voicedaa_check_hook(wc, x); -+ } -+ break; -+ } -+ } -+ if (!(wc->intcount % 10000)) { -+ /* Accept an alarm once per 10 seconds */ -+ for (x=0;x<NUM_CARDS;x++) -+ if (wc->modtype[x] == MOD_TYPE_FXS) { -+ if (wc->mod[x].fxs.palarms) -+ wc->mod[x].fxs.palarms--; -+ } -+ } -+ ystdm_receiveprep(wc, ints); -+ ystdm_transmitprep(wc, ints); -+ } -+ -+ return IRQ_RETVAL(1); -+ -+} -+ -+static int ystdm_voicedaa_insane(struct ystdm *wc, int card) -+{ -+ int blah; -+ blah = ystdm_getreg(wc, card, 2); -+ if (blah != 0x3) -+ return -2; -+ blah = ystdm_getreg(wc, card, 11); -+ if (debug) -+ printk(KERN_DEBUG "VoiceDAA System: %02x\n", blah & 0xf); -+ return 0; -+} -+ -+static int ystdm_proslic_insane(struct ystdm *wc, int card) -+{ -+ int blah,insane_report; -+ insane_report=0; -+ -+ blah = ystdm_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 ((blah & 0xf) == 2) { -+ /* ProSLIC 3215, not a 3210 */ -+ wc->flags[card] |= FLAG_3215; -+ } -+ blah = ystdm_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 = ystdm_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 = ystdm_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. */ -+ ystdm_setreg(wc, card, 30, 0); -+ -+ if (debug) -+ printk(KERN_DEBUG "ProSLIC on module %d seems sane.\n", card); -+ return 0; -+} -+ -+static int ystdm_proslic_powerleak_test(struct ystdm *wc, int card) -+{ -+ unsigned long origjiffies; -+ unsigned char vbat; -+ -+ /* Turn off linefeed */ -+ ystdm_setreg(wc, card, 64, 0); -+ -+ /* Power down */ -+ ystdm_setreg(wc, card, 14, 0x10); -+ -+ /* Wait for one second */ -+ origjiffies = jiffies; -+ -+ while((vbat = ystdm_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 ystdm_powerup_proslic(struct ystdm *wc, int card, int fast) -+{ -+ unsigned char vbat; -+ unsigned long origjiffies; -+ int lim; -+ -+ /* Set period of DC-DC converter to 1/64 khz */ -+ ystdm_setreg(wc, card, 92, 0xff /* was 0xff */); -+ -+ /* Wait for VBat to powerup */ -+ origjiffies = jiffies; -+ -+ /* Disable powerdown */ -+ ystdm_setreg(wc, card, 14, 0); -+ -+ /* If fast, don't bother checking anymore */ -+ if (fast) -+ return 0; -+ -+ while((vbat = ystdm_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 TDM400P??\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); -+ ystdm_setreg(wc,card,LOOP_I_LIMIT,lim); -+ -+ /* Engage DC-DC converter */ -+ ystdm_setreg(wc, card, 93, 0x19 /* was 0x19 */); -+#if 0 -+ origjiffies = jiffies; -+ while(0x80 & ystdm_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 = ystdm_getreg(wc, card, 82); -+ printk("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 ystdm_proslic_manual_calibrate(struct ystdm *wc, int card){ -+ unsigned long origjiffies; -+ unsigned char i; -+ -+ ystdm_setreg(wc, card, 21, 0);//(0) Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 22, 0);//(0)Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 23, 0);//(0)Disable all interupts in DR21 -+ ystdm_setreg(wc, card, 64, 0);//(0) -+ -+ ystdm_setreg(wc, card, 97, 0x18); //(0x18)Calibrations without the ADC and DAC offset and without common mode calibration. -+ ystdm_setreg(wc, card, 96, 0x47); //(0x47) Calibrate common mode and differential DAC mode DAC + ILIM -+ -+ origjiffies=jiffies; -+ while( ystdm_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); -+ ystdm_proslic_setreg_indirect(wc, card, 88,0); -+ ystdm_proslic_setreg_indirect(wc, card, 89,0); -+ ystdm_proslic_setreg_indirect(wc, card, 90,0); -+ ystdm_proslic_setreg_indirect(wc, card, 91,0); -+ ystdm_proslic_setreg_indirect(wc, card, 92,0); -+ ystdm_proslic_setreg_indirect(wc, card, 93,0); -+ -+ ystdm_setreg(wc, card, 98, 0x10); // This is necessary if the calibration occurs other than at reset time -+ ystdm_setreg(wc, card, 99, 0x10); -+ -+ for ( i=0x1f; i>0; i--) -+ { -+ ystdm_setreg(wc, card, 98, i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((ystdm_getreg(wc, card, 88)) == 0) -+ break; -+ } // for -+ -+ for ( i=0x1f; i>0; i--) -+ { -+ ystdm_setreg(wc, card, 99, i); -+ origjiffies=jiffies; -+ while((jiffies-origjiffies)<4); -+ if((ystdm_getreg(wc, card, 89)) == 0) -+ break; -+ }//for -+ -+/*******************************The preceding is the manual gain mismatch calibration****************************/ -+/**********************************The following is the longitudinal Balance Cal***********************************/ -+ ystdm_setreg(wc,card,64,1); -+ while((jiffies-origjiffies)<10); // Sleep 100? -+ -+ ystdm_setreg(wc, card, 64, 0); -+ ystdm_setreg(wc, card, 23, 0x4); // enable interrupt for the balance Cal -+ ystdm_setreg(wc, card, 97, 0x1); // this is a singular calibration bit for longitudinal calibration -+ ystdm_setreg(wc, card, 96, 0x40); -+ -+ ystdm_getreg(wc, card, 96); /* Read Reg 96 just cause */ -+ -+ ystdm_setreg(wc, card, 21, 0xFF); -+ ystdm_setreg(wc, card, 22, 0xFF); -+ ystdm_setreg(wc, card, 23, 0xFF); -+ -+ /**The preceding is the longitudinal Balance Cal***/ -+ return(0); -+ -+} -+#if 1 -+static int ystdm_proslic_calibrate(struct ystdm *wc, int card) -+{ -+ unsigned long origjiffies; -+ int x; -+ /* Perform all calibrations */ -+ ystdm_setreg(wc, card, 97, 0x1f); -+ -+ /* Begin, no speedup */ -+ ystdm_setreg(wc, card, 96, 0x5f); -+ -+ /* Wait for it to finish */ -+ origjiffies = jiffies; -+ while(ystdm_getreg(wc, card, 96)) { -+ if ((jiffies - origjiffies) > 2 * HZ) { -+ printk("Timeout waiting for calibration of module %d\n", card); -+ return -1; -+ } -+ } -+ -+ if (debug) { -+ /* Print calibration parameters */ -+ printk("Calibration Vector Regs 98 - 107: \n"); -+ for (x=98;x<108;x++) { -+ printk("%d: %02x\n", x, ystdm_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 ystdm_set_hwgain(struct ystdm *wc, int card, __s32 gain, __u32 tx) -+{ -+ if (!(wc->modtype[card] == MOD_TYPE_FXO)) { -+ printk("Cannot adjust gain. Unsupported module type!\n"); -+ return -1; -+ } -+ if (tx) { -+ if (debug) -+ printk("setting FXO tx gain for card=%d to %d\n", card, gain); -+ if (gain >= -150 && gain <= 0) { -+ ystdm_setreg(wc, card, 38, 16 + (gain/-10)); -+ ystdm_setreg(wc, card, 40, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ ystdm_setreg(wc, card, 38, gain/10); -+ ystdm_setreg(wc, card, 40, (gain%10)); -+ } else { -+ printk("FXO tx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } else { /* rx */ -+ if (debug) -+ printk("setting FXO rx gain for card=%d to %d\n", card, gain); -+ if (gain >= -150 && gain <= 0) { -+ ystdm_setreg(wc, card, 39, 16+ (gain/-10)); -+ ystdm_setreg(wc, card, 41, 16 + (-gain%10)); -+ } else if (gain <= 120 && gain > 0) { -+ ystdm_setreg(wc, card, 39, gain/10); -+ ystdm_setreg(wc, card, 41, (gain%10)); -+ } else { -+ printk("FXO rx gain is out of range (%d)\n", gain); -+ return -1; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int set_vmwi(struct ystdm * wc, int chan_idx) -+{ -+ struct fxs *const fxs = &wc->mod[chan_idx].fxs; -+ if (fxs->vmwi_active_messages) { -+ fxs->vmwi_lrev = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV) ? 1 : 0; -+ fxs->vmwi_hvdc = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVDC) ? 1 : 0; -+ fxs->vmwi_hvac = -+ (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) ? 1 : 0; -+ } else { -+ fxs->vmwi_lrev = 0; -+ fxs->vmwi_hvdc = 0; -+ fxs->vmwi_hvac = 0; -+ } -+ -+ if (debug) { -+ printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, " -+ "lrev=%d, hvdc=%d, hvac=%d\n", -+ chan_idx, -+ fxs->vmwi_active_messages, -+ fxs->vmwi_lrev, -+ fxs->vmwi_hvdc, -+ fxs->vmwi_hvac -+ ); -+ } -+ if (fxs->vmwi_hvac) { -+ /* Can't change ring generator while in On Hook Transfer mode*/ -+ if (!fxs->ohttimer) { -+ if (POLARITY_XOR) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ /* Set ring generator for neon */ -+ ystdm_set_ring_generator_mode(wc, chan_idx, 1); -+ /* Activate ring to send neon pulses */ -+ fxs->lasttxhook = SLIC_LF_RINGING; -+ ystdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ } else { -+ if (fxs->neonringing) { -+ /* Set ring generator for normal ringer */ -+ ystdm_set_ring_generator_mode(wc, chan_idx, 0); -+ /* ACTIVE, polarity determined later */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ } else if ((fxs->lasttxhook == SLIC_LF_RINGING) || -+ (fxs->lasttxhook == SLIC_LF_OPEN)) { -+ /* Can't change polarity while ringing or when open, -+ set idlehookstate instead */ -+ if (POLARITY_XOR) -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ else -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ -+ printk(KERN_DEBUG "Unable to change polarity on channel" -+ "%d, lasttxhook=0x%X\n", -+ chan_idx, -+ fxs->lasttxhook -+ ); -+ return 0; -+ } -+ if (POLARITY_XOR) { -+ fxs->idletxhookstate |= SLIC_LF_REVMASK; -+ fxs->lasttxhook |= SLIC_LF_REVMASK; -+ } else { -+ fxs->idletxhookstate &= ~SLIC_LF_REVMASK; -+ fxs->lasttxhook &= ~SLIC_LF_REVMASK; -+ } -+ ystdm_setreg(wc, chan_idx, LINE_STATE, fxs->lasttxhook); -+ } -+ return 0; -+} -+ -+static int ystdm_init_voicedaa(struct ystdm *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 && ystdm_voicedaa_insane(wc, card)) -+ return -2; -+ -+ /* Software reset */ -+ ystdm_setreg(wc, card, 1, 0x80); -+ -+ /* Wait just a bit */ -+ wait_just_a_bit(HZ/10); -+ -+ /* Enable PCM, ulaw */ -+ if (alawoverride){ -+ ystdm_setreg(wc, card, 33, 0x20); -+ } else { -+ ystdm_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); -+ ystdm_setreg(wc, card, 16, reg16); -+ -+ if(fwringdetect) { -+ /* Enable ring detector full-wave rectifier mode */ -+ ystdm_setreg(wc, card, 18, 2); -+ ystdm_setreg(wc, card, 24, 0); -+ } else { -+ /* Set to the device defaults */ -+ ystdm_setreg(wc, card, 18, 0); -+ ystdm_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); -+ ystdm_setreg(wc, card, 26, reg26); -+ -+ /* Set AC Impedence */ -+ reg30 = (fxo_modes[_opermode].acim); -+ ystdm_setreg(wc, card, 30, reg30); -+ -+ /* Misc. DAA parameters */ -+ if (fastpickup) -+ reg31 = 0xe3; -+ else -+ reg31 = 0xa3; -+ -+ reg31 |= (fxo_modes[_opermode].ohs2 << 3); -+ ystdm_setreg(wc, card, 31, reg31); -+ -+ /* Set Transmit/Receive timeslot */ -+ if (card < NUM_CARDS/2) { -+ ystdm_setreg(wc, card, 34, (3-card) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (3-card) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } else { -+ ystdm_setreg(wc, card, 34, (3-(card-NUM_CARDS/2)+16) * 8); -+ ystdm_setreg(wc, card, 35, 0x00); -+ ystdm_setreg(wc, card, 36, (3-(card-NUM_CARDS/2)+16) * 8); -+ ystdm_setreg(wc, card, 37, 0x00); -+ } -+ -+ /* Enable ISO-Cap */ -+ ystdm_setreg(wc, card, 6, 0x00); -+ if (fastpickup) -+ ystdm_setreg(wc, card, 17, ystdm_getreg(wc, card, 17) | 0x20); -+ -+ /* Wait 1000ms for ISO-cap to come up */ -+ newjiffies = jiffies; -+ newjiffies += 2 * HZ; -+ while((jiffies < newjiffies) && !(ystdm_getreg(wc, card, 11) & 0xf0)) -+ wait_just_a_bit(HZ/10); -+ -+ if (!(ystdm_getreg(wc, card, 11) & 0xf0)) { -+ printk("VoiceDAA did not bring up ISO link properly!\n"); -+ return -1; -+ } -+ if (debug) -+ printk("ISO-Cap is now up, line side: %02x rev %02x\n", -+ ystdm_getreg(wc, card, 11) >> 4, -+ (ystdm_getreg(wc, card, 13) >> 2) & 0xf); -+ /* Enable on-hook line monitor */ -+ ystdm_setreg(wc, card, 5, 0x08); -+ /* Take values for fxotxgain and fxorxgain and apply them to module */ -+ if (fxotxgain) -+ ystdm_set_hwgain(wc, card, fxotxgain, 1); -+ else -+ ystdm_set_hwgain(wc, card, 0, 1); -+ if (fxorxgain) -+ ystdm_set_hwgain(wc, card, fxorxgain, 0); -+ else -+ ystdm_set_hwgain(wc, card, 20, 0); -+ -+ /* NZ -- crank the tx gain up by 7 dB */ -+ if (!strcmp(fxo_modes[_opermode].name, "NEWZEALAND")) { -+ printk("Adjusting gain\n"); -+ ystdm_set_hwgain(wc, card, 7, 1); -+ -+ } -+ /* KR -- crank the rv gain up by 9 dB */ -+ if (!strcmp(fxo_modes[_opermode].name, "SOUTHKOREA")) { -+ printk("Adjusting gain\n"); -+ ystdm_setreg(wc, card, 39, 0x9); -+ } -+ if(debug) -+ printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (ystdm_getreg(wc, card, 38)/16)?-(ystdm_getreg(wc, card, 38) - 16) : ystdm_getreg(wc, card, 38), (ystdm_getreg(wc, card, 40)/16)? -(ystdm_getreg(wc, card, 40) - 16):ystdm_getreg(wc, card, 40), (ystdm_getreg(wc, card, 39)/16)? -(ystdm_getreg(wc, card, 39) - 16) : ystdm_getreg(wc, card, 39),(ystdm_getreg(wc, card, 41)/16)?-(ystdm_getreg(wc, card, 41) - 16):ystdm_getreg(wc, card, 41)); -+ -+ return 0; -+ -+} -+ -+static int ystdm_init_proslic(struct ystdm *wc, int card, int fast, int manual, int sane) -+{ -+ -+ unsigned short tmp[5]; -+ unsigned char r19,r9; -+ int x; -+ int fxsmode=0; -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ -+ /* Sanity check the ProSLIC */ -+ if (!sane && ystdm_proslic_insane(wc, card)) -+ return -2; -+ -+ /* default messages to none and method to FSK */ -+ memset(&fxs->vmwisetting, 0, sizeof(fxs->vmwisetting)); -+ fxs->vmwi_lrev = 0; -+ fxs->vmwi_hvdc = 0; -+ fxs->vmwi_hvac = 0; -+ -+ /* By default, don't send on hook */ -+ if (!reversepolarity != !fxs->reversepolarity) -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_REV; -+ else -+ fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; -+ -+ /* Sanity check the ProSLIC */ -+ //if (!sane && ystdm_proslic_insane(wc, card)) -+ // return -2; -+ -+ if (sane) { -+ /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ -+ ystdm_setreg(wc, card, 14, 0x10); -+ } -+ -+ if (ystdm_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 */ -+ ystdm_proslic_setreg_indirect(wc, card, 97,0); -+ -+ /* Clear digital loopback */ -+ ystdm_setreg(wc, card, 8, 0); -+ -+ /* Revision C optimization */ -+ ystdm_setreg(wc, card, 108, 0xeb); -+ -+ /* Disable automatic VBat switching for safety to prevent -+ Q7 from accidently turning on and burning out. */ -+ ystdm_setreg(wc, card, 67, 0x07); -+ -+ /* Turn off Q7 */ -+ ystdm_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] = ystdm_proslic_getreg_indirect(wc, card, x + 35); -+ ystdm_proslic_setreg_indirect(wc, card, x + 35, 0x8000); -+ } -+ -+ /* Power up the DC-DC converter */ -+ if (ystdm_powerup_proslic(wc, card, fast)) { -+ printk("Unable to do INITIAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+ -+ if (!fast) { -+ -+ /* Check for power leaks */ -+ if (ystdm_proslic_powerleak_test(wc, card)) { -+ printk("ProSLIC module %d failed leakage test. Check for short circuit\n", card); -+ } -+ /* Power up again */ -+ if (ystdm_powerup_proslic(wc, card, fast)) { -+ printk("Unable to do FINAL ProSLIC powerup on module %d\n", card); -+ return -1; -+ } -+#ifndef NO_CALIBRATION -+ /* Perform calibration */ -+ if(manual) { -+ if (ystdm_proslic_manual_calibrate(wc, card)) { -+ //printk("Proslic failed on Manual Calibration\n"); -+ if (ystdm_proslic_manual_calibrate(wc, card)) { -+ printk("Proslic Failed on Second Attempt to Calibrate Manually. (Try -DNO_CALIBRATION in Makefile)\n"); -+ return -1; -+ } -+ printk("Proslic Passed Manual Calibration on Second Attempt\n"); -+ } -+ } -+ else { -+ if(ystdm_proslic_calibrate(wc, card)) { -+ //printk("ProSlic died on Auto Calibration.\n"); -+ if (ystdm_proslic_calibrate(wc, card)) { -+ printk("Proslic Failed on Second Attempt to Auto Calibrate\n"); -+ return -1; -+ } -+ printk("Proslic Passed Auto Calibration on Second Attempt\n"); -+ } -+ } -+ /* Perform DC-DC calibration */ -+ ystdm_setreg(wc, card, 93, 0x99); -+ r19 = ystdm_getreg(wc, card, 107); -+ if ((r19 < 0x2) || (r19 > 0xd)) { -+ printk("DC-DC cal has a surprising direct 107 of 0x%02x!\n", r19); -+ ystdm_setreg(wc, card, 107, 0x8); -+ } -+ -+ /* Save calibration vectors */ -+ for (x=0;x<NUM_CAL_REGS;x++) -+ fxs->calregs.vals[x] = ystdm_getreg(wc, card, 96 + x); -+#endif -+ -+ } else { -+ /* Restore calibration registers */ -+ for (x=0;x<NUM_CAL_REGS;x++) -+ ystdm_setreg(wc, card, 96 + x, fxs->calregs.vals[x]); -+ } -+ /* Calibration complete, restore original values */ -+ for (x=0;x<5;x++) { -+ ystdm_proslic_setreg_indirect(wc, card, x + 35, tmp[x]); -+ } -+ -+ if (ystdm_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" */ -+ ystdm_setreg(wc, card, 67, 0x0e); -+ blah = ystdm_getreg(wc, card, 67); -+#endif -+ -+#if 0 -+ if (ystdm_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) -+ ystdm_setreg(wc, card, 1, 0x20); -+ else -+ ystdm_setreg(wc, card, 1, 0x28); -+ // U-Law 8-bit interface -+ if (card < NUM_CARDS/2) { -+ ystdm_setreg(wc, card, 2, (3-card) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (3-card) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } else { -+ ystdm_setreg(wc, card, 2, (3-(card-NUM_CARDS/2)+16) * 8); // Tx Start count low byte 0 -+ ystdm_setreg(wc, card, 3, 0); // Tx Start count high byte 0 -+ ystdm_setreg(wc, card, 4, (3-(card-NUM_CARDS/2)+16) * 8); // Rx Start count low byte 0 -+ ystdm_setreg(wc, card, 5, 0); // Rx Start count high byte 0 -+ } -+ ystdm_setreg(wc, card, 18, 0xff); // clear all interrupt -+ ystdm_setreg(wc, card, 19, 0xff); -+ ystdm_setreg(wc, card, 20, 0xff); -+ ystdm_setreg(wc, card, 73, 0x04); -+ if (fxshonormode) { -+ fxsmode = acim2tiss[fxo_modes[_opermode].acim]; -+ ystdm_setreg(wc, card, 10, 0x08 | fxsmode); -+ } -+ if (lowpower) -+ ystdm_setreg(wc, card, 72, 0x10); -+ -+#if 0 -+ ystdm_setreg(wc, card, 21, 0x00); // enable interrupt -+ ystdm_setreg(wc, card, 22, 0x02); // Loop detection interrupt -+ ystdm_setreg(wc, card, 23, 0x01); // DTMF detection interrupt -+#endif -+ -+#if 0 -+ /* Enable loopback */ -+ ystdm_setreg(wc, card, 8, 0x2); -+ ystdm_setreg(wc, card, 14, 0x0); -+ ystdm_setreg(wc, card, 64, 0x0); -+ ystdm_setreg(wc, card, 1, 0x08); -+#endif -+ if (ystdm_init_ring_generator_mode(wc, card)) { -+ return -1; -+ } -+ -+ if(fxstxgain || fxsrxgain) { -+ r9 = ystdm_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; -+ } -+ ystdm_setreg(wc,card,9,r9); -+ } -+ -+ if(debug) -+ printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n",((ystdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((ystdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((ystdm_getreg(wc, card, 9)/2) == 1)?"3.5":((ystdm_getreg(wc,card,9)%2)?"-3.5":"0.0")); -+ -+ fxs->lasttxhook = fxs->idletxhookstate; -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+ -+ /* Analog Transmit Path Gain = 3.5dB; Analog Receive Path Gain = 3.5dB. */ -+ /* ystdm_setreg(wc, card, 9, 0x0a); */ -+ return 0; -+} -+ -+static int ystdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data) -+{ -+ struct ystdm_stats stats; -+ struct ystdm_regs regs; -+ struct ystdm_regop regop; -+ struct ystdm_echo_coefs echoregs; -+ struct dahdi_hwgain hwgain; -+ struct ystdm *wc = chan->pvt; -+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; -+ 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; -+ fxs->ohttimer = x << 3; -+ -+ /* Active mode when idle */ -+ fxs->idletxhookstate = POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; -+ if (fxs->neonringing) { -+ /* keep same Forward polarity */ -+ fxs->lasttxhook = SLIC_LF_OHTRAN_FWD; -+ printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", -+ chan->chanpos - 1); -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ } else if (fxs->lasttxhook == SLIC_LF_ACTIVE_FWD || -+ fxs->lasttxhook == SLIC_LF_ACTIVE_REV) { -+ /* Apply the change if appropriate */ -+ fxs->lasttxhook = POLARITY_XOR ? -+ SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD; -+ printk(KERN_INFO "ioctl: Start OnHookTrans, card %d\n", -+ chan->chanpos - 1); -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ } -+ break; -+ case DAHDI_SETPOLARITY: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (get_user(x, (__user int *) data)) -+ return -EFAULT; -+ /* Can't change polarity while ringing or when open */ -+ if ((fxs->lasttxhook == SLIC_LF_RINGING) || -+ (fxs->lasttxhook == SLIC_LF_OPEN)) -+ return -EINVAL; -+ -+ fxs->reversepolarity = x; -+ if (POLARITY_XOR) { -+ fxs->lasttxhook |= SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Reverse Polarity, card %d\n", -+ chan->chanpos - 1); -+ } -+ else { -+ fxs->lasttxhook &= ~SLIC_LF_REVMASK; -+ printk(KERN_INFO "ioctl: Normal Polarity, card %d\n", -+ chan->chanpos - 1); -+ } -+ -+ ystdm_setreg(wc, chan->chanpos - 1, -+ LINE_STATE, fxs->lasttxhook); -+ break; -+ case DAHDI_VMWI_CONFIG: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (copy_from_user(&(fxs->vmwisetting), (__user void *) data, -+ sizeof(fxs->vmwisetting))) -+ return -EFAULT; -+ set_vmwi(wc, chan->chanpos - 1); -+ break; -+ case DAHDI_VMWI: -+ if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) -+ return -EINVAL; -+ if (get_user(x, (__user int *) data)) -+ return -EFAULT; -+ if (0 > x) -+ return -EFAULT; -+ fxs->vmwi_active_messages = x; -+ set_vmwi(wc, chan->chanpos - 1); -+ break; -+ case WCTDM_GET_STATS: -+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ stats.tipvolt = ystdm_getreg(wc, chan->chanpos - 1, 80) * -376; -+ stats.ringvolt = ystdm_getreg(wc, chan->chanpos - 1, 81) * -376; -+ stats.batvolt = ystdm_getreg(wc, chan->chanpos - 1, 82) * -376; -+ } else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { -+ stats.tipvolt = (signed char)ystdm_getreg(wc, chan->chanpos - 1, 29) * 1000; -+ stats.ringvolt = (signed char)ystdm_getreg(wc, chan->chanpos - 1, 29) * 1000; -+ stats.batvolt = (signed char)ystdm_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] = ystdm_proslic_getreg_indirect(wc, chan->chanpos -1, x); -+ for (x=0;x<NUM_REGS;x++) -+ regs.direct[x] = ystdm_getreg(wc, chan->chanpos - 1, x); -+ } else { -+ memset(®s, 0, sizeof(regs)); -+ for (x=0;x<NUM_FXO_REGS;x++) -+ regs.direct[x] = ystdm_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("Setting indirect %d to 0x%04x on %d\n", regop.reg, regop.val, chan->chanpos); -+ ystdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); -+ } else { -+ regop.val &= 0xff; -+ printk("Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); -+ ystdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); -+ } -+ break; -+ case WCTDM_SET_ECHOTUNE: -+ printk("-- 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 */ -+ ystdm_setreg(wc, chan->chanpos - 1, 30, echoregs.acim); -+ -+ /* Set the digital echo canceller registers */ -+ ystdm_setreg(wc, chan->chanpos - 1, 45, echoregs.coef1); -+ ystdm_setreg(wc, chan->chanpos - 1, 46, echoregs.coef2); -+ ystdm_setreg(wc, chan->chanpos - 1, 47, echoregs.coef3); -+ ystdm_setreg(wc, chan->chanpos - 1, 48, echoregs.coef4); -+ ystdm_setreg(wc, chan->chanpos - 1, 49, echoregs.coef5); -+ ystdm_setreg(wc, chan->chanpos - 1, 50, echoregs.coef6); -+ ystdm_setreg(wc, chan->chanpos - 1, 51, echoregs.coef7); -+ ystdm_setreg(wc, chan->chanpos - 1, 52, echoregs.coef8); -+ -+ printk("-- 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; -+ -+ ystdm_set_hwgain(wc, chan->chanpos-1, hwgain.newgain, hwgain.tx); -+ -+ if (debug) -+ printk("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 ystdm_open(struct dahdi_chan *chan) -+{ -+ struct ystdm *wc = chan->pvt; -+ if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) -+ return -ENODEV; -+ if (wc->dead) -+ return -ENODEV; -+ wc->usecount++; -+ return 0; -+} -+ -+static inline struct ystdm *ystdm_from_span(struct dahdi_span *span) -+{ -+ return container_of(span, struct ystdm, span); -+} -+ -+static int ystdm_watchdog(struct dahdi_span *span, int event) -+{ -+ printk("TDM: Restarting DMA\n"); -+ ystdm_restart_dma(ystdm_from_span(span)); -+ return 0; -+} -+ -+static int ystdm_close(struct dahdi_chan *chan) -+{ -+ struct ystdm *wc = chan->pvt; -+ struct fxs *const fxs = &wc->mod[chan->chanpos - 1].fxs; -+ wc->usecount--; -+ if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXS) { -+ int idlehookstate; -+ idlehookstate = POLARITY_XOR ? -+ SLIC_LF_ACTIVE_REV : -+ SLIC_LF_ACTIVE_FWD; -+ fxs->idletxhookstate = idlehookstate; -+ } -+ /* If we're dead, release us now */ -+ if (!wc->usecount && wc->dead) -+ ystdm_release(wc); -+ return 0; -+} -+ -+static int ystdm_init_ring_generator_mode(struct ystdm *wc, int card) -+{ -+ ystdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ -+ -+ /* neon trapezoid timers */ -+ ystdm_setreg(wc, card, 48, 0xe0); /* Active Timer low byte */ -+ ystdm_setreg(wc, card, 49, 0x01); /* Active Timer high byte */ -+ ystdm_setreg(wc, card, 50, 0xF0); /* Inactive Timer low byte */ -+ ystdm_setreg(wc, card, 51, 0x05); /* Inactive Timer high byte */ -+ -+ ystdm_set_ring_generator_mode(wc, card, 0); -+ -+ return 0; -+} -+ -+static int ystdm_set_ring_generator_mode(struct ystdm *wc, int card, int mode) -+{ -+ int reg20, reg21, reg74; /* RCO, RNGX, VBATH */ -+ struct fxs *const fxs = &wc->mod[card].fxs; -+ -+ fxs->neonringing = mode; /* track ring generator mode */ -+ -+ if (mode) { /* Neon */ -+ if (debug) -+ printk(KERN_DEBUG "NEON ring on chan %d, " -+ "lasttxhook was 0x%x\n", card, fxs->lasttxhook); -+ /* Must be in FORWARD ACTIVE before setting ringer */ -+ fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; -+ ystdm_setreg(wc, card, LINE_STATE, fxs->lasttxhook); -+ -+ ystdm_proslic_setreg_indirect(wc, card, 22, -+ NEON_MWI_RNGY_PULSEWIDTH); -+ ystdm_proslic_setreg_indirect(wc, card, 21, -+ 0x7bef); /* RNGX (91.5Vpk) */ -+ ystdm_proslic_setreg_indirect(wc, card, 20, -+ 0x009f); /* RCO (RNGX, t rise)*/ -+ -+ ystdm_setreg(wc, card, 34, 0x19); /* Ringing Osc. Control */ -+ ystdm_setreg(wc, card, 74, 0x3f); /* VBATH 94.5V */ -+ ystdm_proslic_setreg_indirect(wc, card, 29, 0x4600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the VM led */ -+ } else { -+ ystdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ -+ /* RNGY Initial Phase */ -+ ystdm_proslic_setreg_indirect(wc, card, 22, 0x0000); -+ ystdm_proslic_setreg_indirect(wc, card, 29, 0x3600); /* RPTP */ -+ /* A write of 0x04 to register 64 will turn on the ringer */ -+ -+ if (fastringer) { -+ /* Speed up Ringer */ -+ reg20 = 0x7e6d; -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x0247; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Boosting fast ringer" -+ " on chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x014b; /* RNGX */ -+ if (debug) -+ printk(KERN_DEBUG "Reducing fast ring " -+ "power on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: fast " -+ "ring_x power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x01b9; -+ if (debug) -+ printk(KERN_DEBUG "Speeding up ringer " -+ "on chan %d (25Hz)\n", -+ card); -+ } -+ /* VBATH */ -+ ystdm_setreg(wc, card, 74, reg74); -+ /*RCO*/ -+ ystdm_proslic_setreg_indirect(wc, card, 20, reg20); -+ /*RNGX*/ -+ ystdm_proslic_setreg_indirect(wc, card, 21, reg21); -+ -+ } else { -+ /* Ringer Speed */ -+ if (fxshonormode && fxo_modes[_opermode].ring_osc) { -+ reg20 = fxo_modes[_opermode].ring_osc; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: " -+ "ring_osc speed on chan %d\n", -+ card); -+ } else { -+ reg20 = 0x7ef0; /* Default */ -+ } -+ -+ reg74 = 0x32; /* Default */ -+ /* Beef up Ringing voltage to 89V */ -+ if (boostringer) { -+ reg74 = 0x3f; -+ reg21 = 0x1d1; -+ if (debug) -+ printk(KERN_DEBUG "Boosting ringer on " -+ "chan %d (89V peak)\n", -+ card); -+ } else if (lowpower) { -+ reg21 = 0x108; -+ if (debug) -+ printk(KERN_DEBUG "Reducing ring power " -+ "on chan %d (50V peak)\n", -+ card); -+ } else if (fxshonormode && -+ fxo_modes[_opermode].ring_x) { -+ reg21 = fxo_modes[_opermode].ring_x; -+ if (debug) -+ printk(KERN_DEBUG "fxshonormode: ring_x" -+ " power on chan %d\n", -+ card); -+ } else { -+ reg21 = 0x160; -+ if (debug) -+ printk(KERN_DEBUG "Normal ring power on" -+ " chan %d\n", -+ card); -+ } -+ /* VBATH */ -+ ystdm_setreg(wc, card, 74, reg74); -+ /* RCO */ -+ ystdm_proslic_setreg_indirect(wc, card, 20, reg20); -+ /* RNGX */ -+ ystdm_proslic_setreg_indirect(wc, card, 21, reg21); -+ } -+ } -+ return 0; -+} -+ -+static int ystdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) -+{ -+ struct ystdm *wc = chan->pvt; -+ int chan_entry = chan->chanpos - 1; -+ if (wc->modtype[chan_entry] == MOD_TYPE_FXO) { -+ /* XXX Enable hooksig for FXO XXX */ -+ switch(txsig) { -+ case DAHDI_TXSIG_START: -+ case DAHDI_TXSIG_OFFHOOK: -+ wc->mod[chan_entry].fxo.offhook = 1; -+ ystdm_setreg(wc, chan_entry, 5, 0x9); -+ break; -+ case DAHDI_TXSIG_ONHOOK: -+ wc->mod[chan_entry].fxo.offhook = 0; -+ ystdm_setreg(wc, chan_entry, 5, 0x8); -+ break; -+ default: -+ printk("wcfxo: Can't set tx state to %d\n", txsig); -+ } -+ } else { -+ ystdm_fxs_hooksig(wc, chan_entry, txsig); -+ } -+ return 0; -+} -+ -+static const struct dahdi_span_ops ystdm_span_ops = { -+ .owner = THIS_MODULE, -+ .hooksig = ystdm_hooksig, -+ .open = ystdm_open, -+ .close = ystdm_close, -+ .ioctl = ystdm_ioctl, -+ .watchdog = ystdm_watchdog, -+}; -+ -+static int ystdm_initialize(struct ystdm *wc) -+{ -+ int x; -+ -+ wc->ddev = dahdi_create_device(); -+ if (!wc->ddev) -+ return -ENOMEM; -+ -+ /* Zapata stuff */ -+ sprintf(wc->span.name, "WCTDM/%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 = "YEASTAR"; -+ wc->ddev->devicetype = wc->variety; -+ -+ -+ if (alawoverride) { -+ printk("ALAW override parameter detected. Device will be operating in ALAW\n"); -+ wc->span.deflaw = DAHDI_LAW_ALAW; -+ } else { -+ wc->span.deflaw = DAHDI_LAW_MULAW; -+ } -+ for (x = 0; x < NUM_CARDS; x++) { -+ sprintf(wc->chans[x]->name, "WCTDM/%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; -+ } -+ -+ wc->span.chans = wc->chans; -+ wc->span.channels = NUM_CARDS; -+ wc->span.flags = DAHDI_FLAG_RBS; -+ wc->span.ops = &ystdm_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 span with DAHDI\n"); -+ kfree(wc->ddev->location); -+ dahdi_free_device(wc->ddev); -+ wc->ddev = NULL; -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static void ystdm_post_initialize(struct ystdm *wc) -+{ -+ int x; -+ /* Finalize signalling */ -+ for (x = 0; x < 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 ystdm_hardware_init(struct ystdm *wc) -+{ -+ /* Hardware stuff */ -+ unsigned char ver; -+ unsigned char x,y; -+ unsigned char ol = 0, sl = 0; -+ int failed; -+ -+ /* Signal Reset */ -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ -+ /* Check Freshmaker chip */ -+ x=inb(wc->ioaddr + WC_CNTL); -+ ver = __ystdm_getcreg(wc, WC_VER); -+ failed = 0; -+ if (ver != 0x59) { -+ printk("Freshmaker version: %02x\n", ver); -+ for (x=0;x<255;x++) { -+ /* Test registers */ -+ if (ver >= 0x70) { -+ __ystdm_setcreg(wc, WC_CS, x); -+ y = __ystdm_getcreg(wc, WC_CS); -+ } else { -+ __ystdm_setcreg(wc, WC_TEST, x); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ } -+ if (x != y) { -+ printk("%02x != %02x\n", x, y); -+ failed++; -+ } -+ } -+ if (!failed) { -+ printk("Freshmaker passed register test\n"); -+ } else { -+ printk("Freshmaker failed register test\n"); -+ return -1; -+ } -+ } else { -+ printk("No freshmaker chip\n"); -+ } -+ -+ /* 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 | BIT_SYNC; -+ -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ -+ /* Set all to outputs except AUX 5, which is an input */ -+ outb(0xdf, wc->ioaddr + WC_AUXC); -+ -+ /* 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); -+ -+ /* 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(0x0, wc->ioaddr + WC_FSCDELAY); -+ -+ /* Setup DMA Addresses */ -+ outl(wc->writedma, wc->ioaddr + WC_DMAWS); /* Write start */ -+ outl(wc->writedma + DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMAWI); /* Middle (interrupt) */ -+ outl(wc->writedma + 2 * DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMAWE); /* End */ -+ -+ outl(wc->readdma, wc->ioaddr + WC_DMARS); /* Read start */ -+ outl(wc->readdma + DAHDI_CHUNKSIZE * NUM_CARDS - 4, wc->ioaddr + WC_DMARI); /* Middle (interrupt) */ -+ outl(wc->readdma + 2 * DAHDI_CHUNKSIZE * NUM_CARDS - 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 < NUM_CARDS; x++) { -+ int sane=0,ret=0,readi=0; -+#if 1 -+ /* Init with Auto Calibration */ -+ if (!(ret=ystdm_init_proslic(wc, x, 0, 0, sane))) { -+ wc->cardflag |= (1 << x); -+ sl |= (1 << x); -+ if (debug) { -+ readi = ystdm_getreg(wc,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x, -+ ((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- AUTO FXS/DPO\n",x); -+ } else { -+ if(ret!=-2) { -+ sane=1; -+ /* Init with Manual Calibration */ -+ if (!ystdm_init_proslic(wc, x, 0, 1, sane)) { -+ wc->cardflag |= (1 << x); -+ sl |= (1 << x); -+ if (debug) { -+ readi = ystdm_getreg(wc,x,LOOP_I_LIMIT); -+ printk("Proslic module %d loop current is %dmA\n",x, -+ ((readi*3)+20)); -+ } -+ printk("Module %d: Installed -- MANUAL FXS\n",x); -+ } else { -+ printk("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 = ystdm_init_voicedaa(wc, x, 0, 0, sane))) { -+ wc->cardflag |= (1 << x); -+ ol |= (1 << x); -+ printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name); -+ } else -+ printk("Module %d: Not installed\n", x); -+ } -+#endif -+ } -+ -+ /* Return error if nothing initialized okay. */ -+ if (!wc->cardflag && !timingonly) -+ return -1; -+ if(ver == 0x88) -+ __ystdm_setcreg(wc, WC_SYNC, wc->cardflag); -+ else{ -+ __ystdm_setcreg(wc, WC_SYNC, ol); -+ __ystdm_setcreg(wc, YS_SLC, sl); -+ } -+ return 0; -+} -+ -+static void ystdm_enable_interrupts(struct ystdm *wc) -+{ -+ /* Enable interrupts (we care about all of them) */ -+ outb(0x3f, wc->ioaddr + WC_MASK0); -+ /* No external interrupts */ -+ outb(0x00, wc->ioaddr + WC_MASK1); -+} -+ -+static void ystdm_restart_dma(struct ystdm *wc) -+{ -+ /* Reset Master and TDM */ -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ outb(0x01, wc->ioaddr + WC_OPER); -+} -+ -+static void ystdm_start_dma(struct ystdm *wc) -+{ -+ /* Reset Master and TDM */ -+ unsigned char x,y; -+ outb(0x0f, wc->ioaddr + WC_CNTL); -+ wc->ios &= ~BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(1); -+ wc->ios |= BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ outb(0x01, wc->ioaddr + WC_CNTL); -+ outb(0x01, wc->ioaddr + WC_OPER); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ x = y | 0x01; -+ __ystdm_setcreg(wc, WC_TEST, x); -+} -+ -+static void ystdm_stop_dma(struct ystdm *wc) -+{ -+ unsigned char x,y; -+ wc->ios &= ~BIT_SYNC; -+ outb(wc->ios, wc->ioaddr + WC_AUXD); -+ outb(0x00, wc->ioaddr + WC_OPER); -+ y = __ystdm_getcreg(wc, WC_TEST); -+ x = y & 0xFE; -+ __ystdm_setcreg(wc, WC_TEST, x); -+} -+ -+static void ystdm_reset_tdm(struct ystdm *wc) -+{ -+ /* Reset TDM */ -+ outb(0x0f, wc->ioaddr + WC_CNTL); -+} -+ -+static void ystdm_disable_interrupts(struct ystdm *wc) -+{ -+ outb(0x00, wc->ioaddr + WC_MASK0); -+ outb(0x00, wc->ioaddr + WC_MASK1); -+} -+ -+static int __devinit ystdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ int res; -+ struct ystdm *wc; -+ struct ystdm_desc *d = (struct ystdm_desc *)ent->driver_data; -+ int x; -+ int y; -+ -+ -+ -+ for (x=0;x<WC_MAX_IFACES;x++) -+ if (!ifaces[x]) break; -+ if (x >= WC_MAX_IFACES) { -+ printk("Too many interfaces\n"); -+ return -EIO; -+ } -+ -+ if (pci_enable_device(pdev)) { -+ res = -EIO; -+ } else { -+ wc = kmalloc(sizeof(struct ystdm), GFP_KERNEL); -+ if (wc) { -+ int cardcount = 0; -+ -+ ifaces[x] = wc; -+ memset(wc, 0, sizeof(struct ystdm)); -+ 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->dev = pdev; -+ wc->pos = x; -+ wc->variety = d->name; -+ for (y=0;y<NUM_CARDS;y++) -+ wc->flags[y] = d->flags; -+ /* Keep track of whether we need to free the region */ -+ if (request_region(wc->ioaddr, 0xff, "ystdm")) -+ wc->freeregion = 1; -+ -+ /* Allocate enough memory for two zt chunks, receive and transmit. Each sample uses -+ 32 bits. Allocate an extra set just for control too */ -+ wc->writechunk = pci_alloc_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, &wc->writedma); -+ if (!wc->writechunk) { -+ printk("ystdm: Unable to allocate DMA-able memory\n"); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ return -ENOMEM; -+ } -+ -+ wc->readchunk = wc->writechunk + 2 * DAHDI_MAX_CHUNKSIZE * (NUM_CARDS / 4); /* in doublewords */ -+ wc->readdma = wc->writedma + 2 * DAHDI_MAX_CHUNKSIZE * (NUM_CARDS / 1); /* in bytes */ -+ -+ if (ystdm_initialize(wc)) { -+ printk("ystdm: 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) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ kfree(wc); -+ return -EIO; -+ } -+ -+ /* Enable bus mastering */ -+ pci_set_master(pdev); -+ -+ /* Keep track of which device we are */ -+ pci_set_drvdata(pdev, wc); -+ -+ if (request_irq(pdev->irq, ystdm_interrupt, DAHDI_IRQ_SHARED, "ystdm", wc)) { -+ printk("ystdm: Unable to request IRQ %d\n", pdev->irq); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ pci_set_drvdata(pdev, NULL); -+ kfree(wc); -+ return -EIO; -+ } -+ -+ -+ if (ystdm_hardware_init(wc)) { -+ unsigned char x; -+ -+ /* 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) -+ release_region(wc->ioaddr, 0xff); -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (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; -+ -+ } -+ -+ ystdm_post_initialize(wc); -+ -+ /* Enable interrupts */ -+ ystdm_enable_interrupts(wc); -+ /* Initialize Write/Buffers to all blank data */ -+ memset((void *)wc->writechunk,0,DAHDI_MAX_CHUNKSIZE * 2 * 2 * NUM_CARDS); -+ -+ /* Start DMA */ -+ ystdm_start_dma(wc); -+ -+ for (x = 0; x < NUM_CARDS; x++) { -+ if (wc->cardflag & (1 << x)) -+ cardcount++; -+ } -+ -+ printk("Found a YSTDM8xx: %s (%d modules)\n", wc->variety, cardcount); -+ res = 0; -+ } else -+ res = -ENOMEM; -+ } -+ return res; -+} -+ -+static void ystdm_release(struct ystdm *wc) -+{ -+ dahdi_unregister_device(wc->ddev); -+ if (wc->freeregion) -+ release_region(wc->ioaddr, 0xff); -+ -+ kfree(wc->ddev->location); -+ dahdi_free_device(wc->ddev); -+ -+ kfree(wc); -+ printk("Freed a Wildcard\n"); -+} -+ -+static void __devexit ystdm_remove_one(struct pci_dev *pdev) -+{ -+ struct ystdm *wc = pci_get_drvdata(pdev); -+ if (wc) { -+ -+ /* Stop any DMA */ -+ ystdm_stop_dma(wc); -+ ystdm_reset_tdm(wc); -+ -+ /* In case hardware is still there */ -+ ystdm_disable_interrupts(wc); -+ -+ /* Immediately free resources */ -+ pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * NUM_CARDS, (void *)wc->writechunk, wc->writedma); -+ free_irq(pdev->irq, wc); -+ -+ /* Reset PCI chip and registers */ -+ outb(0x0e, wc->ioaddr + WC_CNTL); -+ -+ /* Release span, possibly delayed */ -+ if (!wc->usecount) -+ ystdm_release(wc); -+ else -+ wc->dead = 1; -+ } -+} -+ -+static DEFINE_PCI_DEVICE_TABLE(ystdm_pci_tbl) = { -+ { 0xe159, 0x0001, 0x2151, PCI_ANY_ID, 0, 0, (unsigned long) &ystdme }, -+ { 0 } -+}; -+ -+MODULE_DEVICE_TABLE(pci, ystdm_pci_tbl); -+ -+static int ystdm_suspend(struct pci_dev *pdev, pm_message_t state) -+{ -+ return -ENOSYS; -+} -+ -+static struct pci_driver ystdm_driver = { -+ .name = "ystdm8xx", -+ .probe = ystdm_init_one, -+ .remove = __devexit_p(ystdm_remove_one), -+ .suspend = ystdm_suspend, -+ .id_table = ystdm_pci_tbl, -+}; -+ -+static int __init ystdm_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("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(" %s\n", fxo_modes[x].name); -+ printk("Note this option is CASE SENSITIVE!\n"); -+ return -ENODEV; -+ } -+ if (!strcmp(opermode, "AUSTRALIA")) { -+ boostringer = 1; -+ fxshonormode = 1; -+ } -+ -+ /* for the voicedaa_check_hook defaults, if the user has not overridden -+ them by specifying them as module parameters, then get the values -+ from the selected operating mode -+ */ -+ 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 = dahdi_pci_module(&ystdm_driver); -+ if (res) -+ return -ENODEV; -+ return 0; -+} -+ -+static void __exit ystdm_cleanup(void) -+{ -+ pci_unregister_driver(&ystdm_driver); -+} -+ -+module_param(debug, int, 0600); -+module_param(fxovoltage, 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(battalarm, uint, 0600); -+module_param(battthresh, 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(dtmf, int, 0600); -+ -+MODULE_DESCRIPTION("YSTDM8xx Yeastar Driver"); -+MODULE_AUTHOR("yeastar <support@yeastar.com>"); -+MODULE_ALIAS("ystdm8xx"); -+MODULE_LICENSE("GPL v2"); -+ -+module_init(ystdm_init); -+module_exit(ystdm_cleanup); |