[svn-commits] jdixon: branch 1.4 r2806 - /branches/1.4/pciradio.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 31 15:41:31 CDT 2007


Author: jdixon
Date: Tue Jul 31 15:41:30 2007
New Revision: 2806

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2806
Log:
Much newer and improved version of pciradio driver

Modified:
    branches/1.4/pciradio.c

Modified: branches/1.4/pciradio.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/pciradio.c?view=diff&rev=2806&r1=2805&r2=2806
==============================================================================
--- branches/1.4/pciradio.c (original)
+++ branches/1.4/pciradio.c Tue Jul 31 15:41:30 2007
@@ -2,7 +2,7 @@
  * PCI RADIO Card  Zapata Telephony PCI Quad Radio Interface driver
  *
  * Written by Jim Dixon <jim at lambdatel.com>
- * Based on previous work by Mark Spencer <markster at digium.com>
+ * Based on previous work by Mark Spencer <markster at linux-support.net>
  * Based on previous works, designs, and archetectures conceived and
  * written by Jim Dixon <jim at lambdatel.com>.
  *
@@ -56,11 +56,7 @@
 #ifdef STANDALONE_ZAPATA
 #include "zaptel.h"
 #else
-#include <zaptel/zaptel.h>
-#endif
-
-#ifdef LINUX26
-#include <linux/moduleparam.h>
+#include <linux/zaptel.h>
 #endif
 
 #define RAD_MAX_IFACES 128
@@ -105,6 +101,11 @@
 #define NUM_CHANS 4
 
 #define	RAD_GOTRX_DEBOUNCE_TIME 75
+#define RAD_CTCSS_ACQUIRE_TIME 10
+#define RAD_CTCSS_TALKOFF_TIME 1000
+
+#define ZT_RADPAR_CTCSSACQUIRETIME 18 /* DEBUG only, this belongs in zaptel.h */
+#define ZT_RADPAR_CTCSSTALKOFFTIME 19 /* DEBUG only, this belongs in zaptel.h */
 
 /*
 * MX828 Commands
@@ -157,7 +158,7 @@
 	int freeregion;
 	int nchans;
 	spinlock_t lock;
-	spinlock_t remotelock;
+	int remote_locked;
 	unsigned char rxbuf[SERIAL_BUFLEN];
 	unsigned short rxindex;
 	unsigned long srxtimer;
@@ -169,17 +170,22 @@
 	volatile unsigned long ioaddr;
 	dma_addr_t 	readdma;
 	dma_addr_t	writedma;
-	volatile unsigned int *writechunk;	/* Double-word aligned write memory */
-	volatile unsigned int *readchunk;	/* Double-word aligned read memory */
+	volatile int *writechunk;	/* Double-word aligned write memory */
+	volatile int *readchunk;	/* Double-word aligned read memory */
 	unsigned char saudio_status[NUM_CHANS];
 	char gotcor[NUM_CHANS];
 	char gotct[NUM_CHANS];
+	char newctcssstate[NUM_CHANS];
+	char ctcssstate[NUM_CHANS];
 	char gotrx[NUM_CHANS];
 	char gotrx1[NUM_CHANS];
 	char gottx[NUM_CHANS];
 	char lasttx[NUM_CHANS];
 	int gotrxtimer[NUM_CHANS];
+	int ctcsstimer[NUM_CHANS];
 	int debouncetime[NUM_CHANS];
+	int ctcssacquiretime[NUM_CHANS];
+	int ctcsstalkofftime[NUM_CHANS];
 	int bursttime[NUM_CHANS];
 	int bursttimer[NUM_CHANS];
 	unsigned char remmode[NUM_CHANS];
