⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wcfxs.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Wilcard TDM400P TDM FXS/FXO Interface Driver for Zapata Telephony interface * * Written by Mark Spencer <markster@linux-support.net> *            Matthew Fredrickson <creslin@linux-support.net> * * Copyright (C) 2001, Linux Support Services, Inc. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *  * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <linux/kernel.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/interrupt.h>#include "proslic.h"#include "wcfxs.h"/* *  Define for audio vs. register based ring detection *   *//* #define AUDIO_RINGCHECK  *//*  Experimental max loop current limit for the proslic  Loop current limit is from 20 mA to 41 mA in steps of 3  (according to datasheet)  So set the value below to:  0x00 : 20mA (default)  0x01 : 23mA  0x02 : 26mA  0x03 : 29mA  0x04 : 32mA  0x05 : 35mA  0x06 : 37mA  0x07 : 41mA*/static int loopcurrent = 20;static alpha  indirect_regs[] ={{0,"DTMF_ROW_0_PEAK",0x55C2},{1,"DTMF_ROW_1_PEAK",0x51E6},{2,"DTMF_ROW2_PEAK",0x4B85},{3,"DTMF_ROW3_PEAK",0x4937},{4,"DTMF_COL1_PEAK",0x3333},{5,"DTMF_FWD_TWIST",0x0202},{6,"DTMF_RVS_TWIST",0x0202},{7,"DTMF_ROW_RATIO_TRES",0x0198},{8,"DTMF_COL_RATIO_TRES",0x0198},{9,"DTMF_ROW_2ND_ARM",0x0611},{10,"DTMF_COL_2ND_ARM",0x0202},{11,"DTMF_PWR_MIN_TRES",0x00E5},{12,"DTMF_OT_LIM_TRES",0x0A1C},{13,"OSC1_COEF",0x7B30},{14,"OSC1X",0x0063},{15,"OSC1Y",0x0000},{16,"OSC2_COEF",0x7870},{17,"OSC2X",0x007D},{18,"OSC2Y",0x0000},{19,"RING_V_OFF",0x0000},{20,"RING_OSC",0x7EF0},{21,"RING_X",0x0160},{22,"RING_Y",0x0000},{23,"PULSE_ENVEL",0x2000},{24,"PULSE_X",0x2000},{25,"PULSE_Y",0x0000},//{26,"RECV_DIGITAL_GAIN",0x4000},	// playback volume set lower{26,"RECV_DIGITAL_GAIN",0x2000},	// playback volume set lower{27,"XMIT_DIGITAL_GAIN",0x4000},//{27,"XMIT_DIGITAL_GAIN",0x2000},{28,"LOOP_CLOSE_TRES",0x1000},{29,"RING_TRIP_TRES",0x3600},{30,"COMMON_MIN_TRES",0x1000},{31,"COMMON_MAX_TRES",0x0200},{32,"PWR_ALARM_Q1Q2",0x07C0},{33,"PWR_ALARM_Q3Q4",0x2600},{34,"PWR_ALARM_Q5Q6",0x1B80},{35,"LOOP_CLOSURE_FILTER",0x8000},{36,"RING_TRIP_FILTER",0x0320},{37,"TERM_LP_POLE_Q1Q2",0x008C},{38,"TERM_LP_POLE_Q3Q4",0x0100},{39,"TERM_LP_POLE_Q5Q6",0x0010},{40,"CM_BIAS_RINGING",0x0C00},{41,"DCDC_MIN_V",0x0C00},{42,"DCDC_XTRA",0x1000},{43,"LOOP_CLOSE_TRES_LOW",0x1000},};static struct fxo_mode {	char *name;	/* FXO */	int ohs;	int ohs2;	int rz;	int rt;	int ilim;	int dcv;	int mini;	int acim;	int ring_osc;	int ring_x;} fxo_modes[] ={	{ "FCC", 0, 0, 0, 0, 0, 0x3, 0, 0 }, 	/* US, Canada */	{ "TBR21", 0, 0, 0, 0, 1, 0x3, 0, 0x2, 0x7e6c, 0x023a },										/* Austria, Belgium, Denmark, Finland, France, Germany, 										   Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands,										   Norway, Portugal, Spain, Sweden, Switzerland, and UK */	{ "ARGENTINA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "AUSTRALIA", 1, 0, 0, 0, 0, 0, 0x3, 0x3 },	{ "AUSTRIA", 0, 1, 0, 0, 1, 0x3, 0, 0x3 },	{ "BAHRAIN", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "BELGIUM", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "BRAZIL", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "BULGARIA", 0, 0, 0, 0, 1, 0x3, 0x0, 0x3 },	{ "CANADA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "CHILE", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "CHINA", 0, 0, 0, 0, 0, 0, 0x3, 0xf },	{ "COLUMBIA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "CROATIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "CYRPUS", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "CZECH", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "DENMARK", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "ECUADOR", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "EGYPT", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "ELSALVADOR", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "FINLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "FRANCE", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "GERMANY", 0, 1, 0, 0, 1, 0x3, 0, 0x3 },	{ "GREECE", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "GUAM", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "HONGKONG", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "HUNGARY", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "ICELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "INDIA", 0, 0, 0, 0, 0, 0x3, 0, 0x4 },	{ "INDONESIA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "IRELAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "ISRAEL", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "ITALY", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "JAPAN", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "JORDAN", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "KAZAKHSTAN", 0, 0, 0, 0, 0, 0x3, 0 },	{ "KUWAIT", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "LATVIA", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "LEBANON", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "LUXEMBOURG", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "MACAO", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "MALAYSIA", 0, 0, 0, 0, 0, 0, 0x3, 0 },	/* Current loop >= 20ma */	{ "MALTA", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "MEXICO", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "MOROCCO", 0, 0, 0, 0, 1, 0x3, 0, 0x2 },	{ "NETHERLANDS", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "NEWZEALAND", 0, 0, 0, 0, 0, 0x3, 0, 0x4 },	{ "NIGERIA", 0, 0, 0, 0, 0x1, 0x3, 0, 0x2 },	{ "NORWAY", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "OMAN", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "PAKISTAN", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "PERU", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "PHILIPPINES", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "POLAND", 0, 0, 1, 1, 0, 0x3, 0, 0 },	{ "PORTUGAL", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "ROMANIA", 0, 0, 0, 0, 0, 3, 0, 0 },	{ "RUSSIA", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "SAUDIARABIA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "SINGAPORE", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "SLOVAKIA", 0, 0, 0, 0, 0, 0x3, 0, 0x3 },	{ "SLOVENIA", 0, 0, 0, 0, 0, 0x3, 0, 0x2 },	{ "SOUTHAFRICA", 1, 0, 1, 0, 0, 0x3, 0, 0x3 },	{ "SOUTHKOREA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "SPAIN", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "SWEDEN", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "SWITZERLAND", 0, 1, 0, 0, 1, 0x3, 0, 0x2 },	{ "SYRIA", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "TAIWAN", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "THAILAND", 0, 0, 0, 0, 0, 0, 0x3, 0 },	{ "UAE", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "UK", 0, 1, 0, 0, 1, 0x3, 0, 0x5 },	{ "USA", 0, 0, 0, 0, 0, 0x3, 0, 0 },	{ "YEMEN", 0, 0, 0, 0, 0, 0x3, 0, 0 },};#ifdef STANDALONE_ZAPATA#include "zaptel.h"#else#include <linux/zaptel.h>#endif#ifdef LINUX26#include <linux/moduleparam.h>#endif#define NUM_FXO_REGS 60#define WC_MAX_IFACES 128#define WC_CNTL    	0x00#define WC_OPER		0x01#define WC_AUXC    	0x02#define WC_AUXD    	0x03#define WC_MASK0   	0x04#define WC_MASK1   	0x05#define WC_INTSTAT 	0x06#define WC_AUXR		0x07#define WC_DMAWS	0x08#define WC_DMAWI	0x0c#define WC_DMAWE	0x10#define WC_DMARS	0x18#define WC_DMARI	0x1c#define WC_DMARE	0x20#define WC_AUXFUNC	0x2b#define WC_SERCTL	0x2d#define WC_FSCDELAY	0x2f#define WC_REGBASE	0xc0#define WC_SYNC		0x0#define WC_TEST		0x1#define WC_CS		0x2#define WC_VER		0x3#define BIT_CS		(1 << 2)#define BIT_SCLK	(1 << 3)#define BIT_SDI		(1 << 4)#define BIT_SDO		(1 << 5)#define FLAG_EMPTY	0#define FLAG_WRITE	1#define FLAG_READ	2#define RING_DEBOUNCE	64		/* Ringer Debounce (in ms) */#define BATT_DEBOUNCE	64		/* Battery debounce (in ms) */#define POLARITY_DEBOUNCE 64           /* Polarity debounce (in ms) */#define BATT_THRESH	3		/* Anything under this is "no battery" */#define OHT_TIMER		6000	/* How long after RING to retain OHT */#define FLAG_DOUBLE_CLOCK	(1 << 0)#define NUM_CARDS 4#define MAX_ALARMS 10#define MOD_TYPE_FXS	0#define MOD_TYPE_FXO	1#define MINPEGTIME	10 * 8		/* 30 ms peak to peak gets us no more than 100 Hz */#define PEGTIME		50 * 8		/* 50ms peak to peak gets us rings of 10 Hz or more */#define PEGCOUNT	5		/* 5 cycles of pegging means RING */#define NUM_CAL_REGS 12struct calregs {	unsigned char vals[NUM_CAL_REGS];};struct wcfxs {	struct pci_dev *dev;	char *variety;	struct zt_span span;	unsigned char ios;	int usecount;	int intcount;	int dead;	int pos;	int flags;	int freeregion;	int alt;	int curcard;	int cards;	int cardflag;		/* Bit-map of present cards */	spinlock_t lock;	/* FXO Stuff */	union {		struct {#ifdef AUDIO_RINGCHECK			unsigned int pegtimer[NUM_CARDS];			int pegcount[NUM_CARDS];			int peg[NUM_CARDS];			int ring[NUM_CARDS];#else						int wasringing[NUM_CARDS];#endif						int ringdebounce[NUM_CARDS];			int offhook[NUM_CARDS];			int battdebounce[NUM_CARDS];			int nobatttimer[NUM_CARDS];			int battery[NUM_CARDS];		        int lastpol[NUM_CARDS];		        int polarity[NUM_CARDS];		        int polaritydebounce[NUM_CARDS];		} fxo;		struct {			int oldrxhook[NUM_CARDS];			int debouncehook[NUM_CARDS];			int lastrxhook[NUM_CARDS];			int debounce[NUM_CARDS];			int ohttimer[NUM_CARDS];			int idletxhookstate[NUM_CARDS];		/* IDLE changing hook state */			int lasttxhook[NUM_CARDS];			int palarms[NUM_CARDS];			struct calregs calregs[NUM_CARDS];		} fxs;	} mod;	/* Receive hook state and debouncing */	int modtype[NUM_CARDS];	unsigned long ioaddr;	dma_addr_t 	readdma;	dma_addr_t	writedma;	volatile int *writechunk;					/* Double-word aligned write memory */	volatile int *readchunk;					/* Double-word aligned read memory */	struct zt_chan chans[NUM_CARDS];};struct wcfxs_desc {	char *name;	int flags;};static struct wcfxs_desc wcfxs = { "Wildcard S400P Prototype", 0 };static struct wcfxs_desc wcfxse = { "Wildcard TDM400P REV E/F", 0 };static struct wcfxs_desc wcfxsh = { "Wildcard TDM400P REV H", 0 };static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };static struct wcfxs *ifaces[WC_MAX_IFACES];static void wcfxs_release(struct wcfxs *wc);static int debug = 0;static int robust = 0;static int timingonly = 0;static int lowpower = 0;static int boostringer = 0;static int _opermode = 0;static char *opermode = "FCC";static int fxshonormode = 0;static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast , int manual, int sane);static inline void wcfxs_transmitprep(struct wcfxs *wc, unsigned char ints){	volatile unsigned int *writechunk;	int x;	if (ints & 0x01) 		/* Write is at interrupt address.  Start writing from normal offset */		writechunk = wc->writechunk;	else 		writechunk = wc->writechunk + ZT_CHUNKSIZE;	/* Calculate Transmission */	zt_transmit(&wc->span);	for (x=0;x<ZT_CHUNKSIZE;x++) {		/* Send a sample, as a 32-bit word */		writechunk[x] = 0;		if (wc->cardflag & (1 << 3))			writechunk[x] |= (wc->chans[3].writechunk[x] << 24);		if (wc->cardflag & (1 << 2))			writechunk[x] |= (wc->chans[2].writechunk[x] << 16);		if (wc->cardflag & (1 << 1))			writechunk[x] |= (wc->chans[1].writechunk[x] << 8);		if (wc->cardflag & (1 << 0))			writechunk[x] |= (wc->chans[0].writechunk[x]);			}}#ifdef AUDIO_RINGCHECKstatic inline void ring_check(struct wcfxs *wc, int card){	int x;	short sample;	if (wc->modtype[card] != MOD_TYPE_FXO)		return;	wc->mod.fxo.pegtimer[card] += ZT_CHUNKSIZE;	for (x=0;x<ZT_CHUNKSIZE;x++) {		/* Look for pegging to indicate ringing */		sample = ZT_XLAW(wc->chans[card].readchunk[x], (&(wc->chans[card])));		if ((sample > 10000) && (wc->mod.fxo.peg[card] != 1)) {			if (debug > 1) printk("High peg!\n");			if ((wc->mod.fxo.pegtimer[card] < PEGTIME) && (wc->mod.fxo.pegtimer[card] > MINPEGTIME))				wc->mod.fxo.pegcount[card]++;			wc->mod.fxo.pegtimer[card] = 0;			wc->mod.fxo.peg[card] = 1;		} else if ((sample < -10000) && (wc->mod.fxo.peg[card] != -1)) {			if (debug > 1) printk("Low peg!\n");			if ((wc->mod.fxo.pegtimer[card] < (PEGTIME >> 2)) && (wc->mod.fxo.pegtimer[card] > (MINPEGTIME >> 2)))				wc->mod.fxo.pegcount[card]++;			wc->mod.fxo.pegtimer[card] = 0;			wc->mod.fxo.peg[card] = -1;		}	}	if (wc->mod.fxo.pegtimer[card] > PEGTIME) {		/* Reset pegcount if our timer expires */		wc->mod.fxo.pegcount[card] = 0;	}	/* Decrement debouncer if appropriate */	if (wc->mod.fxo.ringdebounce[card])		wc->mod.fxo.ringdebounce[card]--;	if (!wc->mod.fxo.offhook[card] && !wc->mod.fxo.ringdebounce[card]) {		if (!wc->mod.fxo.ring[card] && (wc->mod.fxo.pegcount[card] > PEGCOUNT)) {			/* It's ringing */			if (debug)				printk("RING on %d/%d!\n", wc->span.spanno, card + 1);			if (!wc->mod.fxo.offhook[card])				zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);			wc->mod.fxo.ring[card] = 1;		}		if (wc->mod.fxo.ring[card] && !wc->mod.fxo.pegcount[card]) {			/* No more ring */			if (debug)				printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);			zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);			wc->mod.fxo.ring[card] = 0;		}	}}#endifstatic inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -