From cd81703764c4d2884c60f3632f15d5bfc44dc31d Mon Sep 17 00:00:00 2001 From: sruffell Date: Thu, 27 Mar 2008 21:17:46 +0000 Subject: - Updated wctdm24xxp and wcte12xp driver which are now more tolerant of systems which do not exhibit good real-time characteristics. - Bringing in improvements to battery alarm generation that was on kpflemings battery_alarms branch. (Issue #12099) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4096 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/wcte12xp/base.c | 612 +++++++++---------------------------------------- 1 file changed, 113 insertions(+), 499 deletions(-) (limited to 'kernel/wcte12xp/base.c') diff --git a/kernel/wcte12xp/base.c b/kernel/wcte12xp/base.c index ee58db8..32bfe6f 100644 --- a/kernel/wcte12xp/base.c +++ b/kernel/wcte12xp/base.c @@ -8,7 +8,7 @@ * Matthew Fredrickson * William Meadows * - * Copyright (C) 2007, Digium, Inc. + * Copyright (C) 2007-2008, Digium, Inc. * * All rights reserved. * @@ -34,9 +34,7 @@ #include #include #include -#include #include -#include #ifdef LINUX26 #include @@ -46,6 +44,7 @@ #include "../wct4xxp/wct4xxp.h" /* For certain definitions */ +#include "../voicebus.h" #include "wcte12xp.h" #if defined(VPM_SUPPORT) @@ -91,6 +90,7 @@ static int alarmdebounce = 0; static int loopback = 0; static int t1e1override = -1; static int unchannelized = 0; +static int latency = VOICEBUS_DEFAULT_LATENCY; #ifdef VPM_SUPPORT int vpmsupport = 1; int vpmdtmfsupport = 0; @@ -135,89 +135,6 @@ static inline int empty_slot(struct t1 *wc) return -1; } -static inline void __t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val) -{ - outl(val, wc->iobase + addr); -} - -static inline void t1_setctl(struct t1 *wc, unsigned int addr, unsigned int val) -{ - unsigned long flags; - - spin_lock_irqsave(&wc->reglock, flags); - __t1_setctl(wc, addr, val); - spin_unlock_irqrestore(&wc->reglock, flags); -} - -static inline unsigned int __t1_getctl(struct t1 *wc, unsigned int addr) -{ - return inl(wc->iobase + addr); -} - -static inline unsigned int t1_getctl(struct t1 *wc, unsigned int addr) -{ - unsigned long flags; - unsigned int val; - - spin_lock_irqsave(&wc->reglock, flags); - val = __t1_getctl(wc, addr); - spin_unlock_irqrestore(&wc->reglock, flags); - - return val; -} - -static void t1_init_descriptors(struct t1 *wc) -{ - volatile unsigned int *descrip; - dma_addr_t descripdma; - dma_addr_t writedma; - dma_addr_t readdma; - int x; - - descrip = wc->descripchunk; - descripdma = wc->descripdma; - writedma = wc->writedma; - readdma = wc->readdma; - - for (x = 0; x < ERING_SIZE; x++) { - if (x < ERING_SIZE - 1) - descripdma += 16; - else - descripdma = wc->descripdma; - - /* Transmit descriptor */ - descrip[0] = 0x80000000; - descrip[1] = 0xe5800000 | (SFRAME_SIZE); - if (x % 2) - descrip[2] = writedma + SFRAME_SIZE; - else - descrip[2] = writedma; - descrip[3] = descripdma; - - /* Receive descriptor */ - descrip[0 + ERING_SIZE * 4] = 0x80000000; - descrip[1 + ERING_SIZE * 4] = 0x01000000 | (SFRAME_SIZE); - if (x % 2) - descrip[2 + ERING_SIZE * 4] = readdma + SFRAME_SIZE; - else - descrip[2 + ERING_SIZE * 4] = readdma; - descrip[3 + ERING_SIZE * 4] = descripdma + ERING_SIZE * 16; - - /* Advance descriptor */ - descrip += 4; - } -} - -static inline void t1_reinit_descriptor(struct t1 *wc, int tx, int dbl, char *s) -{ - int o2 = dbl * 4; - - if (!tx) - o2 += ERING_SIZE * 4; - - wc->descripchunk[o2] = 0x80000000; -} - static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot) { struct command *curcmd=NULL; @@ -290,93 +207,6 @@ static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk } } -static inline unsigned int __t1_sdi_clk(struct t1 *wc) -{ - unsigned int ret; - - wc->sdi &= ~SDI_CLK; - __t1_setctl(wc, 0x0048, wc->sdi); - ret = __t1_getctl(wc, 0x0048); - wc->sdi |= SDI_CLK; - __t1_setctl(wc, 0x0048, wc->sdi); - return ret & SDI_DIN; -} - -static inline void __t1_sdi_sendbits(struct t1 *wc, unsigned int bits, int count) -{ - wc->sdi &= ~SDI_DREAD; - __t1_setctl(wc, 0x0048, wc->sdi); - while (count--) { - if (bits & (1 << count)) - wc->sdi |= SDI_DOUT; - else - wc->sdi &= ~SDI_DOUT; - __t1_sdi_clk(wc); - } -} - -static inline unsigned int __t1_sdi_recvbits(struct t1 *wc, int count) -{ - unsigned int bits=0; - - wc->sdi |= SDI_DREAD; - __t1_setctl(wc, 0x0048, wc->sdi); - while (count--) { - bits <<= 1; - if (__t1_sdi_clk(wc)) - bits |= 1; - else - bits &= ~1; - } - return bits; -} - -static inline unsigned short __t1_getsdi(struct t1 *wc, unsigned char addr) -{ - unsigned int bits; - - /* Send preamble */ - bits = 0xffffffff; - __t1_sdi_sendbits(wc, bits, 32); - bits = (0x6 << 10) | (1 << 5) | (addr); - __t1_sdi_sendbits(wc, bits, 14); - - return __t1_sdi_recvbits(wc, 18); -} - -static inline unsigned short t1_getsdi(struct t1 *wc, unsigned char addr) -{ - unsigned long flags; - unsigned short val; - - spin_lock_irqsave(&wc->reglock, flags); - val = __t1_getsdi(wc, addr); - spin_unlock_irqrestore(&wc->reglock, flags); - - return val; -} - -static inline void __t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value) -{ - unsigned int bits; - - /* Send preamble */ - bits = 0xffffffff; - __t1_sdi_sendbits(wc, bits, 32); - bits = (0x5 << 12) | (1 << 7) | (addr << 2) | 0x2; - __t1_sdi_sendbits(wc, bits, 16); - __t1_sdi_sendbits(wc, value, 16); -} - -static inline void t1_setsdi(struct t1 *wc, unsigned char addr, unsigned short value) -{ - unsigned long flags; - - spin_lock_irqsave(&wc->reglock, flags); - __t1_setsdi(wc, addr, value); - spin_unlock_irqrestore(&wc->reglock, flags); -} - static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int inisr, int vpm_num) { unsigned long flags; @@ -451,10 +281,16 @@ static inline int t1_getreg_isr(struct t1 *wc, int addr) /* find our requested command */ for (x = 0;x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) { if ((wc->cmdq.cmds[x].flags & __CMD_RD) && - (wc->cmdq.cmds[x].flags & __CMD_FIN) && - (wc->cmdq.cmds[x].address==addr)) { - hit = x; - break; + (wc->cmdq.cmds[x].address==addr)) + { + if (wc->cmdq.cmds[x].flags & __CMD_FIN) { + hit = x; + break; + } + else { + /* still in progress. */ + return -1; + } } } @@ -595,68 +431,6 @@ static inline int t1_getpins(struct t1 *wc, int inisr) return ret; } -static void t1_setintmask(struct t1 *wc, unsigned int intmask) -{ - wc->intmask = intmask; - t1_setctl(wc, 0x0038, intmask); -} - -static void t1_enable_interrupts(struct t1 *wc) -{ - /* Enable interrupts */ - t1_setintmask(wc, 0x00010041); /* only RX */ -} - -static void t1_disable_interrupts(struct t1 *wc) -{ - /* Disable interrupts */ - t1_setintmask(wc, 0x00000000); - t1_setctl(wc, 0x0084, 0x00000000); -} - -static void t1_start_dma(struct t1 *wc) -{ - unsigned int reg; - int x; - - wmb(); - t1_setctl(wc, 0x0020, wc->descripdma); - t1_setctl(wc, 0x0018, wc->descripdma + (16 * ERING_SIZE)); - /* Start receiver/transmitter */ - reg = t1_getctl(wc, 0x0030); - t1_setctl(wc, 0x0030, reg | 0x00002002); - t1_setctl(wc, 0x0008, 0x00000000); - t1_setctl(wc, 0x0010, 0x00000000); - reg = t1_getctl(wc, 0x0028); - t1_setctl(wc, 0x0028, reg); - - /* Set Reset - now with MAGIC TIPS */ - t1_setctl(wc, 0x0048, 0x00000000); - for (x = 0; x < 10; x++) - schluffen(&wc->regq); - /* Clear reset */ - t1_setctl(wc, 0x0048, 0x00010000); - for (x = 0; x < 10; x++) - schluffen(&wc->regq); - /* Switch to caring only about receive interrupts */ - t1_setintmask(wc, 0x00010040); -} - -static void t1_stop_dma(struct t1 *wc) -{ - /* Disable interrupts and reset */ - unsigned int reg; - - /* Disable interrupts */ - t1_setintmask(wc, 0x00000000); - t1_setctl(wc, 0x0084, 0x00000000); - t1_setctl(wc, 0x0048, 0x00000000); - /* Reset the part to be on the safe side */ - reg = t1_getctl(wc, 0x0000); - reg |= 0x00000001; - t1_setctl(wc, 0x0000, reg); -} - static void __t1xxp_set_clear(struct t1 *wc, int channo) { int i,j; @@ -681,8 +455,6 @@ static void __t1xxp_set_clear(struct t1 *wc, int channo) static void t1_release(struct t1 *wc) { zt_unregister(&wc->span); - if (wc->freeregion) - release_region(wc->iobase, 0xff); kfree(wc); printk("Freed a Wildcard TE12xP\n"); } @@ -1076,8 +848,6 @@ static inline void __t1_check_sigbits(struct t1 *wc) spin_lock(&wc->reglock); } } - } else { - debug_printk(1, "no space to request register in isr\n"); } } } else if (wc->span.lineconfig & ZT_CONFIG_D4) { @@ -1240,28 +1010,17 @@ static int t1xxp_close(struct zt_chan *chan) static int t1xxp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data) { - struct t4_regs regs; unsigned int x; struct t1 *wc = chan->pvt; switch (cmd) { case WCT4_GET_REGS: - wc = chan->pvt; - for (x = 0; x < sizeof(regs.pci) / sizeof(regs.pci[0]); x++) -#if 1 - regs.pci[x] = (inb(wc->iobase + (x << 2))) | - (inb(wc->iobase + (x << 2) + 1) << 8) | - (inb(wc->iobase + (x << 2) + 2) << 16) | - (inb(wc->iobase + (x << 2) + 3) << 24); -#else - regs.pci[x] = (inb(wc->iobase + x)); -#endif - - for (x = 0; x < sizeof(regs.regs) / sizeof(regs.regs[0]); x++) - regs.regs[x] = t1_getreg(wc, x, 0); - - if (copy_to_user((struct t4_regs *) data, ®s, sizeof(regs))) - return -EFAULT; + /* Since all register access was moved into the voicebus + * module....this was removed. Although...why does the client + * library need access to the registers (debugging)? \todo .. + */ + WARN_ON(1); + return -ENOSYS; break; #ifdef VPM_SUPPORT case ZT_TONEDETECT: @@ -1339,6 +1098,9 @@ static int t1xxp_echocan_with_params(struct zt_chan *chan, struct zt_echocanpara static int t1_software_init(struct t1 *wc) { int x; + struct pci_dev* dev; + + dev = voicebus_get_pci_dev(wc->vb); /* Find position */ for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++) { @@ -1357,7 +1119,7 @@ static int t1_software_init(struct t1 *wc) sprintf(wc->span.name, "WCT1/%d", wc->num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); wc->span.manufacturer = "Digium"; - zap_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); + strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1); #if defined(VPM_SUPPORT) if (wc->vpm150m) @@ -1365,11 +1127,11 @@ static int t1_software_init(struct t1 *wc) #endif snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); + "PCI Bus %02d Slot %02d", dev->bus->number, PCI_SLOT(dev->devfn) + 1); wc->span.spanconfig = t1xxp_spanconfig; wc->span.chanconfig = t1xxp_chanconfig; - wc->span.irq = wc->dev->irq; + wc->span.irq = dev->irq; wc->span.startup = t1xxp_startup; wc->span.shutdown = t1xxp_shutdown; wc->span.rbsbits = t1xxp_rbsbits; @@ -1660,7 +1422,8 @@ static void __t1_do_counters(struct t1 *wc) static inline void t1_isr_misc(struct t1 *wc) { - unsigned int x; + const unsigned int x = wc->intcount & 0x3f; + int buffer_count = voicebus_current_latency(wc->vb); if (unlikely(!wc->initialized)) return; @@ -1668,52 +1431,35 @@ static inline void t1_isr_misc(struct t1 *wc) __t1_do_counters(wc); - x = wc->intcount & 0xF; - switch (x) { - case 0: - __t1_check_sigbits_reads(wc); - break; - case 1: - if (!(wc->intcount & 0x30)) { - __t1_check_alarms_reads(wc); - wc->alarms_read=1; - } - break; - case 2: - break; - case 4: - break; - case 5: - break; - case 7: - __t1_check_sigbits(wc); - break; - case 8: - if (wc->alarms_read) { - __t1_check_alarms(wc); - wc->alarms_read=0; - } - break; - case 9: - clean_leftovers(wc); - break; + if ( 0 == x ) { + __t1_check_sigbits_reads(wc); + } + else if ( 1 == x ) { + if (!(wc->intcount & 0x30)) { + __t1_check_alarms_reads(wc); + wc->alarms_read=1; + } + } + else if ( x == buffer_count*2) { + __t1_check_sigbits(wc); + } + else if ( x == (buffer_count*2)+1 ) { + if (wc->alarms_read) { + __t1_check_alarms(wc); + wc->alarms_read=0; + } + } + else if ( x == (buffer_count*2)+2) { + clean_leftovers(wc); } } -static inline void t1_transmitprep(struct t1 *wc, int dbl) +static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk) { - volatile unsigned char *writechunk; int x; int y; int chan; - dbl = dbl % 2; - - writechunk = (volatile unsigned char *)(wc->writechunk); - if (dbl) - /* Write is at interrupt address. Start writing from normal offset */ - writechunk += SFRAME_SIZE; - /* Calculate Transmission */ if (likely(wc->initialized)) { spin_unlock(&wc->reglock); @@ -1757,17 +1503,11 @@ static inline void cmd_retransmit(struct t1 *wc) } } -static inline void t1_receiveprep(struct t1 *wc, int dbl) +static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk) { - volatile unsigned char *readchunk; int x,chan; unsigned char expected; - dbl = dbl % 2; - - readchunk = (volatile unsigned char *)wc->readchunk; - if (dbl) - readchunk += SFRAME_SIZE; for (x = 0; x < ZT_CHUNKSIZE; x++) { if (likely(wc->initialized)) { for (chan = 0; chan < wc->span.channels; chan++) { @@ -1782,7 +1522,7 @@ static inline void t1_receiveprep(struct t1 *wc, int dbl) wc->span.irqmisses++; cmd_retransmit(wc); if (unlikely(debug && wc->initialized)) - module_printk("oops: rxident=%d expected=%d\n", wc->rxident, expected); + module_printk("oops: rxident=%d expected=%d x=%d\n", wc->rxident, expected, x); } } cmd_decipher(wc, readchunk); @@ -1809,127 +1549,36 @@ static inline void t1_receiveprep(struct t1 *wc, int dbl) wake_up_interruptible(&wc->regq); } -static inline int t1_check_descriptor(struct t1 *wc, int tx) -{ - int o2 = 0; - - if (!tx) { - o2 += ERING_SIZE * 4; - o2 += wc->rdbl * 4; - } else { - o2 += wc->tdbl * 4; - } - - if (!(wc->descripchunk[o2] & 0x80000000)) { - if (tx) { - wc->txints++; - t1_transmitprep(wc, wc->tdbl); - t1_reinit_descriptor(wc, tx, wc->tdbl, "txchk"); - wc->tdbl = (wc->tdbl + 1) % ERING_SIZE; - wc->intcount++; - t1_isr_misc(wc); - } else { - wc->rxints++; - t1_receiveprep(wc, wc->rdbl); - t1_reinit_descriptor(wc, tx, wc->rdbl, "rxchk"); - wc->rdbl = (wc->rdbl + 1) % ERING_SIZE; - } - return 1; - } - return 0; -} - -static int t1_hardware_init(struct t1 *wc) +static void +t1_handle_transmit(void* vbb, void* context) { - /* Hardware stuff */ - unsigned int reg; - unsigned long newjiffies; - - /* Initialize descriptors */ - t1_init_descriptors(wc); - - /* Enable I/O Access */ - pci_read_config_dword(wc->dev, PCI_COMMAND, ®); - reg |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_dword(wc->dev, PCI_COMMAND, reg); - debug_printk(1, "PCI Config reg is %08x\n", reg); - - t1_setctl(wc, 0x0000, 0xfff88001); - - newjiffies = jiffies + HZ/10; - while(((reg = t1_getctl(wc,0x0000)) & 0x00000001) && ( time_after(newjiffies,jiffies) )); - debug_printk(1, "ctlreg 0x0000 now=%08x!\n", reg); - - t1_setctl(wc, 0x0000, 0xfff88000); - - /* Configure watchdogs, access, etc */ - t1_setctl(wc, 0x0030, 0x00280048); - t1_setctl(wc, 0x0078, 0x00000013 /* | (1 << 28) */); - - reg = t1_getctl(wc, 0x00fc); - t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x7); /* normal mode */ - t1_setsdi(wc, 0x00, 0x0100); - t1_setsdi(wc, 0x16, 0x2100); - debug_printk(1, "Detected SDI REG0: %08x\n", t1_getsdi(wc, 0x00)); - debug_printk(1, "Detected SDI REG1: %08x\n", t1_getsdi(wc, 0x01)); - debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02)); - - reg = t1_getctl(wc, 0x00fc); - debug_printk(1, "(pre) Reg fc is %08x\n", reg); - - t1_setctl(wc, 0x00fc, (reg & ~0x7) | 0x4); /* mac only */ - t1_setsdi(wc, 0x00, 0x0100); /* full duplex */ - t1_setsdi(wc, 0x16, 0x2100); - reg = t1_getctl(wc, 0x00fc); - debug_printk(1, "(post) ctlreg 0xfc=%08x\n", reg); - debug_printk(1, "Detected SDI REG2: %08x\n", t1_getsdi(wc, 0x02)); - debug_printk(1, "ctlreg 0x0088=%08x\n", t1_getctl(wc, 0x0088)); - - return 0; + struct t1* wc = context; + /* Either this function is called from within interrupt context, or + * the reglock will never be acquired from interrupt context, so it's + * safe to grab it without locking interrupt. + */ + memset(vbb, 0, SFRAME_SIZE); + spin_lock(&wc->reglock); + wc->txints++; + t1_transmitprep(wc, vbb); + wc->intcount++; + t1_isr_misc(wc); + spin_unlock(&wc->reglock); + voicebus_transmit(wc->vb, vbb); } - -ZAP_IRQ_HANDLER(te12xp_interrupt) +static void +t1_handle_receive(void* vbb, void* context) { - struct t1 *wc = dev_id; - unsigned int ints; - int res; - - /* Read interrupts */ + struct t1* wc = context; + wc->rxints++; + /* Either this function is called from within interrupt context, or + * the reglock will never be acquired from interrupt context, so it's + * safe to grab it without locking interrupt. + */ spin_lock(&wc->reglock); - ints = __t1_getctl(wc, 0x0028); - ints &= 0x3fef; /* Just look at the interrupt conditions */ - - if (!ints) { - spin_unlock(&wc->reglock); -#ifdef LINUX26 - return IRQ_NONE; -#else - return; -#endif - } - - /* clear interrupts interrupts (we only get here if interrupt is for us) */ - __t1_setctl(wc, 0x0028, ints); - - if (ints & 0x00000041) { - do { - res = t1_check_descriptor(wc, 0); - res |= t1_check_descriptor(wc, 1); - } while(res); - } - - if (ints & 0x0000a3ae) { - /* This will allow us to recover if interrupts are held for a long period of time */ - debug_printk(1, "Abnormal interrupt %08x detected\n", ints); - __t1_setctl(wc, 0x0008, 0x00000000); - __t1_setctl(wc, 0x0010, 0x00000000); - } + t1_receiveprep(wc, vbb); spin_unlock(&wc->reglock); - -#ifdef LINUX26 - return IRQ_RETVAL(1); -#endif } static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1937,6 +1586,8 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi struct t1 *wc; struct t1_desc *d = (struct t1_desc *) ent->driver_data; unsigned int x; + int res; + int startinglatency; for (x = 0; x < sizeof(ifaces) / sizeof(ifaces[0]); x++) if (!ifaces[x]) break; @@ -1946,9 +1597,7 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi return -EIO; } - if (pci_enable_device(pdev)) - return -EIO; - +retry: wc = kmalloc(sizeof(*wc), GFP_KERNEL); if (!wc) return -ENOMEM; @@ -1956,72 +1605,44 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi ifaces[x] = wc; memset(wc, 0, sizeof(*wc)); spin_lock_init(&wc->reglock); - wc->iobase = pci_resource_start(pdev, 0); - wc->dev = pdev; wc->variety = d->name; - /* Keep track of whether we need to free the region */ - if (request_region(wc->iobase, 0xff, te12xp_driver.name)) - wc->freeregion = 1; - - /* Allocate enough memory for two zt chunks, receive and transmit. - * Each sample uses 32 bits. Allocate an extra set just for - * control too */ - wc->writechunk = (int *) pci_alloc_consistent(pdev, PCI_WINDOW_SIZE, &wc->writedma); - if (!wc->writechunk) { - module_printk("Unable to allocate DMA-able memory\n"); - if (wc->freeregion) - release_region(wc->iobase, 0xff); + wc->txident = 1; + + init_waitqueue_head(&wc->regq); + snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", x); + if ((res=voicebus_init(pdev, SFRAME_SIZE, wc->name, + t1_handle_receive, t1_handle_transmit, wc, &wc->vb))) + { + WARN_ON(1); kfree(wc); - return -ENOMEM; + return res; } - wc->readchunk = wc->writechunk + SFRAME_SIZE / 2; /* in doublewords */ - wc->readdma = wc->writedma + SFRAME_SIZE * 2; /* in bytes */ - - wc->descripchunk = wc->readchunk + SFRAME_SIZE / 2; /* in doublewords */ - wc->descripdma = wc->readdma + SFRAME_SIZE * 2; /* in bytes */ - - /* Initialize Write/Buffers to all blank data */ - memset((void *)wc->writechunk, 0x00, SFRAME_SIZE * 2); - memset((void *)wc->readchunk, 0x00, SFRAME_SIZE * 2); - - init_waitqueue_head(&wc->regq); - - /* Enable bus mastering */ - pci_set_master(pdev); - /* Keep track of which device we are */ pci_set_drvdata(pdev, wc); - - if (request_irq(pdev->irq, te12xp_interrupt, ZAP_IRQ_SHARED, te12xp_driver.name, wc)) { - module_printk("Unable to request IRQ %d\n", pdev->irq); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - kfree(wc); - return -EIO; - } - - if (t1_hardware_init(wc)) { - /* Set Reset Low */ - t1_stop_dma(wc); - /* Free Resources */ - free_irq(pdev->irq, wc); - if (wc->freeregion) - release_region(wc->iobase, 0xff); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *) wc->writechunk, wc->writedma); - pci_set_drvdata(pdev, NULL); - - kfree(wc); - return -EIO; - + if (VOICEBUS_DEFAULT_LATENCY != latency) { + voicebus_set_minlatency(wc->vb, latency); } - - t1_enable_interrupts(wc); - t1_start_dma(wc); + voicebus_start(wc->vb); + startinglatency = voicebus_current_latency(wc->vb); t1_hardware_post_init(wc); t1_software_init(wc); + if (voicebus_current_latency(wc->vb) > startinglatency) { + /* The voicebus library increased the latency during + * initialization because the host wasn't able to service the + * interrupts from the adapter quickly enough. In this case, + * we'll increase our latency and restart the initialization. + */ + printk(KERN_NOTICE "%s: Restarting board initialization " \ + "after increasing latency.\n", wc->name); + latency = voicebus_current_latency(wc->vb); + zt_unregister(&wc->span); + voicebus_release(wc->vb); + wc->vb = NULL; + kfree(wc); + wc = NULL; + goto retry; + } module_printk("Found a %s\n", wc->variety); return 0; @@ -2045,19 +1666,14 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev) destroy_workqueue(vpm150m->wq); } #endif - /* Stop any DMA */ - t1_stop_dma(wc); - - /* In case hardware is still there */ - t1_disable_interrupts(wc); - + + BUG_ON(!wc->vb); + voicebus_release(wc->vb); + wc->vb = NULL; + if (debug && wc->isrreaderrors) debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors); - /* Immediately free resources */ - free_irq(pdev->irq, wc); - pci_free_consistent(pdev, PCI_WINDOW_SIZE, (void *)wc->writechunk, wc->writedma); - #ifdef VPM_SUPPORT if(vpm150m) { spin_lock_irqsave(&wc->reglock, flags); @@ -2084,7 +1700,7 @@ static struct pci_device_id te12xp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, te12xp_pci_tbl); struct pci_driver te12xp_driver = { - name: "wcte12x[p]", + name: "wcte12xp", probe: te12xp_init_one, #ifdef LINUX26 remove: __devexit_p(te12xp_remove_one), @@ -2117,13 +1733,11 @@ module_param(loopback, int, S_IRUGO | S_IWUSR); module_param(t1e1override, int, S_IRUGO | S_IWUSR); module_param(j1mode, int, S_IRUGO | S_IWUSR); module_param(alarmdebounce, int, S_IRUGO | S_IWUSR); +module_param(latency, int, S_IRUGO | S_IWUSR); #ifdef VPM_SUPPORT module_param(vpmsupport, int, S_IRUGO | S_IWUSR); module_param(vpmdtmfsupport, int, S_IRUGO | S_IWUSR); module_param(vpmtsisupport, int, S_IRUGO | S_IWUSR); -module_param(vpmnlptype, int, S_IRUGO | S_IWUSR); -module_param(vpmnlpthresh, int, S_IRUGO | S_IWUSR); -module_param(vpmnlpmaxsupp, int, S_IRUGO | S_IWUSR); #endif #else MODULE_PARM(debug, "i"); -- cgit v1.2.3