From b7abd42a7b1cb85eec8d6f5b367a64f5b175b59f Mon Sep 17 00:00:00 2001 From: jim Date: Mon, 24 Jan 2005 06:30:14 +0000 Subject: 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 --- pciradio.c | 126 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 55 deletions(-) (limited to 'pciradio.c') 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 #include #include +#include #include + #ifdef STANDALONE_ZAPATA #include "zaptel.h" #else #include #endif -#ifdef LINUX26 -#include -#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 "); #ifdef MODULE_LICENSE -- cgit v1.2.3