@@ -474,19 +480,29 @@
 
 void rbi_out(struct pciradio *rad, int n, unsigned char *rbicmd)
 {
+unsigned long flags;
 int	x;
 DECLARE_WAIT_QUEUE_HEAD(mywait);
 
 
-	spin_lock(&rad->remotelock);
-	while(__pciradio_getcreg(rad,0xc) & 2) interruptible_sleep_on_timeout(&mywait,2);
+	for(;;)
+	{
+		spin_lock_irqsave(&rad->lock,flags);
+		x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
+		if (!x) rad->remote_locked = 1;
+		spin_unlock_irqrestore(&rad->lock,flags);
+		if (x) interruptible_sleep_on_timeout(&mywait,2);
+		else break;
+	}	
+	spin_lock_irqsave(&rad->lock,flags);
 	/* enable and address RBI serializer */
 	__pciradio_setcreg(rad,0xf,rad->pfsave | (n << 4) | 0x40);
 	/* output commands */
 	for(x = 0; x < 5; x++) __pciradio_setcreg(rad,0xc,rbicmd[x]);
 	/* output it */
 	__pciradio_setcreg(rad,0xb,1);
-	spin_unlock(&rad->remotelock);
+	rad->remote_locked = 0;
+	spin_unlock_irqrestore(&rad->lock,flags);
 	return;
 }
 
@@ -539,7 +555,7 @@
 static void _do_encdec(struct pciradio *rad)
 {
 int	i,n;
-unsigned char byte1 = 0, byte2 = 0;
+unsigned char byte1,byte2;
 
 	/* return doing nothing if busy */
 	if ((rad->encdec.lastcmd + 2) > jiffies) return;
@@ -713,7 +729,11 @@
 static void pciradio_reset_serial(struct pciradio *rad);
 static void pciradio_restart_dma(struct pciradio *rad);
 
-ZAP_IRQ_HANDLER(pciradio_interrupt)
+#ifdef LINUX26
+static irqreturn_t pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#endif
 {
 	struct pciradio *rad = dev_id;
 	unsigned char ints,byte1,byte2,gotcor,gotctcss,gotslowctcss,ctcss;
@@ -810,13 +830,27 @@
 				gotctcss = gotslowctcss = ((byteuio & mask) != 0);
 		}
 		rad->gotct[x] = gotslowctcss;
-		if ((rad->radmode[x] & RADMODE_IGNORECT) || (!ctcss))
+		if ((rad->radmode[x] & RADMODE_IGNORECT) || 
+		   ((!(rad->radmode[x] & RADMODE_EXTTONE)) && (!ctcss))) 
 		{
 			gotctcss = 1;
 			gotslowctcss = 1;
 			rad->present_code[x] = 0;
 		}
-		gotrx = gotcor && gotctcss;
+		if(rad->newctcssstate[x] != gotctcss){
+			rad->newctcssstate[x] = gotctcss;
+			if(rad->newctcssstate[x])
+				rad->ctcsstimer[x]=rad->ctcssacquiretime[x];
+			else
+				rad->ctcsstimer[x]=rad->ctcsstalkofftime[x];
+		}
+		else{
+			 if(!rad->ctcsstimer[x])
+				rad->ctcssstate[x] = rad->newctcssstate[x];
+			else
+				rad->ctcsstimer[x]--;
+		}
+		gotrx = gotcor && rad->ctcssstate[x];
 		if (gotrx != rad->gotrx[x])
 		{
 			rad->gotrxtimer[x] = rad->debouncetime[x];
@@ -902,7 +936,7 @@
 				}
 			}
 		}
-/* process serial if any */
+		/* process serial if any */
 		/* send byte if there is one in buffer to send */
 		if (rad->txlen && (rad->txlen != rad->txindex))
 		{
@@ -926,6 +960,14 @@
 		}
 		pciradio_receiveprep(rad, ints);
 		pciradio_transmitprep(rad, ints);
+		i = 0;
+		for(x = 0; x < 4; x++)
+		{
+			if (rad->gottx[x]) i |= (1 << (x * 2));
+			if (rad->gotrx[x]) i |= (2 << (x * 2));
+		}  
+		/* output LED's */
+		__pciradio_setcreg(rad, 9, i);
 	}
 #ifdef LINUX26
 	return IRQ_RETVAL(1);
