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

📄 wcte11xp.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Digium, Inc.  Wildcard TE110P T1/PRI card Driver * * Written by Mark Spencer <markster@linux-support.net> *            Matthew Fredrickson <creslin@linux-support.net> *            William Meadows <wmeadows@linux-support.net> * * Copyright (C) 2004, Digium, Inc. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *  * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  * * $Id: wcte11xp.c,v 1.1.2.4 2005/01/17 01:58:09 russell Exp $ */#include <linux/kernel.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/init.h>#include <linux/usb.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/spinlock.h>#ifdef STANDALONE_ZAPATA#include "zaptel.h"#else#include <linux/zaptel.h>#endif#ifdef LINUX26#include <linux/moduleparam.h>#endif#include "wct4xxp.h"	/* For certain definitions */#define WC_MAX_CARDS	32/*#define TEST_REGS*//* Define to get more attention-grabbing but slightly more I/O using   alarm status */#define FANCY_ALARM/* Define to enable the V2.1 errata register settings */#if 0#define TRUST_INFINEON_ERRATA#endif#define DELAY	0x0	/* 30 = 15 cycles, 10 = 8 cycles, 0 = 3 cycles */#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_DMAWS	0x08#define WC_DMAWI	0x0c#define WC_DMAWE	0x10#define WC_DMARS	0x18#define WC_DMARI	0x1c#define WC_DMARE	0x20#define WC_CURPOS	0x24#define WC_SERC		0x2d#define WC_FSCDELAY	0x2f#define WC_USERREG	0xc0#define WC_CLOCK	0x0#define WC_LEDTEST	0x1#define WC_VERSION	0x2/* Offset between transmit and receive */#define WC_OFFSET	4#define BIT_CS		(1 << 7)#define BIT_ADDR	(0xf << 3)#define BIT_LED1	(1 << 0)#define BIT_LED0	(1 << 1)#define BIT_TEST	(1 << 2)#define FLAG_STARTED 		(1 << 0)#define FLAG_NMF 			(1 << 1)#define FLAG_SENDINGYELLOW 	(1 << 2)#define FLAG_FALC12			(1 << 3)#define	TYPE_T1	1		/* is a T1 card */#define	TYPE_E1	2		/* is an E1 card */static int chanmap_t1[] = { 2,1,0,  6,5,4,  10,9,8,  14,13,12,  18,17,16,  22,21,20,  26,25,24,  30,29,28 };static int chanmap_e1[] = { 2,1,0,  7,6,5,4,  11,10,9,8,  15,14,13,12,  19,18,17,16,  23,22,21,20,  27,26,25,24,  31,30,29,28 };#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, };#endifstruct t1 {	struct pci_dev *dev;	spinlock_t lock;	int spantype;	int spanflags;		/* Span flags */	unsigned char txsigs[16];  /* Copy of tx sig registers */	int num;	int alarmcount;			/* How much red alarm we've seen */	int alarmdebounce;	/* Our offset for finding channel 1 */	int offset;	char *variety;	int intcount;	int usecount;	int clocktimeout;	int sync;	int dead;	int blinktimer;	int alarmtimer;	int checktiming;	/* Set >0 to cause the timing source to be checked */	int loopupcnt;	int loopdowncnt;	int miss;	int misslast;	int *chanmap;#ifdef FANCY_ALARM	int alarmpos;#endif	unsigned char ledtestreg;	unsigned char outbyte;	unsigned long ioaddr;	unsigned short canary;	/* T1 signalling */	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 */	unsigned char ec_chunk1[31][ZT_CHUNKSIZE];	unsigned char ec_chunk2[31][ZT_CHUNKSIZE];	unsigned char tempo[32];	struct zt_span span;						/* Span */	struct zt_chan chans[31];					/* Channels */};#define CANARY 0xca1estatic int debug = 0;   /* doesnt do anything */static int alarmdebounce = 0;static int loopback = 0;static int clockextra = 0;static int t1e1override = -1;static struct t1 *cards[WC_MAX_CARDS];static inline void start_alarm(struct t1 *wc){#ifdef FANCY_ALARM	wc->alarmpos = 0;#endif	wc->blinktimer = 0;}static inline void stop_alarm(struct t1 *wc){#ifdef FANCY_ALARM	wc->alarmpos = 0;#endif	wc->blinktimer = 0;}static inline void __select_framer(struct t1 *wc, int reg){	/* Top four bits of address from AUX 6-3 */	wc->outbyte &= ~BIT_CS;	wc->outbyte &= ~BIT_ADDR;	wc->outbyte |= (reg & 0xf0) >> 1;	outb(wc->outbyte, wc->ioaddr + WC_AUXD);}static inline void __select_control(struct t1 *wc){	if (!(wc->outbyte & BIT_CS)) {		wc->outbyte |= BIT_CS;		outb(wc->outbyte, wc->ioaddr + WC_AUXD);	}}static int t1xxp_open(struct zt_chan *chan){	struct t1 *wc = chan->pvt;	if (wc->dead)		return -ENODEV;	wc->usecount++;#ifndef LINUX26		MOD_INC_USE_COUNT;#endif		return 0;}static int __control_set_reg(struct t1 *wc, int reg, unsigned char val){	__select_control(wc);	outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));	return 0;}static int control_set_reg(struct t1 *wc, int reg, unsigned char val){	unsigned long flags;	int res;	spin_lock_irqsave(&wc->lock, flags);	res = __control_set_reg(wc, reg, val);	spin_unlock_irqrestore(&wc->lock, flags);	return res;}static int __control_get_reg(struct t1 *wc, int reg){	unsigned char res;	/* The following makes UTTERLY no sense, but what was happening	   was that reads in some cases were not actually happening	   on the physical bus. Why, we dunno. But in debugging, we found	   that writing before reading (in this case to an unused position)	   seems to get rid of the problem */	__control_set_reg(wc,3,0x69); /* do magic here */	/* now get the read byte from the Xilinx part */	res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));	return res;}static int control_get_reg(struct t1 *wc, int reg){	unsigned long flags;	int res;	spin_lock_irqsave(&wc->lock, flags);	res = __control_get_reg(wc, reg);	spin_unlock_irqrestore(&wc->lock, flags);	return res;}static inline unsigned int __t1_framer_in(struct t1 *wc, const unsigned int reg){	unsigned char res;	__select_framer(wc, reg);	/* Get value */	res = inb(wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));	return res;#if 0	unsigned int ret;	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | ( 1 << 10) | WC_LREAD);	ret = __t1_pci_in(wc, WC_LDATA);	__t1_pci_out(wc, WC_LADDR, 0);	return ret & 0xff;#endif	}static inline unsigned int t1_framer_in(struct t1 *wc, const unsigned int addr){	unsigned long flags;	unsigned int ret;	spin_lock_irqsave(&wc->lock, flags);	ret = __t1_framer_in(wc, addr);	spin_unlock_irqrestore(&wc->lock, flags);	return ret;}static inline void __t1_framer_out(struct t1 *wc, const unsigned int reg, const unsigned int val){	if (debug > 1)		printk("Writing %02x to address %02x\n", val, reg);	__select_framer(wc, reg);	/* Send address */	outb(val, wc->ioaddr + WC_USERREG + ((reg & 0xf) << 2));#if 0	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	__t1_pci_out(wc, WC_LDATA, value);	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10) | WC_LWRITE);	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));	__t1_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));		__t1_pci_out(wc, WC_LADDR, 0);	if (debug) printk("Write complete\n");#endif	#if 0	{ unsigned int tmp;	tmp = t1_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 t1_framer_out(struct t1 *wc, const unsigned int addr, const unsigned int value){	unsigned long flags;	spin_lock_irqsave(&wc->lock, flags);	__t1_framer_out(wc, addr, value);	spin_unlock_irqrestore(&wc->lock, flags);}static void t1xxp_release(struct t1 *wc){	zt_unregister(&wc->span);	kfree(wc);	printk("Freed a Wildcard\n");}static int t1xxp_close(struct zt_chan *chan){	struct t1 *wc = chan->pvt;	wc->usecount--;#ifndef LINUX26		MOD_DEC_USE_COUNT;#endif	/* If we're dead, release us now */	if (!wc->usecount && wc->dead) 		t1xxp_release(wc);	return 0;}static void t1xxp_enable_interrupts(struct t1 *wc){	/* Clear interrupts */	outb(0xff, wc->ioaddr + WC_INTSTAT);	/* Enable interrupts (we care about all of them) */	outb(0x3c /* 0x3f */, wc->ioaddr + WC_MASK0); 	/* No external interrupts */	outb(0x00, wc->ioaddr + WC_MASK1);	if (debug) printk("Enabled interrupts!\n");}static void t1xxp_start_dma(struct t1 *wc){	/* Reset Master and TDM */	outb(DELAY | 0x0f, wc->ioaddr + WC_CNTL);	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(1);	outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);	outb(0x01, wc->ioaddr + WC_OPER);	if (debug) printk("Started DMA\n");	outb(0x03, wc->ioaddr + WC_OPER);	outb(0x01, wc->ioaddr + WC_OPER);}static void __t1xxp_stop_dma(struct t1 *wc){	outb(0x00, wc->ioaddr + WC_OPER);}static void __t1xxp_disable_interrupts(struct t1 *wc)	{	outb(0x00, wc->ioaddr + WC_MASK0);	outb(0x00, wc->ioaddr + WC_MASK1);}static void __t1xxp_set_clear(struct t1 *wc){	int i,j;	unsigned short val=0;	for (i=0;i<24;i++) {		j = (i/8);		if (wc->span.chans[i].flags & ZT_FLAG_CLEAR) 			val |= 1 << (7 - (i % 8));		if ((i % 8)==7) {			if (debug > 1)				printk("Putting %d in register %02x\n",			       val, 0x2f + j);			__t1_framer_out(wc, 0x2f + j, val);			val = 0;		}	}}static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data){	struct t4_regs regs;	int x;	struct t1 *wc;	switch(cmd) {	case WCT4_GET_REGS:		wc = chan->pvt;		for (x=0;x<NUM_PCI;x++)#if 1			regs.pci[x] = (inb(wc->ioaddr + (x << 2))) |				       (inb(wc->ioaddr + (x << 2) + 1) << 8) |					(inb(wc->ioaddr + (x << 2) + 2) << 16) |					 (inb(wc->ioaddr + (x << 2) + 3) << 24);#else			regs.pci[x] = (inb(wc->ioaddr + x));#endif		for (x=0;x<NUM_REGS;x++)			regs.regs[x] = t1_framer_in(wc, x);		if (copy_to_user((struct t4_regs *)data, &regs, sizeof(regs)))			return -EFAULT;		break;	default:		return -ENOTTY;	}	return 0;}static int t1xxp_maint(struct zt_span *span, int cmd){	struct t1 *wc = span->pvt;	if (wc->spantype == 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("TE110P: 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:			t1_framer_out(wc, 0x21, 0x50);	/* FMR5: Nothing but RBS mode */			break;	    case ZT_MAINT_LOOPDOWN:			t1_framer_out(wc, 0x21, 0x60);	/* FMR5: Nothing but RBS mode */			break;	    case ZT_MAINT_LOOPSTOP:			t1_framer_out(wc, 0x21, 0x40);	/* FMR5: Nothing but RBS mode */			break;	    default:			printk("TE110P: Unknown T1 maint command: %d\n", cmd);			break;	   }    }	return 0;}static int t1xxp_rbsbits(struct zt_chan *chan, int bits){	u_char m,c;	int n,b;	struct t1 *wc = chan->pvt;	unsigned long flags;		if(debug > 1) printk("Setting bits to %d on channel %s\n", bits, chan->name);	spin_lock_irqsave(&wc->lock, flags);		if (wc->spantype == TYPE_E1) { /* do it E1 way */		if (chan->chanpos == 16) {			spin_unlock_irqrestore(&wc->lock, flags);			return 0;		}		n = chan->chanpos - 1;		if (chan->chanpos > 15) n--;		b = (n % 15);		c = wc->txsigs[b];		m = (n / 15) << 2; /* nibble selector */		c &= (0xf << m); /* keep the other nibble */		c |= (bits & 0xf) << (4 - m); /* put our new nibble here */		wc->txsigs[b] = c;		  /* output them to the chip */		__t1_framer_out(wc,0x71 + b,c); 	} else if (wc->span.lineconfig & ZT_CONFIG_D4) {		n = chan->chanpos - 1;		b = (n/4);		c = wc->txsigs[b];		m = ((3 - (n % 4)) << 1); /* nibble selector */		c &= ~(0x3 << m); /* keep the other nibble */		c |= ((bits >> 2) & 0x3) << m; /* put our new nibble here */		wc->txsigs[b] = c;		  /* output them to the chip */		__t1_framer_out(wc,0x70 + b,c); 

⌨️ 快捷键说明

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