summaryrefslogtreecommitdiff
path: root/pciradio.c
diff options
context:
space:
mode:
authorjim <jim@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-01-24 06:30:14 +0000
committerjim <jim@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-01-24 06:30:14 +0000
commitb7abd42a7b1cb85eec8d6f5b367a64f5b175b59f (patch)
tree2960eadd3948dd8b8053bce26e5370668bfff9af /pciradio.c
parent285e2417b6283c0b31eb9151e1350c55bad244cb (diff)
Updated pciradio driver and VHDL to fix nasty bus access bug, and added
diagnostic (raddiag). git-svn-id: http://svn.digium.com/svn/zaptel/trunk@572 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'pciradio.c')
-rwxr-xr-xpciradio.c126
1 files changed, 71 insertions, 55 deletions
diff --git a/pciradio.c b/pciradio.c
index 862e437..28ef258 100755
--- a/pciradio.c
+++ b/pciradio.c
@@ -50,15 +50,14 @@ With driver: 303826 (1.5 %)
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <asm/io.h>
#include <asm/delay.h>
+
#ifdef STANDALONE_ZAPATA
#include "zaptel.h"
#else
#include <linux/zaptel.h>
#endif
-#ifdef LINUX26
-#include <linux/moduleparam.h>
-#endif
#define RAD_MAX_IFACES 128
@@ -132,7 +131,10 @@ struct encdec
unsigned char saudio_ctrl[NUM_CHANS];
unsigned char saudio_setup[NUM_CHANS];
unsigned char txcode[NUM_CHANS];
+ unsigned long lastcmd;
int myindex[NUM_CHANS];
+ unsigned long waittime;
+ unsigned char retstate;
} ;
@@ -150,7 +152,7 @@ struct pciradio {
spinlock_t rbilock;
unsigned char pasave;
unsigned char pfsave;
- unsigned long ioaddr;
+ volatile unsigned long ioaddr;
dma_addr_t readdma;
dma_addr_t writedma;
volatile int *writechunk; /* Double-word aligned write memory */
@@ -445,12 +447,12 @@ int i;
}
-static void __pciradio_setcreg(struct pciradio *rad, unsigned char reg, unsigned char val)
+void __pciradio_setcreg(struct pciradio *rad, unsigned char reg, unsigned char val)
{
outb(val, rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2));
}
-static unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg)
+unsigned char __pciradio_getcreg(struct pciradio *rad, unsigned char reg)
{
return inb(rad->ioaddr + RAD_REGBASE + ((reg & 0xf) << 2));
}
@@ -496,36 +498,48 @@ void mx828_command(struct pciradio *rad,int channel, unsigned char command, unsi
void mx828_command_wait(struct pciradio *rad,int channel, unsigned char command, unsigned char *byte1, unsigned char *byte2)
{
-unsigned int flags;
DECLARE_WAIT_QUEUE_HEAD(mywait);
+unsigned int flags;
+
- for(;;)
+ spin_lock_irqsave(&rad->lock,flags);
+ while(rad->encdec.state)
{
- spin_lock_irqsave(&rad->lock,flags);
- if ((!(__pciradio_getcreg(rad,0xc) & 1)) &&
- (!(rad->encdec.state)))
- {
- mx828_command(rad,channel,command,byte1,byte2);
- spin_unlock_irqrestore(&rad->lock,flags);
- return;
- }
- spin_unlock_irqrestore(&rad->lock,flags);
- interruptible_sleep_on_timeout(&mywait,5);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ interruptible_sleep_on_timeout(&mywait,2);
+ spin_lock_irqsave(&rad->lock,flags);
}
+ rad->encdec.lastcmd = jiffies + 1000;
+ spin_unlock_irqrestore(&rad->lock,flags);
+ while(__pciradio_getcreg(rad,0xc) & 1);
+ rad->encdec.lastcmd = jiffies + 1000;
+ spin_lock_irqsave(&rad->lock,flags);
+ rad->encdec.lastcmd = jiffies + 1000;
+ mx828_command(rad,channel,command,byte1,byte2);
+ spin_unlock_irqrestore(&rad->lock,flags);
+ rad->encdec.lastcmd = jiffies + 1000;
+ while(__pciradio_getcreg(rad,0xc) & 1);
+ rad->encdec.lastcmd = jiffies;
}
-
-static void _do_encdec(struct pciradio *rad, int n)
+static void _do_encdec(struct pciradio *rad)
{
-int i;
+int i,n;
unsigned char byte1,byte2;
/* return doing nothing if busy */
+ if ((rad->encdec.lastcmd + 2) > jiffies) return;
if (__pciradio_getcreg(rad,0xc) & 1) return;
+ n = 0;
switch(rad->encdec.state)
{
case 0:
- if (!rad->encdec.req[n]) return;
+ for(i = 0; i < rad->nchans; i++)
+ {
+ n = (unsigned)(i - rad->intcount) % rad->nchans;
+ if (rad->encdec.req[n]) break;
+ }
+ if (i >= rad->nchans) return;
rad->encdec.req[n] = 0;
rad->encdec.dcsrx[n] = 0;
rad->encdec.ctrx[n] = 0;
@@ -588,7 +602,7 @@ unsigned char byte1,byte2;
byte1 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b1;
byte2 = cttable_tx[rad->encdec.txcode[rad->encdec.chan]].b2;
mx828_command(rad,rad->encdec.chan, MX828_TX_TONE, &byte1, &byte2 );
- }
+ }
rad->encdec.state = 5;
break;
case 5:
@@ -725,15 +739,15 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (ints & 0x0f) {
+
rad->intcount++;
x = rad->intcount % rad->nchans;
/* freeze */
__pciradio_setcreg(rad,0,rad->mx828_addr | 4);
/* read SAUDIO_STATUS for the proper channel */
- byte1 = __pciradio_getcreg(rad,x);
+ byte1 = rad->saudio_status[x] = __pciradio_getcreg(rad,x);
/* thaw */
__pciradio_setcreg(rad,0,rad->mx828_addr);
- rad->saudio_status[x] = byte1;
/* get COR input */
byte2 = __pciradio_getcreg(rad,9);
/* get bit for this channel */
@@ -802,7 +816,7 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
rad->encdec.req[x] = 1;
rad->last_code[x] = rad->present_code[x];
}
- _do_encdec(rad,x);
+ _do_encdec(rad);
for(x = 0; x < rad->nchans; x++)
{
unsigned char mask = 1 << x;
@@ -871,7 +885,7 @@ static void pciradio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (debug) printk("Chan %d lost rx\n",x + 1);
zt_qevent_lock(&rad->chans[x], ZT_EVENT_ONHOOK);
}
- rad->encdec.req[x] = 1;
+ rad->encdec.req[x] = 1;
}
rad->gotrx1[x] = rad->gotrx[x];
}
@@ -1025,7 +1039,9 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
}
rad->corthresh[chan->chanpos - 1] = stack.p.data;
byte1 = 0xc0 | (rad->corthresh[chan->chanpos - 1] << 2);
+ spin_unlock_irqrestore(&rad->lock,flags);
mx828_command_wait(rad,chan->chanpos - 1, MX828_GEN_CTRL, &byte1, &byte2);
+ spin_lock_irqsave(&rad->lock,flags);
break;
case ZT_RADPAR_EXTRXTONE:
if (stack.p.data)
@@ -1044,7 +1060,7 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
rad->rxclass[chan->chanpos - 1][i] = 0;
rad->txcode[chan->chanpos - 1][i] = 0;
}
- break;
+ spin_unlock_irqrestore(&rad->lock,flags);
for(i = 0; i < NUM_CODES; i++)
{
/* set to no encode/decode */
@@ -1055,6 +1071,8 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
byte2 = 0;
mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 );
}
+ spin_lock_irqsave(&rad->lock,flags);
+ break;
case ZT_RADPAR_RXTONE:
if (!stack.p.index) /* if RX DCS mode */
{
@@ -1083,7 +1101,9 @@ static int pciradio_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long
rad->rxcode[chan->chanpos - 1][stack.p.index] = mycode;
byte1 = cttable_rx[mycode].b1 | ((stack.p.index - 1) << 4);
byte2 = cttable_rx[mycode].b2;
+ spin_unlock_irqrestore(&rad->lock,flags);
mx828_command_wait(rad,chan->chanpos - 1, MX828_RX_TONE, &byte1, &byte2 );
+ spin_lock_irqsave(&rad->lock,flags);
/* zot out DCS one if there */
rad->rxcode[chan->chanpos - 1][0] = 0;
rad->encdec.req[chan->chanpos - 1] = 1;
@@ -1406,8 +1426,13 @@ unsigned long endjif;
printk("Did not get DONE signal. Short file maybe??\n");
return -1;
}
+ wait_just_a_bit(2);
+ /* get the thingy started */
+ outb(0,rad->ioaddr + RAD_REGBASE);
+ outb(0,rad->ioaddr + RAD_REGBASE);
printk("Xilinx Chip successfully loaded, configured and started!!\n");
+ wait_just_a_bit(HZ/4);
rad->pasave = 0;
__pciradio_setcreg(rad,0xa,rad->pasave);
@@ -1418,14 +1443,9 @@ unsigned long endjif;
rad->pfsave = 0;
__pciradio_setcreg(rad,0xf,rad->pfsave);
-
-
/* Back to normal, with automatic DMA wrap around */
outb(0x30 | 0x01, rad->ioaddr + RAD_CNTL);
- /* Make sure serial port and DMA are out of reset */
- outb(inb(rad->ioaddr + RAD_CNTL) & 0xf9, RAD_CNTL);
-
/* Configure serial port for MSB->LSB operation */
outb(0xc1, rad->ioaddr + RAD_SERCTL); /* DEBUG set double dlck to 0 SR */
@@ -1461,7 +1481,8 @@ unsigned long endjif;
mx828_command_wait(rad,x, MX828_GEN_CTRL, &byte1, &byte2);
rad->corthresh[x] = 2;
}
-
+ /* Wait 1/4 of a sec */
+ wait_just_a_bit(HZ/4);
return 0;
}
@@ -1477,17 +1498,17 @@ static void pciradio_enable_interrupts(struct pciradio *rad)
static void pciradio_restart_dma(struct pciradio *rad)
{
/* Reset Master and serial */
- outb(0x01, rad->ioaddr + RAD_CNTL);
+ outb(0x31, rad->ioaddr + RAD_CNTL);
outb(0x01, rad->ioaddr + RAD_OPER);
}
static void pciradio_start_dma(struct pciradio *rad)
{
/* Reset Master and serial */
- outb(0x0f, rad->ioaddr + RAD_CNTL);
+ outb(0x3f, rad->ioaddr + RAD_CNTL);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
- outb(0x01, rad->ioaddr + RAD_CNTL);
+ outb(0x31, rad->ioaddr + RAD_CNTL);
outb(0x01, rad->ioaddr + RAD_OPER);
}
@@ -1499,7 +1520,7 @@ static void pciradio_stop_dma(struct pciradio *rad)
static void pciradio_reset_serial(struct pciradio *rad)
{
/* Reset serial */
- outb(0x0f, rad->ioaddr + RAD_CNTL);
+ outb(0x3f, rad->ioaddr + RAD_CNTL);
}
static void pciradio_disable_interrupts(struct pciradio *rad)
@@ -1579,19 +1600,9 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
/* Keep track of which device we are */
pci_set_drvdata(pdev, 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);
- pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
- pci_set_drvdata(pdev, NULL);
- kfree(rad);
- return -EIO;
- }
-
-
if (pciradio_hardware_init(rad)) {
unsigned char x;
+
/* Set Reset Low */
x=inb(rad->ioaddr + RAD_CNTL);
outb((~0x1)&x, rad->ioaddr + RAD_CNTL);
@@ -1607,6 +1618,16 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
}
+ 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);
+ pci_free_consistent(pdev, ZT_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma);
+ pci_set_drvdata(pdev, NULL);
+ kfree(rad);
+ return -EIO;
+ }
+
/* Enable interrupts */
pciradio_enable_interrupts(rad);
/* Initialize Write/Buffers to all blank data */
@@ -1614,7 +1635,6 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de
/* Start DMA */
pciradio_start_dma(rad);
-
printk("Found a PCI Radio Card\n");
res = 0;
} else
@@ -1649,7 +1669,7 @@ static void __devexit pciradio_remove_one(struct pci_dev *pdev)
free_irq(pdev->irq, rad);
/* Reset PCI chip and registers */
- outb(0x0e, rad->ioaddr + RAD_CNTL);
+ outb(0x3e, rad->ioaddr + RAD_CNTL);
/* Release span, possibly delayed */
if (!rad->usecount)
@@ -1694,11 +1714,7 @@ static void __exit pciradio_cleanup(void)
pci_unregister_driver(&pciradio_driver);
}
-#ifdef LINUX26
-module_param(debug, int, 0600);
-#else
MODULE_PARM(debug, "i");
-#endif
MODULE_DESCRIPTION("Zapate Telephony PCI Radio Card Zaptel Driver");
MODULE_AUTHOR("Jim Dixon <jim@lambdatel.com>");
#ifdef MODULE_LICENSE