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

📄 wct1xxp.c

📁 This a SOFTWARE pbx DRIVER
💻 C
📖 第 1 页 / 共 3 页
字号:
			}		} 	}	/* Store the next canary */	canary = (unsigned int *)(rxbuf + ZT_CHUNKSIZE * 32 - 4);	*canary = (wc->canary++) | (CANARY << 16);	for (x=0;x<wc->span.channels;x++) {		zt_ec_chunk(&wc->chans[x], wc->chans[x].readchunk, 			wc->ec_chunk2[x]);		memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],ZT_CHUNKSIZE);		memcpy(wc->ec_chunk1[x],wc->chans[x].writechunk,ZT_CHUNKSIZE);	}	zt_receive(&wc->span);}static void __t1xxp_check_sigbits(struct t1xxp *wc, int x){	int a,b,i,y,rxs;	if (wc->ise1) {		/* Read 5 registers at a time, loading 10 channels at a time */		for (i = (x * 5); i < (x * 5) + 5; i++) {			a = __t1_get_reg(wc, 0x31 + i);			/* Get high channel in low bits */			rxs = (a & 0xf);			if (!(wc->chans[i+16].sig & ZT_SIG_CLEAR)) {				if (wc->chans[i+16].rxsig != rxs)					zt_rbsbits(&wc->chans[i+16], rxs);			}			rxs = (a >> 4) & 0xf;			if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {				if (wc->chans[i].rxsig != rxs)					zt_rbsbits(&wc->chans[i], rxs);			}		}	} else {		a = __t1_get_reg(wc, 0x60 + x);		b = __t1_get_reg(wc, 0x63 + x);		for (y=0;y<8;y++) {			i = x * 8 + y;				rxs = 0;			if (a & (1 << y))				rxs |= ZT_ABIT;			if (b & (1 << y))				rxs |= ZT_BBIT;			if (!(wc->chans[i].sig & ZT_SIG_CLEAR)) {				if (wc->chans[i].rxsig != rxs)					zt_rbsbits(&wc->chans[i], rxs);			}		}	}}static void __t1xxp_check_alarms(struct t1xxp *wc){	unsigned char c,d;	int alarms;	int x,j;	if (wc->ise1) {		__t1_set_reg(wc, 0x06, 0xff); 		c = __t1_get_reg(wc, 0x6);	} else {		/* Get RIR2 */		c = __t1_get_reg(wc, 0x31);		wc->span.rxlevel = c >> 6;			/* Get status register s*/		__t1_set_reg(wc, 0x20, 0xff); 		c = __t1_get_reg(wc, 0x20); 	}	/* Assume no alarms */	alarms = 0;	/* And consider only carrier alarms */	wc->span.alarms &= (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_NOTOPEN);	if (wc->ise1) {		/* XXX Implement me XXX */	} else {		/* Detect loopup code if we're not sending one */		if ((!wc->span.mainttimer) && (c & 0x80)) {			/* Loop-up code detected */			if ((wc->loopupcnt++ > 80)  && (wc->span.maintstat != ZT_MAINT_REMOTELOOP)) {				__t1_set_reg(wc, 0x1e, 0);	/* No local loop */				__t1_set_reg(wc, 0x0a, 0x40);	/* Remote Loop */				wc->span.maintstat = ZT_MAINT_REMOTELOOP;			}		} else {			wc->loopupcnt = 0;		}		/* Same for loopdown code */		if ((!wc->span.mainttimer) && (c & 0x40)) {			/* Loop-down code detected */			if ((wc->loopdowncnt++ > 80)  && (wc->span.maintstat == ZT_MAINT_REMOTELOOP)) {				__t1_set_reg(wc, 0x1e, 0);	/* No local loop */				__t1_set_reg(wc, 0x0a, 0x0);	/* No remote Loop */				wc->span.maintstat = ZT_MAINT_NONE;			}		} else			wc->loopdowncnt = 0;	}	if (wc->span.lineconfig & ZT_CONFIG_NOTOPEN) {		for (x=0,j=0;x < wc->span.channels;x++)			if ((wc->chans[x].flags & ZT_FLAG_OPEN) ||			    (wc->chans[x].flags & ZT_FLAG_NETDEV))				j++;		if (!j)			alarms |= ZT_ALARM_NOTOPEN;	}	if (wc->ise1) {		if (c & 0x9) 			alarms |= ZT_ALARM_RED;		if (c & 0x2)			alarms |= ZT_ALARM_BLUE;	} else {		/* Check actual alarm status */		if (c & 0x3) 			alarms |= ZT_ALARM_RED;		if (c & 0x8)			alarms |= ZT_ALARM_BLUE;	}	/* Keep track of recovering */	if ((!alarms) && wc->span.alarms)		wc->alarmtimer = ZT_ALARMSETTLE_TIME;	/* If receiving alarms, go into Yellow alarm state */	if (alarms && (!wc->span.alarms)) {#if 0		printk("Going into yellow alarm\n");#endif		if (wc->ise1)			__t1_set_reg(wc, 0x21, 0x7f); 		else			__t1_set_reg(wc, 0x35, 0x11); 	}	if (wc->span.alarms != alarms) {		d = __control_get_reg(wc, WC_CLOCK); 		start_alarm(wc);		if (!(alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&		    wc->sync) {			/* Use the recieve signalling */			wc->span.syncsrc = wc->span.spanno;			d |= 1;		} else {			wc->span.syncsrc = 0;			d &= ~1;		}		__control_set_reg(wc, WC_CLOCK, d);  	}	if (wc->alarmtimer)		alarms |= ZT_ALARM_RECOVER;	if (c & 0x4)		alarms |= ZT_ALARM_YELLOW;	wc->span.alarms = alarms;	zt_alarm_notify(&wc->span);}static void __t1xxp_do_counters(struct t1xxp *wc){	if (wc->alarmtimer) {		if (!--wc->alarmtimer) {			wc->span.alarms &= ~(ZT_ALARM_RECOVER);			/* Clear yellow alarm */#if 0			printk("Coming out of alarm\n");#endif			if (wc->ise1)				__t1_set_reg(wc, 0x21, 0x5f);			else				__t1_set_reg(wc, 0x35, 0x10);			zt_alarm_notify(&wc->span);		}	}}#ifdef LINUX26static irqreturn_t t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs)#elsestatic void t1xxp_interrupt(int irq, void *dev_id, struct pt_regs *regs)#endif{	struct t1xxp *wc = dev_id;	unsigned char ints;	unsigned long flags;	int x;	ints = inb(wc->ioaddr + WC_INTSTAT);	outb(ints, wc->ioaddr + WC_INTSTAT);	if (!ints)#ifdef LINUX26		return IRQ_NONE;#else		return;#endif			if (!wc->intcount) {		if (debug) printk("Got interrupt: 0x%04x\n", ints);	}	wc->intcount++;	if (wc->clocktimeout && !--wc->clocktimeout) 		control_set_reg(wc, WC_CLOCK, 0x00 | wc->sync | wc->ise1);	if (ints & 0x0f) {		t1xxp_receiveprep(wc, ints);		t1xxp_transmitprep(wc, ints);	}	spin_lock_irqsave(&wc->lock, flags);#if 1	__handle_leds(wc);#endif	/* Count down timers */	__t1xxp_do_counters(wc);	/* Do some things that we don't have to do very often */	x = wc->intcount & 15 /* 63 */;	switch(x) {	case 0:	case 1:	case 2:		__t1xxp_check_sigbits(wc, x);		break;	case 4:		/* Check alarms 1/4 as frequently */		if (!(wc->intcount & 0x30))			__t1xxp_check_alarms(wc);		break;	}		spin_unlock_irqrestore(&wc->lock, flags);	if (ints & 0x10) 		printk("PCI Master abort\n");	if (ints & 0x20)		printk("PCI Target abort\n");#ifdef LINUX26	return IRQ_RETVAL(1);#endif		}static int t1xxp_hardware_init(struct t1xxp *wc){	/* Hardware PCI stuff */	/* Reset chip and registers */	outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);	/* Set all outputs to 0 */	outb(0x00, wc->ioaddr + WC_AUXD);	/* Set all to outputs except AUX1 (TDO). */	outb(0xfd, wc->ioaddr + WC_AUXC);	/* Configure the serial port: double clock, 20ns width, no inversion,	   MSB first */	outb(0xc8, wc->ioaddr + WC_SERC);	/* Internally delay FSC by one */	outb(0x01, wc->ioaddr + WC_FSCDELAY);	/* Back to normal, with automatic DMA wrap around */	outb(DELAY | 0x01, wc->ioaddr + WC_CNTL);		/* Make sure serial port and DMA are out of reset */	outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, WC_CNTL);		/* Setup DMA Addresses */	/* Start at writedma */	outl(wc->writedma,                    wc->ioaddr + WC_DMAWS);		/* Write start */	/* First frame */	outl(wc->writedma + ZT_CHUNKSIZE * 32 - 4, wc->ioaddr + WC_DMAWI);		/* Middle (interrupt) */	/* Second frame */	outl(wc->writedma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMAWE);			/* End */		outl(wc->readdma,                    	 wc->ioaddr + WC_DMARS);	/* Read start */	/* First frame */	outl(wc->readdma + ZT_CHUNKSIZE * 32 - 4, 	 wc->ioaddr + WC_DMARI);	/* Middle (interrupt) */	/* Second frame */	outl(wc->readdma + ZT_CHUNKSIZE * 32 * 2 - 4, wc->ioaddr + WC_DMARE);	/* End */		if (debug) printk("Setting up DMA (write/read = %08lx/%08lx)\n", (long)wc->writedma, (long)wc->readdma);	/* Check out the controller */	if (debug) printk("Controller version: %02x\n", control_get_reg(wc, WC_VERSION));	control_set_reg(wc, WC_LEDTEST, 0x00);	/* Sanity check also determines e1 or t1 */	if (t1xxp_framer_sanity_check(wc))		return -1;	if (wc->ise1)		wc->chanmap = chanmap_e1;	else		wc->chanmap = chanmap_t1;	/* Setup clock appropriately */	control_set_reg(wc, WC_CLOCK, 0x02 | wc->sync | wc->ise1);	wc->clocktimeout = 100;		/* Reset the T1 and report */	t1xxp_framer_hard_reset(wc);	start_alarm(wc);	return 0;}static int __devinit t1xxp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){	int res;	struct t1xxp *wc;	unsigned int *canary;		if (pci_enable_device(pdev)) {		res = -EIO;	} else {		wc = kmalloc(sizeof(struct t1xxp), GFP_KERNEL);		if (wc) {			memset(wc, 0x0, sizeof(struct t1xxp));			spin_lock_init(&wc->lock);			wc->ioaddr = pci_resource_start(pdev, 0);			wc->dev = pdev;			wc->offset = 28;	/* And you thought 42 was the answer */			wc->writechunk = 				/* 32 channels, Double-buffer, Read/Write */				(unsigned char *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 32 * 2 * 2, &wc->writedma);			if (!wc->writechunk) {				printk("wct1xxp: Unable to allocate DMA-able memory\n");				return -ENOMEM;			}			/* Read is after the whole write piece (in bytes) */			wc->readchunk = wc->writechunk + ZT_CHUNKSIZE * 32 * 2;			/* Same thing...  */			wc->readdma = wc->writedma + ZT_CHUNKSIZE * 32 * 2;			/* Initialize Write/Buffers to all blank data */			memset((void *)wc->writechunk,0x00,ZT_MAX_CHUNKSIZE * 2 * 2 * 32);			/* Initialize canary */			canary = (unsigned int *)(wc->readchunk + ZT_CHUNKSIZE * 64 - 4);			*canary = (CANARY << 16) | (0xffff);			/* Enable bus mastering */			pci_set_master(pdev);			/* Keep track of which device we are */			pci_set_drvdata(pdev, wc);			if (request_irq(pdev->irq, t1xxp_interrupt, SA_INTERRUPT | SA_SHIRQ, "t1xxp", wc)) {				printk("t1xxp: Unable to request IRQ %d\n", pdev->irq);				kfree(wc);				return -EIO;			}			/* Initialize hardware */			t1xxp_hardware_init(wc);			/* We now know which version of card we have */			if (wc->ise1)				wc->variety = "Digium Wildcard E100P E1/PRA";			else				wc->variety = "Digium Wildcard T100P T1/PRI";			/* Misc. software stuff */			t1xxp_software_init(wc);			printk("Found a Wildcard: %s\n", wc->variety);			res = 0;		} else			res = -ENOMEM;	}	return res;}static void t1xxp_stop_stuff(struct t1xxp *wc){	/* Kill clock */	control_set_reg(wc, WC_CLOCK, 0);	/* Turn off LED's */	control_set_reg(wc, WC_LEDTEST, 0);	/* Reset the T1 */	t1xxp_framer_hard_reset(wc);}static void __devexit t1xxp_remove_one(struct pci_dev *pdev){	struct t1xxp *wc = pci_get_drvdata(pdev);	if (wc) {		/* Stop any DMA */		__t1xxp_stop_dma(wc);		/* In case hardware is still there */		__t1xxp_disable_interrupts(wc);				t1xxp_stop_stuff(wc);		/* Immediately free resources */		pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 32 * 4, (void *)wc->writechunk, wc->writedma);		free_irq(pdev->irq, wc);		/* Reset PCI chip and registers */		outb(DELAY | 0x0e, wc->ioaddr + WC_CNTL);		/* Release span, possibly delayed */		if (!wc->usecount)			t1xxp_release(wc);		else			wc->dead = 1;	}}static struct pci_device_id t1xxp_pci_tbl[] = {	{ 0xe159, 0x0001, 0x6159, PCI_ANY_ID, 0, 0, (unsigned long) "Digium Wildcard T100P T1/PRI or E100P E1/PRA Board" },	{ 0 }};MODULE_DEVICE_TABLE(pci,t1xxp_pci_tbl);static struct pci_driver t1xxp_driver = {	name: 	"t1xxp",	probe: 	t1xxp_init_one,#ifdef LINUX26	remove:	__devexit_p(t1xxp_remove_one),#else	remove:	t1xxp_remove_one,#endif	suspend: NULL,	resume:	NULL,	id_table: t1xxp_pci_tbl,};static int __init t1xxp_init(void){	int res;	res = pci_module_init(&t1xxp_driver);	if (res)		return -ENODEV;	return 0;}static void __exit t1xxp_cleanup(void){	pci_unregister_driver(&t1xxp_driver);}#ifdef LINUX26module_param(debug, int, 0600);#elseMODULE_PARM(debug, "i");#endifMODULE_DESCRIPTION("Wildcard T100P/E100P Zaptel Driver");MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifmodule_init(t1xxp_init);module_exit(t1xxp_cleanup);

⌨️ 快捷键说明

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