summaryrefslogtreecommitdiff
path: root/pciradio.c
diff options
context:
space:
mode:
authorjdixon <jdixon@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-07-31 20:41:30 +0000
committerjdixon <jdixon@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-07-31 20:41:30 +0000
commit45e0df08a84367ecb5cb51bb0fcbdf5d058f7b7a (patch)
tree6b80e56312ce92d2537aa89941d59871a872ed55 /pciradio.c
parent9f197f6598a4aabc02198513095fd95ed8025b42 (diff)
Much newer and improved version of pciradio driver
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@2806 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'pciradio.c')
-rw-r--r--pciradio.c184
1 files changed, 144 insertions, 40 deletions
diff --git a/pciradio.c b/pciradio.c
index d9b2d82..bb02914 100644
--- a/pciradio.c
+++ b/pciradio.c
@@ -2,7 +2,7 @@
* PCI RADIO Card Zapata Telephony PCI Quad Radio Interface driver
*
* Written by Jim Dixon <jim@lambdatel.com>
- * Based on previous work by Mark Spencer <markster@digium.com>
+ * Based on previous work by Mark Spencer <markster@linux-support.net>
* Based on previous works, designs, and archetectures conceived and
* written by Jim Dixon <jim@lambdatel.com>.
*
@@ -56,11 +56,7 @@ With driver: 303826 (1.5 %)
#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 @@ With driver: 303826 (1.5 %)
#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 @@ struct pciradio {
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 @@ struct pciradio {
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 @@ unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg)
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 @@ unsigned long flags;
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_stop_dma(struct pciradio *rad);
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 @@ ZAP_IRQ_HANDLER(pciradio_interrupt)
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 @@ ZAP_IRQ_HANDLER(pciradio_interrupt)
}
}
}
-/* 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 @@ ZAP_IRQ_HANDLER(pciradio_interrupt)
}
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
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 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
stack.p.index = rad->rxindex;
break;
}
- if (copy_to_user((struct zt_radio_stat *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
+ /* 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;
return 0;
default:
spin_unlock_irqrestore(&rad->lock,flags);
@@ -1388,7 +1478,7 @@ static int pciradio_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
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 @@ static int pciradio_initialize(struct pciradio *rad)
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,14 +1617,6 @@ unsigned long endjif;
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);
@@ -1540,6 +1624,15 @@ unsigned long endjif;
/* 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 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
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 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
/* 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 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
/* 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 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
/* 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 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
}
- 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 @@ static void __devexit pciradio_remove_one(struct pci_dev *pdev)
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)