@@ -1012,6 +1054,15 @@
 		case ZT_RADPAR_DEBOUNCETIME:
 			stack.p.data = rad->debouncetime[chan->chanpos - 1];
 			break;
+
+		case ZT_RADPAR_CTCSSACQUIRETIME:
+			stack.p.data = rad->ctcssacquiretime[chan->chanpos - 1];
+			break;
+
+		case ZT_RADPAR_CTCSSTALKOFFTIME:
+			stack.p.data = rad->ctcsstalkofftime[chan->chanpos - 1];
+			break;
+
 		case ZT_RADPAR_BURSTTIME:
 			stack.p.data = rad->bursttime[chan->chanpos - 1];
 			break;
@@ -1168,6 +1219,15 @@
 		case ZT_RADPAR_DEBOUNCETIME:
 			rad->debouncetime[chan->chanpos - 1] = stack.p.data;
 			break;
+
+		case ZT_RADPAR_CTCSSACQUIRETIME:
+			rad->ctcssacquiretime[chan->chanpos - 1] = stack.p.data;
+			break;
+
+		case ZT_RADPAR_CTCSSTALKOFFTIME:
+			rad->ctcsstalkofftime[chan->chanpos - 1] = stack.p.data;
+			break;
+
 		case ZT_RADPAR_BURSTTIME:
 			rad->bursttime[chan->chanpos - 1] = stack.p.data;
 			break;
@@ -1178,7 +1238,6 @@
 			if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1));
 			if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3));
 			__pciradio_setcreg(rad,8,byte1);
-			spin_unlock_irqrestore(&rad->lock,flags);
 			break;
 		case ZT_RADPAR_UIOMODE:
 			byte1 = __pciradio_getcreg(rad,0xe);
@@ -1187,7 +1246,6 @@
 			if (stack.p.data & 1) byte1 |= (1 << (chan->chanpos - 1));
 			if (stack.p.data & 2) byte1 |= (1 << (chan->chanpos + 3));
 			__pciradio_setcreg(rad,0xe,byte1);
-			spin_unlock_irqrestore(&rad->lock,flags);
 			break;
 		case ZT_RADPAR_REMMODE:
 			rad->remmode[chan->chanpos - 1] = stack.p.data;
@@ -1222,7 +1280,20 @@
 				spin_lock_irqsave(&rad->lock,flags);
 				break;
 			}
-			/* set UIOA and UIOB for output */
+			spin_unlock_irqrestore(&rad->lock,flags);
+			for(;;)
+			{
+				int x;
+
+				spin_lock_irqsave(&rad->lock,flags);
+				x = rad->remote_locked || (__pciradio_getcreg(rad,0xc) & 2);
+				if (!x) rad->remote_locked = 1;
+				spin_unlock_irqrestore(&rad->lock,flags);
+				if (x) interruptible_sleep_on_timeout(&mywait,2);
+				else break;
+			}	
+			spin_lock_irqsave(&rad->lock,flags);
+			/* set UIOA for input and UIOB for output */
 			byte1 = __pciradio_getcreg(rad,0xe);
 			mask = 1 << (chan->chanpos + 3); /* B an output */
 			byte2 = byte1 & (~mask);
@@ -1231,16 +1302,19 @@
 			byte1 = __pciradio_getcreg(rad,8);
 			byte2 = byte1 | mask;
 			byte2 |= 1 << (chan->chanpos - 1);
+			byte2 |= 1 << (chan->chanpos + 3);
 			__pciradio_setcreg(rad,8,byte2);
 			spin_unlock_irqrestore(&rad->lock,flags);
