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

📄 wcfxs.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 5 页
字号:
	wc->span.ioctl = wcfxs_ioctl;	wc->span.watchdog = wcfxs_watchdog;	init_waitqueue_head(&wc->span.maintq);	wc->span.pvt = wc;	if (zt_register(&wc->span, 0)) {		printk("Unable to register span with zaptel\n");		return -1;	}	return 0;}static void wcfxs_post_initialize(struct wcfxs *wc){	int x;	/* Finalize signalling  */	for (x=0;x<wc->cards;x++) {		if (wc->cardflag & (1 << x)) {			if (wc->modtype[x] == MOD_TYPE_FXO)				wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;			else				wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM;		}	}}static int wcfxs_hardware_init(struct wcfxs *wc){	/* Hardware stuff */	unsigned char ver;	unsigned char x,y;	int failed;	/* Signal Reset */	outb(0x01, wc->ioaddr + WC_CNTL);	/* Check Freshmaker chip */	x=inb(wc->ioaddr + WC_CNTL);	ver = __wcfxs_getcreg(wc, WC_VER);	failed = 0;	if (ver != 0x59) {		printk("Freshmaker version: %02x\n", ver);		for (x=0;x<255;x++) {			/* Test registers */			if (ver >= 0x70) {				__wcfxs_setcreg(wc, WC_CS, x);				y = __wcfxs_getcreg(wc, WC_CS);			} else {				__wcfxs_setcreg(wc, WC_TEST, x);				y = __wcfxs_getcreg(wc, WC_TEST);			}			if (x != y) {				printk("%02x != %02x\n", x, y);				failed++;			}		}		if (!failed) {			printk("Freshmaker passed register test\n");		} else {			printk("Freshmaker failed register test\n");			return -1;		}		/* Go to half-duty FSYNC */		__wcfxs_setcreg(wc, WC_SYNC, 0x01);		y = __wcfxs_getcreg(wc, WC_SYNC);	} else {		printk("No freshmaker chip\n");	}	/* Reset PCI Interface chip and registers (and serial) */	outb(0x06, wc->ioaddr + WC_CNTL);	/* Setup our proper outputs for when we switch for our "serial" port */	wc->ios = BIT_CS | BIT_SCLK | BIT_SDI;	outb(wc->ios, wc->ioaddr + WC_AUXD);	/* Set all to outputs except AUX 5, which is an input */	outb(0xdf, wc->ioaddr + WC_AUXC);	/* Select alternate function for AUX0 */	outb(0x4, wc->ioaddr + WC_AUXFUNC);		/* Wait 1/4 of a sec */	wait_just_a_bit(HZ/4);	/* Back to normal, with automatic DMA wrap around */	outb(0x30 | 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 */	outb(0xc1, wc->ioaddr + WC_SERCTL);	/* Delay FSC by 0 so it's properly aligned */	outb(0x0, wc->ioaddr + WC_FSCDELAY);	/* Setup DMA Addresses */	outl(wc->writedma,                    wc->ioaddr + WC_DMAWS);		/* Write start */	outl(wc->writedma + ZT_CHUNKSIZE * 4 - 4, wc->ioaddr + WC_DMAWI);		/* Middle (interrupt) */	outl(wc->writedma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWE);			/* End */		outl(wc->readdma,                    	 wc->ioaddr + WC_DMARS);	/* Read start */	outl(wc->readdma + ZT_CHUNKSIZE * 4 - 4, 	 wc->ioaddr + WC_DMARI);	/* Middle (interrupt) */	outl(wc->readdma + ZT_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMARE);	/* End */		/* Clear interrupts */	outb(0xff, wc->ioaddr + WC_INTSTAT);	/* Wait 1/4 of a second more */	wait_just_a_bit(HZ/4);	for (x=0;x<wc->cards;x++) {		int sane=0,ret=0,readi=0;#if 1		/* Init with Auto Calibration */		if (!(ret=wcfxs_init_proslic(wc, x, 0, 0, sane))) {			wc->cardflag |= (1 << x);                        if (debug) {                                readi = wcfxs_getreg(wc,x,LOOP_I_LIMIT);                                printk("Proslic module %d loop current is %dmA\n",x,                                ((readi*3)+20));                        }			printk("Module %d: Installed -- AUTO FXS/DPO\n",x);		} else {			if(ret!=-2) {				sane=1;				/* Init with Manual Calibration */				if (!wcfxs_init_proslic(wc, x, 0, 1, sane)) {					wc->cardflag |= (1 << x);                                if (debug) {                                        readi = wcfxs_getreg(wc,x,LOOP_I_LIMIT);                                        printk("Proslic module %d loop current is %dmA\n",x,                                        ((readi*3)+20));                                }					printk("Module %d: Installed -- MANUAL FXS\n",x);				} else {					printk("Module %d: FAILED FXS (%s)\n", x, fxshonormode ? fxo_modes[_opermode].name : "FCC");				} 			} else if (!(ret = wcfxs_init_voicedaa(wc, x, 0, 0, sane))) {				wc->cardflag |= (1 << x);				printk("Module %d: Installed -- AUTO FXO (%s mode)\n",x, fxo_modes[_opermode].name);			} else				printk("Module %d: Not installed\n", x);		}#endif	}	/* Return error if nothing initialized okay. */	if (!wc->cardflag && !timingonly)		return -1;	__wcfxs_setcreg(wc, WC_SYNC, (wc->cardflag << 1) | 0x1);	return 0;}static void wcfxs_enable_interrupts(struct wcfxs *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 wcfxs_restart_dma(struct wcfxs *wc){	/* Reset Master and TDM */	outb(0x01, wc->ioaddr + WC_CNTL);	outb(0x01, wc->ioaddr + WC_OPER);}static void wcfxs_start_dma(struct wcfxs *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 wcfxs_stop_dma(struct wcfxs *wc){	outb(0x00, wc->ioaddr + WC_OPER);}static void wcfxs_reset_tdm(struct wcfxs *wc){	/* Reset TDM */	outb(0x0f, wc->ioaddr + WC_CNTL);}static void wcfxs_disable_interrupts(struct wcfxs *wc)	{	outb(0x00, wc->ioaddr + WC_MASK0);	outb(0x00, wc->ioaddr + WC_MASK1);}static int __devinit wcfxs_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	int res;	struct wcfxs *wc;	struct wcfxs_desc *d = (struct wcfxs_desc *)ent->driver_data;	int x;	static int initd_ifaces=0;		if(initd_ifaces){		memset((void *)ifaces,0,(sizeof(struct wcfxs *))*WC_MAX_IFACES);		initd_ifaces=1;	}	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 wcfxs), GFP_KERNEL);		if (wc) {			ifaces[x] = wc;			memset(wc, 0, sizeof(struct wcfxs));			spin_lock_init(&wc->lock);			wc->curcard = -1;			wc->cards = 4;			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, "wcfxs")) 				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("wcfxs: Unable to allocate DMA-able memory\n");				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				return -ENOMEM;			}			wc->readchunk = wc->writechunk + ZT_MAX_CHUNKSIZE * 2;	/* in doublewords */			wc->readdma = wc->writedma + ZT_MAX_CHUNKSIZE * 8;		/* in bytes */			if (wcfxs_initialize(wc)) {				printk("wcfxs: Unable to intialize FXS\n");				/* Set Reset Low */				x=inb(wc->ioaddr + WC_CNTL);				outb((~0x1)&x, wc->ioaddr + WC_CNTL);				/* Free Resources */				free_irq(pdev->irq, wc);				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);				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, wcfxs_interrupt, SA_SHIRQ, "wctdm", wc)) {				printk("wcfxs: Unable to request IRQ %d\n", pdev->irq);				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);				pci_set_drvdata(pdev, NULL);				kfree(wc);				return -EIO;			}			if (wcfxs_hardware_init(wc)) {				unsigned char x;				/* Set Reset Low */				x=inb(wc->ioaddr + WC_CNTL);				outb((~0x1)&x, wc->ioaddr + WC_CNTL);				/* Free Resources */				free_irq(pdev->irq, wc);				if (wc->freeregion)					release_region(wc->ioaddr, 0xff);				pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma);				pci_set_drvdata(pdev, NULL);				zt_unregister(&wc->span);				kfree(wc);				return -EIO;			}			wcfxs_post_initialize(wc);			/* Enable interrupts */			wcfxs_enable_interrupts(wc);			/* Initialize Write/Buffers to all blank data */			memset((void *)wc->writechunk,0,ZT_MAX_CHUNKSIZE * 2 * 2 * 4);			/* Start DMA */			wcfxs_start_dma(wc);			printk("Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->cards);			res = 0;		} else			res = -ENOMEM;	}	return res;}static void wcfxs_release(struct wcfxs *wc){	zt_unregister(&wc->span);	if (wc->freeregion)		release_region(wc->ioaddr, 0xff);	kfree(wc);	printk("Freed a Wildcard\n");}static void __devexit wcfxs_remove_one(struct pci_dev *pdev){	struct wcfxs *wc = pci_get_drvdata(pdev);	if (wc) {		/* Stop any DMA */		wcfxs_stop_dma(wc);		wcfxs_reset_tdm(wc);		/* In case hardware is still there */		wcfxs_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)			wcfxs_release(wc);		else			wc->dead = 1;	}}static struct pci_device_id wcfxs_pci_tbl[] = {	{ 0xe159, 0x0001, 0xa159, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxs },	{ 0xe159, 0x0001, 0xe159, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxs },	{ 0xe159, 0x0001, 0xb100, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxse },	{ 0xe159, 0x0001, 0xa9fd, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },	{ 0xe159, 0x0001, 0xa8fd, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },	{ 0xe159, 0x0001, 0xa800, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },	{ 0xe159, 0x0001, 0xa801, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },	{ 0xe159, 0x0001, 0xa908, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },	{ 0xe159, 0x0001, 0xa901, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },#ifdef TDM_REVH_MATCHALL        { 0xe159, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &wcfxsh },#endif	{ 0 }};MODULE_DEVICE_TABLE(pci, wcfxs_pci_tbl);static struct pci_driver wcfxs_driver = {	name: 	"wcfxs",	probe: 	wcfxs_init_one,#ifdef LINUX26	remove:	__devexit_p(wcfxs_remove_one),#else	remove:	wcfxs_remove_one,#endif	suspend: NULL,	resume:	NULL,	id_table: wcfxs_pci_tbl,};static int __init wcfxs_init(void){	int res;	int x;	for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {		if (!strcmp(fxo_modes[x].name, opermode))			break;	}	if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {		_opermode = x;	} else {		printk("Invalid/unknown operating mode '%s' specified.  Please choose one of:\n", opermode);		for (x=0;x<sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)			printk("  %s\n", fxo_modes[x].name);		printk("Note this option is CASE SENSITIVE!\n");		return -ENODEV;	}	res = pci_module_init(&wcfxs_driver);	if (res)		return -ENODEV;	return 0;}static void __exit wcfxs_cleanup(void){	pci_unregister_driver(&wcfxs_driver);}#ifdef LINUX26module_param(debug, int, 0600);module_param(loopcurrent, int, 0600);module_param(robust, int, 0600);module_param(_opermode, int, 0600);module_param(opermode, charp, 0600);module_param(timingonly, int, 0600);module_param(lowpower, int, 0600);module_param(boostringer, int, 0600);module_param(fxshonormode, int, 0600);#elseMODULE_PARM(debug, "i");MODULE_PARM(loopcurrent, "i");MODULE_PARM(robust, "i");MODULE_PARM(_opermode, "i");MODULE_PARM(opermode, "s");MODULE_PARM(timingonly, "i");MODULE_PARM(lowpower, "i");MODULE_PARM(boostringer, "i");MODULE_PARM(fxshonormode, "i");#endifMODULE_DESCRIPTION("Wildcard TDM400P Zaptel Driver");MODULE_AUTHOR("Mark Spencer <markster@digium.com>");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifmodule_init(wcfxs_init);module_exit(wcfxs_cleanup);

⌨️ 快捷键说明

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