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

📄 wct4xxp.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * TE410P  Quad-T1/E1 PCI Driver version 0.1, 12/16/02 * * Written by Mark Spencer <markster@linux-support.net> * Based on previous works, designs, and archetectures conceived and * written by Jim Dixon <jim@lambdatel.com>. * * Copyright (C) 2001 Jim Dixon / Zapata Telephony. * Copyright (C) 2001, 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/pci.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/interrupt.h>#ifdef STANDALONE_ZAPATA#include "zaptel.h"#else#include <linux/zaptel.h>#endif#ifdef LINUX26#include <linux/moduleparam.h>#endif#include "wct4xxp.h"/* * Tasklets provide better system interactive response at the cost of the * possibility of losing a frame of data at very infrequent intervals.  If * you are more concerned with the performance of your machine, enable the * tasklets.  If you are strict about absolutely no drops, then do not enable * tasklets. *//* #define ENABLE_TASKLETS *//* Define to get more attention-grabbing but slightly more I/O using   alarm status */#define FANCY_ALARMstatic int debug;static int timingcable;static int highestorder;static int t1e1override = -1;static int loopback = 0;static int alarmdebounce = 0;static int noburst = 0;#ifdef FANCY_ALARMstatic int altab[] = {0, 0, 0, 1, 2, 3, 4, 6, 8, 9, 11, 13, 16, 18, 20, 22, 24, 25, 27, 28, 29, 30, 31, 31, 32, 31, 31, 30, 29, 28, 27, 25, 23, 22, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, };#endif#define MAX_SPANS 16#define FLAG_STARTED (1 << 0)#define FLAG_NMF (1 << 1)#define FLAG_SENDINGYELLOW (1 << 2)#define	TYPE_T1	1		/* is a T1 card */#define	TYPE_E1	2		/* is an E1 card */#define CANARY 0xc0destatic int inirq = 0;struct t4 {	/* This structure exists one per card */	struct pci_dev *dev;		/* Pointer to PCI device */	int intcount;	int num;			/* Which card we are */	int t1e1;			/* T1/E1 select pins */	int globalconfig;	/* Whether global setup has been done */	int syncsrc;			/* active sync source */	int syncs[4];			/* sync sources */	int psyncs[4];			/* span-relative sync sources */	int alarmtimer[4];		/* Alarm timer */	int redalarms[4];	int blinktimer;	int alarmcount[4];			/* How much red alarm we've seen */#ifdef FANCY_ALARM	int alarmpos;#endif	int irq;			/* IRQ used by device */	int order;			/* Order */	int flags;			/* Device flags */	int spanflags[4];		/* Span flags */	int syncpos[4];			/* span-relative sync sources */	int master;				/* Are we master */	int ledreg;				/* LED Register */	int e1check[4];			/* E1 check */	unsigned int dmactrl;	int e1recover;			/* E1 recovery timer */	dma_addr_t 	readdma;	dma_addr_t	writedma;	unsigned long memaddr;		/* Base address of card */	unsigned long memlen;	volatile unsigned int *membase;	/* Base address of card */	struct zt_span spans[4];	/* Spans */	struct zt_chan *chans[4];	/* Pointers to blocks of 24(30/31) contiguous zt_chans for each span */	unsigned char txsigs[4][16];  /* Copy of tx sig registers */	int loopupcnt[4];		/* loop up code counter */	int loopdowncnt[4];		/* loop down code counter */	int spansstarted;		/* number of spans started */	/* spinlock_t lock; */		/* lock context */	spinlock_t reglock;		/* lock register access */	unsigned char ec_chunk1[4][31][ZT_CHUNKSIZE]; /* first EC chunk buffer */	unsigned char ec_chunk2[4][31][ZT_CHUNKSIZE]; /* second EC chunk buffer */	volatile unsigned int *writechunk;					/* Double-word aligned write memory */	volatile unsigned int *readchunk;					/* Double-word aligned read memory */	unsigned short canary;#ifdef ENABLE_TASKLETS	int taskletrun;	int taskletsched;	int taskletpending;	int taskletexec;	int txerrors;	struct tasklet_struct t4xxp_tlet;#endif	int spantype[4];		/* card type, T1 or E1 */	unsigned int passno;	/* number of interrupt passes */	char *variety;	int last0;		/* for detecting double-missed IRQ */	int checktiming;	/* Set >0 to cause the timing source to be checked */};static void __set_clear(struct t4 *wc, int span);static int t4_startup(struct zt_span *span);static int t4_shutdown(struct zt_span *span);static int t4_rbsbits(struct zt_chan *chan, int bits);static int t4_maint(struct zt_span *span, int cmd);static int t4_reset_dma(struct t4 *wc);static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);static void __t4_set_timing_source(struct t4 *wc, int unit);#define WC_RDADDR	0#define WC_WRADDR	1#define WC_COUNT	2#define WC_DMACTRL	3	#define WC_INTR		4/* #define WC_GPIO		5 */#define WC_VERSION	6#define WC_LEDS		7#define WC_ACTIVATE	(1 << 12)#define WC_GPIOCTL	8#define WC_GPIO		9#define WC_LADDR	10#define WC_LDATA		11#define WC_LREAD			(1 << 15)#define WC_LWRITE		(1 << 16)#define WC_OFF    (0)#define WC_RED    (1)#define WC_GREEN  (2)#define WC_YELLOW (3)#define MAX_T4_CARDS 64#ifdef ENABLE_TASKLETSstatic void t4_tasklet(unsigned long data);#endifstatic struct t4 *cards[MAX_T4_CARDS];static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value){	unsigned int tmp;	wc->membase[addr] = value;#if 1	tmp = wc->membase[addr];	if ((value != tmp) && (addr != WC_LEDS) && (addr != WC_LDATA) &&		(addr != WC_GPIO) && (addr != WC_INTR))		printk("Tried to load %08x into %08x, but got %08x instead\n", value, addr, tmp);#endif		}static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr){	return wc->membase[addr];}static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value){	unsigned long flags;	spin_lock_irqsave(&wc->reglock, flags);	__t4_pci_out(wc, addr, value);	spin_unlock_irqrestore(&wc->reglock, flags);}static inline void __t4_set_led(struct t4 *wc, int span, int color){	int oldreg = wc->ledreg;	wc->ledreg &= ~(0x3 << (span << 1));	wc->ledreg |= (color << (span << 1));	if (oldreg != wc->ledreg)		__t4_pci_out(wc, WC_LEDS, wc->ledreg);}static inline void t4_activate(struct t4 *wc){	wc->ledreg |= WC_ACTIVATE;	t4_pci_out(wc, WC_LEDS, wc->ledreg);}static inline unsigned int t4_pci_in(struct t4 *wc, const unsigned int addr){	unsigned int ret;	unsigned long flags;		spin_lock_irqsave(&wc->reglock, flags);	ret = __t4_pci_in(wc, addr);	spin_unlock_irqrestore(&wc->reglock, flags);	return ret;}static inline unsigned int __t4_framer_in(struct t4 *wc, int unit, const unsigned int addr){	unsigned int ret;	unit &= 0x3;	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | ( 1 << 10) | WC_LREAD);	ret = __t4_pci_in(wc, WC_LDATA);	__t4_pci_out(wc, WC_LADDR, 0);	return ret & 0xff;}static inline unsigned int t4_framer_in(struct t4 *wc, int unit, const unsigned int addr){	unsigned long flags;	unsigned int ret;	spin_lock_irqsave(&wc->reglock, flags);	ret = __t4_framer_in(wc, unit, addr);	spin_unlock_irqrestore(&wc->reglock, flags);	return ret;}static inline void __t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value){	unit &= 0x3;	if (debug)		printk("Writing %02x to address %02x of unit %d\n", value, addr, unit);	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	__t4_pci_out(wc, WC_LDATA, value);	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10) | WC_LWRITE);	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));		__t4_pci_out(wc, WC_LADDR, 0);	if (debug) printk("Write complete\n");#if 0	{ unsigned int tmp;	tmp = t4_framer_in(wc, unit, addr);	if (tmp != value) {		printk("Expected %d from unit %d register %d but got %d instead\n", value, unit, addr, tmp);	} }#endif	}static inline void t4_framer_out(struct t4 *wc, int unit, const unsigned int addr, const unsigned int value){	unsigned long flags;	spin_lock_irqsave(&wc->reglock, flags);	__t4_framer_out(wc, unit, addr, value);	spin_unlock_irqrestore(&wc->reglock, flags);}static void __set_clear(struct t4 *wc, int span){	int i,j;	unsigned short val=0;	for (i=0;i<24;i++) {		j = (i/8);		if (wc->spans[span].chans[i].flags & ZT_FLAG_CLEAR) 			val |= 1 << (7 - (i % 8));		if ((i % 8)==7) {			if (debug)				printk("Putting %d in register %02x on span %d\n",			       val, 0x2f + j, span + 1);			__t4_framer_out(wc,span, 0x2f + j, val);			val = 0;		}	}}#if 0static void set_clear(struct t4 *wc, int span){	unsigned long flags;	spin_lock_irqsave(&wc->reglock, flags);	__set_clear(wc, span);	spin_unlock_irqrestore(&wc->reglock, flags);}#endifstatic int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data){	struct t4_regs regs;	int x;	switch(cmd) {	case WCT4_GET_REGS:		for (x=0;x<NUM_PCI;x++)			regs.pci[x] = t4_pci_in(chan->pvt, x);		for (x=0;x<NUM_REGS;x++)			regs.regs[x] = t4_framer_in(chan->pvt, chan->span->offset, x);		if (copy_to_user((struct t4_regs *)data, &regs, sizeof(regs)))			return -EFAULT;		break;	default:		return -ENOTTY;	}	return 0;}static int t4_maint(struct zt_span *span, int cmd){	struct t4 *wc = span->pvt;	if (wc->spantype[span->offset] == TYPE_E1) {		switch(cmd) {		case ZT_MAINT_NONE:			printk("XXX Turn off local and remote loops E1 XXX\n");			break;		case ZT_MAINT_LOCALLOOP:			printk("XXX Turn on local loopback E1 XXX\n");			break;		case ZT_MAINT_REMOTELOOP:			printk("XXX Turn on remote loopback E1 XXX\n");			break;		case ZT_MAINT_LOOPUP:			printk("XXX Send loopup code E1 XXX\n");			break;		case ZT_MAINT_LOOPDOWN:			printk("XXX Send loopdown code E1 XXX\n");			break;		case ZT_MAINT_LOOPSTOP:			printk("XXX Stop sending loop codes E1 XXX\n");			break;		default:			printk("TE410P: Unknown E1 maint command: %d\n", cmd);			break;		}	} else {		switch(cmd) {	    case ZT_MAINT_NONE:			printk("XXX Turn off local and remote loops T1 XXX\n");			break;	    case ZT_MAINT_LOCALLOOP:			printk("XXX Turn on local loop and no remote loop XXX\n");			break;	    case ZT_MAINT_REMOTELOOP:			printk("XXX Turn on remote loopup XXX\n");			break;	    case ZT_MAINT_LOOPUP:			t4_framer_out(wc, span->offset, 0x21, 0x50);	/* FMR5: Nothing but RBS mode */			break;	    case ZT_MAINT_LOOPDOWN:			t4_framer_out(wc, span->offset, 0x21, 0x60);	/* FMR5: Nothing but RBS mode */			break;	    case ZT_MAINT_LOOPSTOP:			t4_framer_out(wc, span->offset, 0x21, 0x40);	/* FMR5: Nothing but RBS mode */			break;	    default:			printk("TE410P: Unknown T1 maint command: %d\n", cmd);			break;	   }    }	return 0;}static int t4_rbsbits(struct zt_chan *chan, int bits){	u_char m,c;	int k,n,b;	struct t4 *wc = chan->pvt;	unsigned long flags;		if(debug) printk("Setting bits to %d on channel %s\n", bits, chan->name);	spin_lock_irqsave(&wc->reglock, flags);		k = chan->span->offset;	if (wc->spantype[k] == TYPE_E1) { /* do it E1 way */		if (chan->chanpos == 16) {			spin_unlock_irqrestore(&wc->reglock, flags);			return 0;		}		n = chan->chanpos - 1;		if (chan->chanpos > 15) n--;		b = (n % 15);		c = wc->txsigs[k][b];		m = (n / 15) << 2; /* nibble selector */		c &= (0xf << m); /* keep the other nibble */		c |= (bits & 0xf) << (4 - m); /* put our new nibble here */		wc->txsigs[k][b] = c;		  /* output them to the chip */		__t4_framer_out(wc,k,0x71 + b,c); 	} else if (wc->spans[k].lineconfig & ZT_CONFIG_D4) {		n = chan->chanpos - 1;		b = (n/4);		c = wc->txsigs[k][b];		m = ((3 - (n % 4)) << 1); /* nibble selector */		c &= ~(0x3 << m); /* keep the other nibble */		c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */		wc->txsigs[k][b] = c;		  /* output them to the chip */		__t4_framer_out(wc,k,0x70 + b,c); 		__t4_framer_out(wc,k,0x70 + b + 6,c); 	} else if (wc->spans[k].lineconfig & ZT_CONFIG_ESF) {		n = chan->chanpos - 1;		b = (n/2);		c = wc->txsigs[k][b];		m = ((n % 2) << 2); /* nibble selector */		c &= (0xf << m); /* keep the other nibble */		c |= (bits & 0xf) << (4 - m); /* put our new nibble here */		wc->txsigs[k][b] = c;		  /* output them to the chip */		__t4_framer_out(wc,k,0x70 + b,c); 	} 	spin_unlock_irqrestore(&wc->reglock, flags);

⌨️ 快捷键说明

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