-			if (byte1 != byte2)
-				interruptible_sleep_on_timeout(&mywait,100);
+			if (byte1 != byte2) 
+				interruptible_sleep_on_timeout(&mywait,3);
 			while (jiffies < rad->lastremcmd + 10)
 				interruptible_sleep_on_timeout(&mywait,10);
 			rad->lastremcmd = jiffies;
-			spin_lock(&rad->remotelock);
-			while(__pciradio_getcreg(rad,0xc) & 2) interruptible_sleep_on_timeout(&mywait,2);
-			spin_unlock(&rad->remotelock);
+			for(;;)
+			{
+				if (!(__pciradio_getcreg(rad,0xc) & 2)) break;
+ 				interruptible_sleep_on_timeout(&mywait,2);
+			}
 			spin_lock_irqsave(&rad->lock,flags);
 			/* enable and address async serializer */
 			__pciradio_setcreg(rad,0xf,rad->pfsave | ((chan->chanpos - 1) << 4) | 0x80);
@@ -1258,7 +1332,7 @@
 				if ((rad->rxindex < stack.p.data) &&
 				  (rad->srxtimer < SRX_TIMEOUT) &&
 				    ((rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL) ||
-					(!strchr((char *) rad->rxbuf,'\r'))))
+					(!strchr(rad->rxbuf,'\r'))))
 				{
 					spin_unlock_irqrestore(&rad->lock,flags);
 					interruptible_sleep_on_timeout(&mywait,2);
@@ -1273,8 +1347,24 @@
 				stack.p.index = rad->rxindex;
 				break;
 			}
+			/* wait for done only if in SERIAL_ASCII mode */
+			if (rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL_ASCII)
+			{			
+				/* wait for TX to be done if not already */
+				while(rad->txlen && (rad->txindex < rad->txlen))
+				{
+					spin_unlock_irqrestore(&rad->lock,flags);
+					interruptible_sleep_on_timeout(&mywait,2);
+					spin_lock_irqsave(&rad->lock,flags);
+				}
+				/* disable and un-address async serializer */
+				__pciradio_setcreg(rad,0xf,rad->pfsave); 
+			}
+			rad->remote_locked = 0;
+			spin_unlock_irqrestore(&rad->lock,flags);
+			if (rad->remmode[chan->chanpos - 1] == ZT_RADPAR_REM_SERIAL_ASCII)
+				interruptible_sleep_on_timeout(&mywait,100);
 			if (copy_to_user((struct zt_radio_stat *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
-			spin_unlock_irqrestore(&rad->lock,flags);
 			return 0;
 		default:
 			spin_unlock_irqrestore(&rad->lock,flags);
@@ -1388,7 +1478,7 @@
 		printk("pciradio: Can't set tx state to %d\n", txsig);
 		break;
 	}
-	if (debug)
+	if (debug) 
 		printk("pciradio: Setting Radio hook state to %d on chan %d\n", txsig, chan->chanpos);
 	return 0;
 }
@@ -1407,6 +1497,8 @@
 		rad->chans[x].chanpos = x+1;
 		rad->chans[x].pvt = rad;
 		rad->debouncetime[x] = RAD_GOTRX_DEBOUNCE_TIME;
+		rad->ctcssacquiretime[x] = RAD_CTCSS_ACQUIRE_TIME;
+		rad->ctcsstalkofftime[x] = RAD_CTCSS_TALKOFF_TIME;
 	}
 	rad->span.chans = rad->chans;
 	rad->span.channels = rad->nchans;
@@ -1525,20 +1617,21 @@
 
 	wait_just_a_bit(HZ/4);
 
-	rad->pasave = 0;
-	__pciradio_setcreg(rad,0xa,rad->pasave);
-
-	__pciradio_setcreg(rad,8,0);
-	__pciradio_setcreg(rad,9,0x55);
-	__pciradio_setcreg(rad,0xe,0);
-	rad->pfsave = 0;
-	__pciradio_setcreg(rad,0xf,rad->pfsave);
 
 	/* Back to normal, with automatic DMA wrap around */
 	outb(0x30 | 0x01, rad->ioaddr + RAD_CNTL);
 	
 	/* Configure serial port for MSB->LSB operation */
 	outb(0xc1, rad->ioaddr + RAD_SERCTL); /* DEBUG set double dlck to 0 SR */
