diff options
author | Maik Broemme | 2015-10-04 21:51:11 +0200 |
---|---|---|
committer | Maik Broemme | 2015-10-04 21:51:11 +0200 |
commit | 205e1524de216b894a99a525a9cd45f49a6d2119 (patch) | |
tree | d6683bbd43e65fe52c986a349662aff443c5c60b /dahdi-linux-2.10.1-openvox-2.patch | |
parent | 126ae972e89a76accea7bcc79972ae8f72c17ab3 (diff) | |
download | aur-205e1524de216b894a99a525a9cd45f49a6d2119.tar.gz |
Removed no longer needed patches
Diffstat (limited to 'dahdi-linux-2.10.1-openvox-2.patch')
-rw-r--r-- | dahdi-linux-2.10.1-openvox-2.patch | 5851 |
1 files changed, 0 insertions, 5851 deletions
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 |