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

📄 wcfxo.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (wc->battdebounce)			wc->battdebounce--;#ifdef	JAPAN		if (wc->ohdebounce)			wc->ohdebounce--;#endif	}#ifdef LINUX26	return IRQ_RETVAL(1);#endif		}static int wcfxo_setreg(struct wcfxo *wc, unsigned char reg, unsigned char value){	int x;	if (wc->wregcount < ZT_CHUNKSIZE) {		x = wc->wregcount;		wc->regs[x].reg = reg;		wc->regs[x].value = value;		wc->regs[x].flags = FLAG_WRITE;		wc->wregcount++;		return 0;	}	printk("wcfxo: Out of space to write register %02x with %02x\n", reg, value);	return -1;}static int wcfxo_open(struct zt_chan *chan){	struct wcfxo *wc = chan->pvt;	if (wc->dead)		return -ENODEV;	wc->usecount++;#ifndef LINUX26	MOD_INC_USE_COUNT;#endif		return 0;}static int wcfxo_watchdog(struct zt_span *span, int event){	printk("FXO: Restarting DMA\n");	wcfxo_restart_dma(span->pvt);	return 0;}static int wcfxo_close(struct zt_chan *chan){	struct wcfxo *wc = chan->pvt;	wc->usecount--;#ifndef LINUX26	MOD_DEC_USE_COUNT;#endif	/* If we're dead, release us now */	if (!wc->usecount && wc->dead)		wcfxo_release(wc);	return 0;}static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig){	struct wcfxo *wc = chan->pvt;	int reg=0;	switch(txsig) {	case ZT_TXSIG_START:	case ZT_TXSIG_OFFHOOK:		/* Take off hook and enable normal mode reception.  This must		   be done in two steps because of a hardware bug. */		reg = wc->readregs[0x5] & ~0x08;		wcfxo_setreg(wc, 0x5, reg);		reg = reg | 0x1;		wcfxo_setreg(wc, 0x5, reg);		wc->offhook = 1;#ifdef	JAPAN		wc->battery = 1;		wc->battdebounce = BATT_DEBOUNCE;		wc->ohdebounce = OH_DEBOUNCE;#endif		break;	case ZT_TXSIG_ONHOOK:		/* Put on hook and enable on hook line monitor */		reg =  wc->readregs[0x5] & 0xfe;		wcfxo_setreg(wc, 0x5, reg);		reg = reg | 0x08;		wcfxo_setreg(wc, 0x5, reg);		wc->offhook = 0;		/* Don't accept a ring for another 1000 ms */		wc->ringdebounce = 1000;#ifdef	JAPAN		wc->ohdebounce = OH_DEBOUNCE;#endif		break;	default:		printk("wcfxo: Can't set tx state to %d\n", txsig);	}	if (debug)		printk("Setting hook state to %d (%02x)\n", txsig, reg);	return 0;}static int wcfxo_initialize(struct wcfxo *wc){	/* Zapata stuff */	sprintf(wc->span.name, "WCFXO/%d", wc->pos);	sprintf(wc->span.desc, "%s Board %d", wc->variety, wc->pos + 1);	sprintf(wc->chan.name, "WCFXO/%d/%d", wc->pos, 0);	wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;	wc->chan.chanpos = 1;	wc->span.chans = &wc->chan;	wc->span.channels = 1;	wc->span.hooksig = wcfxo_hooksig;	wc->span.open = wcfxo_open;	wc->span.close = wcfxo_close;	wc->span.flags = ZT_FLAG_RBS;	wc->span.deflaw = ZT_LAW_MULAW;	wc->span.watchdog = wcfxo_watchdog;#ifdef ENABLE_TASKLETS	tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);#endif	init_waitqueue_head(&wc->span.maintq);	wc->span.pvt = wc;	wc->chan.pvt = wc;	if (zt_register(&wc->span, 0)) {		printk("Unable to register span with zaptel\n");		return -1;	}	return 0;}static int wcfxo_hardware_init(struct wcfxo *wc){	/* Hardware stuff */	/* Reset PCI Interface chip and registers */	outb(0x0e, wc->ioaddr + WC_CNTL);	if (wc->flags & FLAG_RESET_ON_AUX5) {		/* Set hook state to on hook for when we switch.		   Make sure reset is high */		outb(0x34, wc->ioaddr + WC_AUXD);	} else {		/* Set hook state to on hook for when we switch */		outb(0x24, wc->ioaddr + WC_AUXD);	}	/* Set all to outputs except AUX 4, which is an input */	outb(0xef, wc->ioaddr + WC_AUXC);	/* Back to normal, with automatic DMA wrap around */	outb(0x01, wc->ioaddr + WC_CNTL);	/* Make sure serial port and DMA are out of reset */	outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL);	/* Configure serial port for MSB->LSB operation */	if (wc->flags & FLAG_DOUBLE_CLOCK)		outb(0xc1, wc->ioaddr + WC_SERCTL);	else		outb(0xc0, wc->ioaddr + WC_SERCTL);	if (wc->flags & FLAG_USE_XTAL) {		/* Use the crystal oscillator */		outb(0x04, wc->ioaddr + WC_AUXFUNC);	}	/* Delay FSC by 2 so it's properly aligned */	outb(0x2, wc->ioaddr + WC_FSCDELAY);	/* Setup DMA Addresses */	outl(wc->writedma,                    wc->ioaddr + WC_DMAWS);		/* Write start */	outl(wc->writedma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWI);		/* Middle (interrupt) */	outl(wc->writedma + ZT_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMAWE);			/* End */		outl(wc->readdma,                    	 wc->ioaddr + WC_DMARS);	/* Read start */	outl(wc->readdma + ZT_CHUNKSIZE * 8 - 4, 	 wc->ioaddr + WC_DMARI);	/* Middle (interrupt) */	outl(wc->readdma + ZT_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMARE);	/* End */		/* Clear interrupts */	outb(0xff, wc->ioaddr + WC_INTSTAT);	return 0;}static void wcfxo_enable_interrupts(struct wcfxo *wc){	/* Enable interrupts (we care about all of them) */	outb(0x3f, wc->ioaddr + WC_MASK0);	/* No external interrupts */	outb(0x00, wc->ioaddr + WC_MASK1);}static void wcfxo_start_dma(struct wcfxo *wc){	/* Reset Master and TDM */	outb(0x0f, wc->ioaddr + WC_CNTL);	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(1);	outb(0x01, wc->ioaddr + WC_CNTL);	outb(0x01, wc->ioaddr + WC_OPER);}static void wcfxo_restart_dma(struct wcfxo *wc){	/* Reset Master and TDM */	outb(0x01, wc->ioaddr + WC_CNTL);	outb(0x01, wc->ioaddr + WC_OPER);}static void wcfxo_stop_dma(struct wcfxo *wc){	outb(0x00, wc->ioaddr + WC_OPER);}static void wcfxo_reset_tdm(struct wcfxo *wc){	/* Reset TDM */	outb(0x0f, wc->ioaddr + WC_CNTL);}static void wcfxo_disable_interrupts(struct wcfxo *wc)	{	outb(0x00, wc->ioaddr + WC_MASK0);	outb(0x00, wc->ioaddr + WC_MASK1);}static int wcfxo_set_daa_mode(struct wcfxo *wc){	/* Set country specific parameters (OHS, ACT, DCT, RZ, RT, LIM, VOL) */	int reg16 = ((fxo_modes[opermode].ohs & 0x1) << 6) |				((fxo_modes[opermode].act & 0x1) << 5) |				((fxo_modes[opermode].dct & 0x3) << 2) |				((fxo_modes[opermode].rz & 0x1) << 1) |				((fxo_modes[opermode].rt & 0x1) << 0);	int reg17 = ((fxo_modes[opermode].lim & 0x3) << 3);	int reg18 = ((fxo_modes[opermode].vol & 0x3) << 3);	wcfxo_setreg(wc, 0x16, reg16);	wcfxo_setreg(wc, 0x17, reg17);	wcfxo_setreg(wc, 0x18, reg18);	/* Wait a couple of jiffies for our writes to finish */	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);	printk("wcfxo: DAA mode is '%s'\n", fxo_modes[opermode].name);	return 0;}static int wcfxo_init_daa(struct wcfxo *wc){	/* This must not be called in an interrupt */	/* We let things settle for a bit */	unsigned char reg15;//	set_current_state(TASK_INTERRUPTIBLE);//	schedule_timeout(10);	/* Soft-reset it */	wcfxo_setreg(wc, 0x1, 0x80);	/* Let the reset go */	set_current_state(TASK_UNINTERRUPTIBLE);	schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);	/* We have a clock at 18.432 Mhz, so N1=1, M1=2, CGM=0 */	wcfxo_setreg(wc, 0x7, 0x0);	/* This value is N1 - 1 */	wcfxo_setreg(wc, 0x8, 0x1);	/* This value is M1 - 1 */	/* We want to sample at 8khz, so N2 = 9, M2 = 10 (N2-1, M2-1) */	wcfxo_setreg(wc, 0x9, 0x89);		/* Wait until the PLL's are locked. Time is between 100 uSec and 1 mSec */	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(1 + HZ/1000 + (ZT_CHUNKSIZE * HZ) / 800);	/* No additional ration is applied to the PLL and faster lock times	 * are possible */	wcfxo_setreg(wc, 0xa, 0x0);	/* Enable off hook pin */	wcfxo_setreg(wc, 0x5, 0x0a);	if (monitor) {		/* Enable ISOcap and external speaker and charge pump if present */		wcfxo_setreg(wc, 0x6, 0x80);	} else {		/* Enable ISOcap and charge pump if present (leave speaker disabled) */		wcfxo_setreg(wc, 0x6, 0xe0);	}	/* Wait a couple of jiffies for our writes to finish */	set_current_state(TASK_INTERRUPTIBLE);	schedule_timeout(1 + (ZT_CHUNKSIZE * HZ) / 800);	reg15 = 0x0;	/* Go ahead and attenuate transmit signal by 6 db */	if (quiet) {		printk("wcfxo: Attenuating transmit signal for quiet operation\n");		reg15 |= (quiet & 0x3) << 4;	}	if (boost) {		printk("wcfxo: Boosting receive signal\n");		reg15 |= (boost & 0x3);	}	wcfxo_setreg(wc, 0xf, reg15);	/* Didn't get it right.  Register 9 is still garbage */	if (wc->readregs[0x9] != 0x89)		return -1;#if 0	{ int x;	int y;	for (y=0;y<100;y++) {		printk(" reg dump ====== %d ======\n", y);		for (x=0;x<sizeof(wecareregs) / sizeof(wecareregs[0]);x++) {			printk("daa: Reg %d: %02x\n", wecareregs[x], wc->readregs[wecareregs[x]]);		}		set_current_state(TASK_INTERRUPTIBLE);		schedule_timeout(100);	} }#endif		return 0;}static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	int res;	struct wcfxo *wc;	struct wcfxo_desc *d = (struct wcfxo_desc *)ent->driver_data;	int x;	for (x=0;x<WC_MAX_IFACES;x++)		if (!ifaces[x]) break;	if (x >= WC_MAX_IFACES) {		printk("Too many interfaces\n");		return -EIO;	}		if (pci_enable_device(pdev)) {		res = -EIO;	} else {		wc = kmalloc(sizeof(struct wcfxo), GFP_KERNEL);		if (wc) {			ifaces[x] = wc;			memset(wc, 0, sizeof(struct wcfxo));			wc->ioaddr = pci_resource_start(pdev, 0);			wc->dev = pdev;			wc->pos = x;			wc->variety = d->name;			wc->flags = d->flags;			/* Keep track of whether we need to free the region */			if (request_region(wc->ioaddr, 0xff, "wcfxo")) 				wc->freeregion = 1;			/* Allocate enough memory for two zt chunks, receive and transmit.  Each sample uses			   32 bits.  Allocate an extra set just for control too */			wc->writechunk = (int *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &wc->writedma);			if (!wc->writechunk) {				printk("wcfxo: Unable to allocate DMA-able memory\n");				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				return -ENOMEM;			}			wc->readchunk = wc->writechunk + ZT_MAX_CHUNKSIZE * 4;	/* in doublewords */			wc->readdma = wc->writedma + ZT_MAX_CHUNKSIZE * 16;		/* in bytes */			if (wcfxo_initialize(wc)) {				printk("wcfxo: Unable to intialize modem\n");				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				kfree(wc);				return -EIO;			}			/* Enable bus mastering */			pci_set_master(pdev);			/* Keep track of which device we are */			pci_set_drvdata(pdev, wc);			if (request_irq(pdev->irq, wcfxo_interrupt, SA_SHIRQ, "wcfxo", wc)) {				printk("wcfxo: Unable to request IRQ %d\n", pdev->irq);				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				kfree(wc);				return -EIO;			}			wcfxo_hardware_init(wc);			/* Enable interrupts */			wcfxo_enable_interrupts(wc);			/* Initialize Write/Buffers to all blank data */			memset((void *)wc->writechunk,0,ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4);			/* Start DMA */			wcfxo_start_dma(wc);			/* Initialize DAA (after it's started) */			if (wcfxo_init_daa(wc)) {				printk("Failed to initailize DAA, giving up...\n");				wcfxo_stop_dma(wc);				wcfxo_disable_interrupts(wc);				zt_unregister(&wc->span);				free_irq(pdev->irq, wc);				/* Reset PCI chip and registers */				outb(0x0e, wc->ioaddr + WC_CNTL);								if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				kfree(wc);				return -EIO;			}			wcfxo_set_daa_mode(wc);			printk("Found a Wildcard FXO: %s\n", wc->variety);			res = 0;		} else			res = -ENOMEM;	}	return res;}static void wcfxo_release(struct wcfxo *wc){	zt_unregister(&wc->span);	if (wc->freeregion)		release_region(wc->ioaddr, 0xff);	kfree(wc);	printk("Freed a Wildcard\n");}static void __devexit wcfxo_remove_one(struct pci_dev *pdev){	struct wcfxo *wc = pci_get_drvdata(pdev);	if (wc) {		/* Stop any DMA */		wcfxo_stop_dma(wc);		wcfxo_reset_tdm(wc);		/* In case hardware is still there */		wcfxo_disable_interrupts(wc);				/* Immediately free resources */		pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);		free_irq(pdev->irq, wc);		/* Reset PCI chip and registers */		outb(0x0e, wc->ioaddr + WC_CNTL);		/* Release span, possibly delayed */		if (!wc->usecount)			wcfxo_release(wc);		else			wc->dead = 1;	}}static struct pci_device_id wcfxo_pci_tbl[] = {	{ 0xe159, 0x0001, 0x8085, PCI_ANY_ID, 0, 0, (unsigned long) &wcx101p },	{ 0xe159, 0x0001, 0x8086, PCI_ANY_ID, 0, 0, (unsigned long) &generic },	{ 0xe159, 0x0001, 0x8087, PCI_ANY_ID, 0, 0, (unsigned long) &generic },	{ 0x1057, 0x5608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcx100p },	{ 0 }};MODULE_DEVICE_TABLE (pci, wcfxo_pci_tbl);static struct pci_driver wcfxo_driver = {	name: 	"wcfxo",	probe: 	wcfxo_init_one,#ifdef LINUX26	remove:	__devexit_p(wcfxo_remove_one),#else	remove:	wcfxo_remove_one,#endif	id_table: wcfxo_pci_tbl,};static int __init wcfxo_init(void){	int res;	int x;	if ((opermode >= sizeof(fxo_modes) / sizeof(fxo_modes[0])) || (opermode < 0)) {		printk("Invalid/unknown operating mode specified.  Please choose one of:\n");		for (x=0;x<sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)			printk("%d: %s\n", x, fxo_modes[x].name);		return -ENODEV;	}	res = pci_module_init(&wcfxo_driver);	if (res)		return -ENODEV;	return 0;}static void __exit wcfxo_cleanup(void){	pci_unregister_driver(&wcfxo_driver);}#ifdef LINUX26module_param(debug, int, 0600);module_param(quiet, int, 0600);module_param(boost, int, 0600);module_param(monitor, int, 0600);module_param(opermode, int, 0600);#elseMODULE_PARM(debug, "i");MODULE_PARM(quiet, "i");MODULE_PARM(boost, "i");MODULE_PARM(monitor, "i");MODULE_PARM(opermode, "i");#endifMODULE_DESCRIPTION("Wildcard X100P Zaptel Driver");MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifmodule_init(wcfxo_init);module_exit(wcfxo_cleanup);

⌨️ 快捷键说明

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