+
+	rad->pasave = 0;
+	__pciradio_setcreg(rad,0xa,rad->pasave);
+
+	__pciradio_setcreg(rad,0xf,rad->pfsave);
+	__pciradio_setcreg(rad,8,0xff);
+	__pciradio_setcreg(rad,0xe,0xff);
+	__pciradio_setcreg(rad,9,0);
+	rad->pfsave = 0;
 
 	/* Delay FSC by 0 so it's properly aligned */
 	outb(/* 1 */ 0, rad->ioaddr + RAD_FSCDELAY);
@@ -1648,7 +1741,6 @@
 			ifaces[x] = rad;
 			memset(rad, 0, sizeof(struct pciradio));
 			spin_lock_init(&rad->lock);
-			spin_lock_init(&rad->remotelock);
 			rad->nchans = 4;
 			rad->ioaddr = pci_resource_start(pdev, 0);
 			rad->dev = pdev;
@@ -1660,7 +1752,7 @@
 
 			/* Allocate enough memory for two zt chunks, receive and transmit.  Each sample uses
 			   32 bits.  Allocate an extra set just for control too */
-			rad->writechunk = pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &rad->writedma);
+			rad->writechunk = (int *)pci_alloc_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, &rad->writedma);
 			if (!rad->writechunk) {
 				printk("pciradio: Unable to allocate DMA-able memory\n");
 				if (rad->freeregion)
@@ -1676,6 +1768,9 @@
 				/* Set Reset Low */
 				x=inb(rad->ioaddr + RAD_CNTL);
 				outb((~0x1)&x, rad->ioaddr + RAD_CNTL);
+				outb(x, rad->ioaddr + RAD_CNTL);
+				__pciradio_setcreg(rad,8,0xff);
+				__pciradio_setcreg(rad,0xe,0xff);
 				/* Free Resources */
 				free_irq(pdev->irq, rad);
 				if (rad->freeregion)
@@ -1697,6 +1792,9 @@
 				/* Set Reset Low */
 				x=inb(rad->ioaddr + RAD_CNTL);
 				outb((~0x1)&x, rad->ioaddr + RAD_CNTL);
+				outb(x, rad->ioaddr + RAD_CNTL);
+				__pciradio_setcreg(rad,8,0xff);
+				__pciradio_setcreg(rad,0xe,0xff);
 				/* Free Resources */
 				free_irq(pdev->irq, rad);
 				if (rad->freeregion)
@@ -1709,7 +1807,7 @@
 
 			}
 
-			if (request_irq(pdev->irq, pciradio_interrupt, ZAP_IRQ_SHARED, "pciradio", rad)) {
+			if (request_irq(pdev->irq, pciradio_interrupt, SA_SHIRQ, "pciradio", rad)) {
 				printk("pciradio: Unable to request IRQ %d\n", pdev->irq);
 				if (rad->freeregion)
 					release_region(rad->ioaddr, 0xff);
@@ -1760,7 +1858,13 @@
 		free_irq(pdev->irq, rad);
 
 		/* Reset PCI chip and registers */
-		outb(0x3e, rad->ioaddr + RAD_CNTL);
+		outb(0x3e, rad->ioaddr + RAD_CNTL); 
+
+		/* Clear Reset Line */
+		outb(0x3f, rad->ioaddr + RAD_CNTL); 
+
+		__pciradio_setcreg(rad,8,0xff);
+		__pciradio_setcreg(rad,0xe,0xff);
 
 		/* Release span, possibly delayed */
 		if (!rad->usecount)




More information about the svn-commits mailing list