diff options
Diffstat (limited to 'drivers/dahdi/wcte12xp/base.c')
-rw-r--r-- | drivers/dahdi/wcte12xp/base.c | 906 |
1 files changed, 350 insertions, 556 deletions
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c index 4209842..9294350 100644 --- a/drivers/dahdi/wcte12xp/base.c +++ b/drivers/dahdi/wcte12xp/base.c @@ -8,7 +8,7 @@ * Matthew Fredrickson <creslin@digium.com> * William Meadows <wmeadows@digium.com> * - * Copyright (C) 2007-2008, Digium, Inc. + * Copyright (C) 2007-2009, Digium, Inc. * * All rights reserved. * @@ -35,6 +35,9 @@ #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/moduleparam.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/delay.h> #include <dahdi/kernel.h> @@ -50,36 +53,6 @@ struct pci_driver te12xp_driver; -static int chanmap_t1[] = -{ 2,1,0, - 6,5,4, - 10,9,8, - 14,13,12, - 18,17,16, - 22,21,20, - 26,25,24, - 30,29,28 }; - -static int chanmap_e1[] = -{ 2,1,0, - 7,6,5,4, - 11,10,9,8, - 15,14,13,12, - 19,18,17,16, - 23,22,21,20, - 27,26,25,24, - 31,30,29,28 }; - -static int chanmap_e1uc[] = -{ 3,2,1,0, - 7,6,5,4, - 11,10,9,8, - 15,14,13,12, - 19,18,17,16, - 23,22,21,20, - 27,26,25,24, - 31,30,29,28 }; - int debug = 0; static int j1mode = 0; static int alarmdebounce = 0; @@ -108,33 +81,65 @@ static struct t1_desc te120p = { "Wildcard TE120P", 0 }; static struct t1_desc te122 = { "Wildcard TE122", 0 }; static struct t1_desc te121 = { "Wildcard TE121", 0 }; -int schluffen(wait_queue_head_t *q) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static kmem_cache_t *cmd_cache; +#else +static struct kmem_cache *cmd_cache; +#endif + +static struct command *get_free_cmd(struct t1 *wc) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(q, &wait); - current->state = TASK_INTERRUPTIBLE; - if (!signal_pending(current)) schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(q, &wait); - if (signal_pending(current)) return -ERESTARTSYS; - return(0); + struct command *cmd; + cmd = kmem_cache_alloc(cmd_cache, GFP_ATOMIC); + if (cmd) { + memset(cmd, 0, sizeof(*cmd)); + INIT_LIST_HEAD(&cmd->node); + } + return cmd; } -static inline int empty_slot(struct t1 *wc) +static void free_cmd(struct t1 *wc, struct command *cmd) { - unsigned int x; + kmem_cache_free(cmd_cache, cmd); +} - for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) { - if (!wc->cmdq.cmds[x].flags && !wc->cmdq.cmds[x].address) - return x; +static struct command *get_pending_cmd(struct t1 *wc) +{ + struct command *cmd = NULL; + unsigned long flags; + spin_lock_irqsave(&wc->cmd_list_lock, flags); + if (!list_empty(&wc->pending_cmds)) { + cmd = list_entry(wc->pending_cmds.next, struct command, node); + list_move_tail(&cmd->node, &wc->active_cmds); } - return -1; + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); + return cmd; +} + +static void submit_cmd(struct t1 *wc, struct command *cmd) +{ + unsigned long flags; + if (cmd->flags & (__CMD_RD | __CMD_PINS)) + init_completion(&cmd->complete); + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_add_tail(&cmd->node, &wc->pending_cmds); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); +} + +static void resend_cmds(struct t1 *wc) +{ + unsigned long flags; + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_splice_init(&wc->active_cmds, &wc->pending_cmds); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } -static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot) +static void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk, int eframe, int slot) { struct command *curcmd=NULL; - unsigned int x; + u16 address; + u8 data; + u32 flags; /* Skip audio */ writechunk += 66; @@ -143,287 +148,145 @@ static inline void cmd_dequeue(struct t1 *wc, volatile unsigned char *writechunk /* only 6 useable cs slots per */ /* framer */ - for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) { - if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) && - !(wc->cmdq.cmds[x].flags & (__CMD_TX | __CMD_FIN))) { - curcmd = &wc->cmdq.cmds[x]; - wc->cmdq.cmds[x].flags |= __CMD_TX; - wc->cmdq.cmds[x].ident = wc->txident; - break; - } - } - if (!curcmd) { - curcmd = &wc->dummy; + curcmd = get_pending_cmd(wc); + if (curcmd) { + curcmd->cs_slot = slot; + curcmd->ident = wc->txident; + + address = curcmd->address; + data = curcmd->data; + flags = curcmd->flags; + } else { /* If nothing else, use filler */ - curcmd->address = 0x4a; - curcmd->data = 0x00; - curcmd->flags = __CMD_RD; + address = 0x4a; + data = 0; + flags = __CMD_RD; } - curcmd->cs_slot = slot; - if (curcmd->flags & __CMD_WR) - writechunk[CMD_BYTE(slot,0,0)] = 0x0c; /* 0c write command */ - else if (curcmd->flags & __CMD_LEDS) - writechunk[CMD_BYTE(slot,0,0)] = 0x10 | ((curcmd->address) & 0x0E); /* led set command */ - else if (curcmd->flags & __CMD_PINS) - writechunk[CMD_BYTE(slot,0,0)] = 0x30; /* CPLD2 pin state */ + + if (flags & __CMD_WR) + writechunk[CMD_BYTE(slot, 0, 0)] = 0x0c; /* 0c write command */ + else if (flags & __CMD_LEDS) + writechunk[CMD_BYTE(slot, 0, 0)] = 0x10 | ((address) & 0x0E); /* led set command */ + else if (flags & __CMD_PINS) + writechunk[CMD_BYTE(slot, 0, 0)] = 0x30; /* CPLD2 pin state */ else - writechunk[CMD_BYTE(slot,0,0)] = 0x0a; /* read command */ - writechunk[CMD_BYTE(slot,1,0)] = curcmd->address; - writechunk[CMD_BYTE(slot,2,0)] = curcmd->data; - } + writechunk[CMD_BYTE(slot, 0, 0)] = 0x0a; /* read command */ + writechunk[CMD_BYTE(slot, 1, 0)] = address; + writechunk[CMD_BYTE(slot, 2, 0)] = data; + } } static inline void cmd_decipher(struct t1 *wc, volatile unsigned char *readchunk) { - unsigned char ident, cs_slot; - unsigned int x; - unsigned int is_vpm = 0; + struct command *cmd = NULL; + unsigned long flags; + const int IS_VPM = 0; /* Skip audio */ readchunk += 66; - /* Search for any pending results */ - for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) { - if ((wc->cmdq.cmds[x].flags & (__CMD_RD | __CMD_WR | __CMD_LEDS | __CMD_PINS)) && - (wc->cmdq.cmds[x].flags & (__CMD_TX)) && - !(wc->cmdq.cmds[x].flags & (__CMD_FIN))) { - ident = wc->cmdq.cmds[x].ident; - cs_slot = wc->cmdq.cmds[x].cs_slot; - - if (ident == wc->rxident) { - /* Store result */ - wc->cmdq.cmds[x].data |= readchunk[CMD_BYTE(cs_slot,2,is_vpm)]; - /*printk(KERN_INFO "answer in rxident=%d cs_slot=%d is %d CMD_BYTE=%d jiffies=%d\n", ident, cs_slot, last_read_command, CMD_BYTE(cs_slot, 2), jiffies); */ - wc->cmdq.cmds[x].flags |= __CMD_FIN; - if (wc->cmdq.cmds[x].flags & (__CMD_WR | __CMD_LEDS)) - /* clear out writes (and leds) since they need no ack */ - memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x])); - } - } - } -} - -static inline int t1_setreg_full(struct t1 *wc, int addr, int val, const int inisr, int vpm_num) -{ - unsigned long flags = 0; - int hit; - int ret; - - - do { - if (!inisr) - spin_lock_irqsave(&wc->reglock, flags); - hit = empty_slot(wc); - if (hit > -1) { - wc->cmdq.cmds[hit].address = addr; - wc->cmdq.cmds[hit].data = val; - wc->cmdq.cmds[hit].flags |= __CMD_WR; - if(vpm_num >= 0) { - wc->cmdq.cmds[hit].flags |= __CMD_VPM; - wc->cmdq.cmds[hit].vpm_num = vpm_num; - } - } - if (inisr) + spin_lock_irqsave(&wc->cmd_list_lock, flags); + while (!list_empty(&wc->active_cmds)) { + cmd = list_entry(wc->active_cmds.next, struct command, node); + if (cmd->ident != wc->rxident) break; - else - spin_unlock_irqrestore(&wc->reglock, flags); - if (hit < 0) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit < 0); - - return (hit > -1) ? 0 : -1; -} -static inline int t1_setreg(struct t1 *wc, int addr, int val) -{ - return t1_setreg_full(wc, addr, val, 0, NOT_VPM); -} - -/*************************************************************************** - * clean_leftovers() - * - * Check for unconsumed isr register reads and clean them up. - **************************************************************************/ -static inline void clean_leftovers(struct t1 *wc) -{ - unsigned int x; - int count = 0; - - /* 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_ISR) && - !(wc->cmdq.cmds[x].flags & __CMD_FIN)) { - debug_printk(1,"leftover isr read! %d", count); - memset(&wc->cmdq.cmds[x], 0, sizeof(wc->cmdq.cmds[x])); + if (cmd->flags & (__CMD_WR | __CMD_LEDS)) { + /* Nobody is waiting on writes...so let's just + * free them here. */ + list_del(&cmd->node); + free_cmd(wc, cmd); + } else { + cmd->data |= readchunk[CMD_BYTE(cmd->cs_slot, 2, IS_VPM)]; + list_del_init(&cmd->node); + complete(&cmd->complete); } } + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); } -/******************************************************************** - * t1_getreg_isr() - * - * Called in interrupt context to retrieve a value already requested - * by the normal t1_getreg(). - *******************************************************************/ -static inline int t1_getreg_isr(struct t1 *wc, int addr) +static inline int t1_setreg_full(struct t1 *wc, int addr, int val, int vpm_num) { - int hit=-1; - int ret; - unsigned int x; - - /* 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].address==addr)) - { - if (wc->cmdq.cmds[x].flags & __CMD_FIN) { - hit = x; - break; - } - else { - /* still in progress. */ - return -1; - } - } + struct command *cmd; + cmd = get_free_cmd(wc); + if (!cmd) { + WARN_ON(1); + return -ENOMEM; } - - if (hit < 0) { - debug_printk(2, "t1_getreg_isr() no addr=%02x\n", addr); - return -1; /* oops, couldn't find it */ + cmd->address = addr; + cmd->data = val; + cmd->flags |= __CMD_WR; + if (vpm_num >= 0) { + cmd->flags |= __CMD_VPM; + cmd->vpm_num = vpm_num; } - - ret = wc->cmdq.cmds[hit].data; - memset(&wc->cmdq.cmds[hit], 0, sizeof(struct command)); - - return ret; + submit_cmd(wc, cmd); + return 0; } -static inline int t1_getreg_full(struct t1 *wc, int addr, const int inisr, int vpm_num) +static inline int t1_setreg(struct t1 *wc, int addr, int val) { - unsigned long flags = 0; - int hit; - int ret = 0; + return t1_setreg_full(wc, addr, val, NOT_VPM); +} - do { - if (!inisr) { - spin_lock_irqsave(&wc->reglock, flags); - } - hit = empty_slot(wc); - if (hit > -1) { - wc->cmdq.cmds[hit].address = addr; - wc->cmdq.cmds[hit].data = 0x00; - wc->cmdq.cmds[hit].flags |= __CMD_RD; - if(vpm_num >= 0) { - wc->cmdq.cmds[hit].flags |= __CMD_VPM; - wc->cmdq.cmds[hit].vpm_num = vpm_num; - } - if (inisr) - wc->cmdq.cmds[hit].flags |= __CMD_ISR; - } - if (inisr) /* must be requested in t1_getreg_isr() */ - return (hit > -1) ? 0 : -1; - else { - spin_unlock_irqrestore(&wc->reglock, flags); - } - if (hit < 0) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit < 0); +static inline int t1_getreg_full(struct t1 *wc, int addr, int vpm_num) +{ + struct command *cmd = NULL; + int ret; - do { - spin_lock_irqsave(&wc->reglock, flags); - if (wc->cmdq.cmds[hit].flags & __CMD_FIN) { - ret = wc->cmdq.cmds[hit].data; - memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit])); - hit = -1; - } - spin_unlock_irqrestore(&wc->reglock, flags); - if (hit > -1) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit > -1); + might_sleep(); + cmd = get_free_cmd(wc); + if (!cmd) + return -ENOMEM; + cmd->address = addr; + cmd->data = 0x00; + cmd->flags = __CMD_RD; + if (vpm_num > -1) { + cmd->flags |= __CMD_VPM; + cmd->vpm_num = vpm_num; + } + submit_cmd(wc, cmd); + wait_for_completion(&cmd->complete); + ret = cmd->data; + free_cmd(wc, cmd); return ret; } -static inline int t1_getreg(struct t1 *wc, int addr, int inisr) +static int t1_getreg(struct t1 *wc, int addr) { - return t1_getreg_full(wc, addr, inisr, NOT_VPM); + return t1_getreg_full(wc, addr, NOT_VPM); } -static inline int t1_setleds(struct t1 *wc, int leds, const int inisr) +static void t1_setleds(struct t1 *wc, int leds) { - unsigned long flags = 0; - int hit; - int ret = 0; + struct command *cmd; - leds = ~leds & 0x0E; /* invert the LED bits (3 downto 1)*/ - - do { - if (!inisr) { - spin_lock_irqsave(&wc->reglock, flags); - } - hit = empty_slot(wc); - if (hit > -1) { - wc->cmdq.cmds[hit].flags |= __CMD_LEDS; - wc->cmdq.cmds[hit].address = leds; - } - if (inisr) { - break; - } else { - spin_unlock_irqrestore(&wc->reglock, flags); - } - if (hit < 0) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit < 0); + leds = (~leds) & 0x0E; /* invert the LED bits (3 downto 1)*/ - return (hit > -1) ? 0 : -1; + cmd = get_free_cmd(wc); + if (!cmd) + return; + cmd->flags |= __CMD_LEDS; + cmd->address = leds; + submit_cmd(wc, cmd); } static inline int t1_getpins(struct t1 *wc, int inisr) { - unsigned long flags; - int hit; int ret = 0; - - do { - spin_lock_irqsave(&wc->reglock, flags); - hit = empty_slot(wc); - if (hit > -1) { - wc->cmdq.cmds[hit].address = 0x00; - wc->cmdq.cmds[hit].data = 0x00; - wc->cmdq.cmds[hit].flags |= __CMD_PINS; - } - spin_unlock_irqrestore(&wc->reglock, flags); - if (inisr) - return (hit > -1) ? 0 : -1; - if (hit < 0) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit < 0); - - do { - spin_lock_irqsave(&wc->reglock, flags); - if (wc->cmdq.cmds[hit].flags & __CMD_FIN) { - ret = wc->cmdq.cmds[hit].data; - memset(&wc->cmdq.cmds[hit], 0, sizeof(wc->cmdq.cmds[hit])); - hit = -1; - } - spin_unlock_irqrestore(&wc->reglock, flags); - if (hit > -1) { - if ((ret = schluffen(&wc->regq))) - return ret; - } - } while (hit > -1); - + struct command *cmd; + + cmd = get_free_cmd(wc); + BUG_ON(!cmd); + + cmd->address = 0x00; + cmd->data = 0x00; + cmd->flags = __CMD_PINS; + submit_cmd(wc, cmd); + wait_for_completion(&cmd->complete); + ret = cmd->data; + free_cmd(wc, cmd); return ret; } @@ -440,7 +303,7 @@ static void __t1xxp_set_clear(struct t1 *wc, int channo) if (((i % 8)==7) && /* write byte every 8 channels */ ((channo < 0) || /* channo=-1 means all channels */ (j == (channo-1)/8) )) { /* only the register for this channo */ - ret = t1_setreg_full(wc, 0x2f + j, val, 1, NOT_VPM); + ret = t1_setreg_full(wc, 0x2f + j, val, NOT_VPM); if (ret < 0) module_printk("set_clear failed for chan %d!\n",i); val = 0; @@ -448,16 +311,33 @@ static void __t1xxp_set_clear(struct t1 *wc, int channo) } } -static void t1_release(struct t1 *wc) +static void free_wc(struct t1 *wc) { unsigned int x; + unsigned long flags; + struct command *cmd; + LIST_HEAD(list); - dahdi_unregister(&wc->span); - for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { + for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) kfree(wc->chans[x]); + + spin_lock_irqsave(&wc->cmd_list_lock, flags); + list_splice_init(&wc->active_cmds, &list); + list_splice_init(&wc->pending_cmds, &list); + spin_unlock_irqrestore(&wc->cmd_list_lock, flags); + while (!list_empty(&list)) { + cmd = list_entry(list.next, struct command, node); + list_del(&cmd->node); + free_cmd(wc, cmd); } kfree(wc); - printk(KERN_INFO "Freed a Wildcard TE12xP\n"); +} + +static void t1_release(struct t1 *wc) +{ + dahdi_unregister(&wc->span); + printk(KERN_INFO "Freed a Wildcard TE12xP.\n"); + free_wc(wc); } static void t4_serial_setup(struct t1 *wc) @@ -668,9 +548,6 @@ static void t1_configure_e1(struct t1 *wc, int lineconfig) static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) { - int alreadyrunning = wc->span.flags & DAHDI_FLAG_RUNNING; - unsigned long flags; - if (wc->spantype == TYPE_E1) { /* if this is an E1 card */ t1_configure_e1(wc, span->lineconfig); } else { /* is a T1 card */ @@ -678,10 +555,7 @@ static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) __t1xxp_set_clear(wc, -1); } - spin_lock_irqsave(&wc->reglock, flags); - if (!alreadyrunning) - wc->span.flags |= DAHDI_FLAG_RUNNING; - spin_unlock_irqrestore(&wc->reglock, flags); + set_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags); } static int t1xxp_startup(struct dahdi_span *span) @@ -705,23 +579,18 @@ static int t1xxp_startup(struct dahdi_span *span) static int t1xxp_shutdown(struct dahdi_span *span) { struct t1 *wc = span->pvt; - unsigned long flags; - t1_setreg(wc, 0x46, 0x41); /* GCR: Interrupt on Activation/Deactivation of AIX, LOS */ - spin_lock_irqsave(&wc->reglock, flags); - span->flags &= ~DAHDI_FLAG_RUNNING; - spin_unlock_irqrestore(&wc->reglock, flags); + clear_bit(DAHDI_FLAGBIT_RUNNING, &span->flags); return 0; } static int t1xxp_chanconfig(struct dahdi_chan *chan, int sigtype) { struct t1 *wc = chan->pvt; - int alreadyrunning = chan->span->flags & DAHDI_FLAG_RUNNING; - - if (alreadyrunning && (wc->spantype != TYPE_E1)) + if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) && + (wc->spantype != TYPE_E1)) { __t1xxp_set_clear(wc, chan->channo); - + } return 0; } @@ -730,14 +599,13 @@ static int t1xxp_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc struct t1 *wc = span->pvt; /* Do we want to SYNC on receive or not */ - wc->sync = lc->sync; - if (wc->sync) - wc->ctlreg |= 0x80; + if (lc->sync) + set_bit(7, &wc->ctlreg); else - wc->ctlreg &= ~0x80; + clear_bit(7, &wc->ctlreg); /* If already running, apply changes immediately */ - if (span->flags & DAHDI_FLAG_RUNNING) + if (test_bit(DAHDI_FLAGBIT_RUNNING, &span->flags)) return t1xxp_startup(span); return 0; @@ -766,7 +634,7 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ - t1_setreg_full(wc,0x71 + b,c,1,NOT_VPM); + t1_setreg_full(wc, 0x71 + b, c, NOT_VPM); } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { n = chan->chanpos - 1; b = (n / 4); @@ -778,8 +646,8 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ - t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM); - t1_setreg_full(wc,0x70 + b + 6,c,1,NOT_VPM); + t1_setreg_full(wc, 0x70 + b, c, NOT_VPM); + t1_setreg_full(wc, 0x70 + b + 6, c, NOT_VPM); } else if (wc->span.lineconfig & DAHDI_CONFIG_ESF) { n = chan->chanpos - 1; b = (n / 2); @@ -791,124 +659,84 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) wc->txsigs[b] = c; spin_unlock_irqrestore(&wc->reglock, flags); /* output them to the chip */ - t1_setreg_full(wc,0x70 + b,c,1,NOT_VPM); + t1_setreg_full(wc, 0x70 + b, c, NOT_VPM); } debug_printk(2,"Finished setting RBS bits\n"); return 0; } -static inline void __t1_check_sigbits_reads(struct t1 *wc) -{ - int i; - - if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) - return; - if (wc->spantype == TYPE_E1) { - for (i = 0; i < 15; i++) { - if (t1_getreg(wc, 0x71 + i, 1)) - wc->isrreaderrors++; - } - } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { - for (i = 0; i < 24; i+=4) { - if (t1_getreg(wc, 0x70 + (i >> 2), 1)) - wc->isrreaderrors++; - } - } else { - for (i = 0; i < 24; i+=2) { - if (t1_getreg(wc, 0x70 + (i >> 1), 1)) - wc->isrreaderrors++; - } - } -} - -static inline void __t1_check_sigbits(struct t1 *wc) +static inline void t1_check_sigbits(struct t1 *wc) { int a,i,rxs; - if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) + if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; if (wc->spantype == TYPE_E1) { for (i = 0; i < 15; i++) { - a = t1_getreg_isr(wc, 0x71 + i); + a = t1_getreg(wc, 0x71 + i); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+16]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+16]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i+16], rxs); - spin_lock(&wc->reglock); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i], rxs); - spin_lock(&wc->reglock); } } } } } else if (wc->span.lineconfig & DAHDI_CONFIG_D4) { for (i = 0; i < 24; i+=4) { - a = t1_getreg_isr(wc, 0x70 + (i>>2)); + a = t1_getreg(wc, 0x70 + (i>>2)); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0x3) << 2; if (!(wc->span.chans[i+3]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+3]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i+3], rxs); - spin_lock(&wc->reglock); } } rxs = (a & 0xc); if (!(wc->span.chans[i+2]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+2]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i+2], rxs); - spin_lock(&wc->reglock); } } rxs = (a >> 2) & 0xc; if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i+1], rxs); - spin_lock(&wc->reglock); } } rxs = (a >> 4) & 0xc; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i], rxs); - spin_lock(&wc->reglock); } } } } } else { for (i = 0; i < 24; i+=2) { - a = t1_getreg_isr(wc, 0x70 + (i>>1)); + a = t1_getreg(wc, 0x70 + (i>>1)); if (a > -1) { /* Get high channel in low bits */ rxs = (a & 0xf); if (!(wc->span.chans[i+1]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i+1]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i+1], rxs); - spin_lock(&wc->reglock); } } rxs = (a >> 4) & 0xf; if (!(wc->span.chans[i]->sig & DAHDI_SIG_CLEAR)) { if (wc->span.chans[i]->rxsig != rxs) { - spin_unlock(&wc->reglock); dahdi_rbsbits(wc->span.chans[i], rxs); - spin_lock(&wc->reglock); } } } @@ -975,29 +803,15 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) static int t1xxp_open(struct dahdi_chan *chan) { - struct t1 *wc = chan->pvt; - - if (wc->dead) - return -ENODEV; - wc->usecount++; - - try_module_get(THIS_MODULE); - - return 0; + if (!try_module_get(THIS_MODULE)) + return -ENXIO; + else + return 0; } static int t1xxp_close(struct dahdi_chan *chan) { - struct t1 *wc = chan->pvt; - - wc->usecount--; - module_put(THIS_MODULE); - - /* If we're dead, release us now */ - if (!wc->usecount && wc->dead) - t1_release(wc); - return 0; } @@ -1091,6 +905,7 @@ static int t1xxp_echocan_with_params(struct dahdi_chan *chan, struct dahdi_echoc static int t1_software_init(struct t1 *wc) { int x; + int num; struct pci_dev* dev; dev = voicebus_get_pci_dev(wc->vb); @@ -1108,9 +923,9 @@ static int t1_software_init(struct t1 *wc) t4_serial_setup(wc); - wc->num = x; - sprintf(wc->span.name, "WCT1/%d", wc->num); - snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); + num = x; + sprintf(wc->span.name, "WCT1/%d", num); + snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num); wc->span.manufacturer = "Digium"; strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1); @@ -1151,11 +966,11 @@ static int t1_software_init(struct t1 *wc) wc->span.deflaw = DAHDI_LAW_MULAW; } wc->span.chans = wc->chans; - wc->span.flags = DAHDI_FLAG_RBS; + set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags); wc->span.pvt = wc; init_waitqueue_head(&wc->span.maintq); for (x = 0; x < wc->span.channels; x++) { - sprintf(wc->chans[x]->name, "WCT1/%d/%d", wc->num, x + 1); + sprintf(wc->chans[x]->name, "WCT1/%d/%d", num, x + 1); wc->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_EM_E1 | DAHDI_SIG_FXSLS | DAHDI_SIG_FXSGS | DAHDI_SIG_MTP2 | DAHDI_SIG_FXSKS | DAHDI_SIG_FXOLS | DAHDI_SIG_DACS_RBS | @@ -1167,7 +982,8 @@ static int t1_software_init(struct t1 *wc) module_printk("Unable to register span with DAHDI\n"); return -1; } - wc->initialized = 1; + + set_bit(INITIALIZED, &wc->bit_flags); return 0; } @@ -1175,12 +991,12 @@ static int t1_software_init(struct t1 *wc) #ifdef VPM_SUPPORT static inline unsigned char t1_vpm_in(struct t1 *wc, int unit, const unsigned int addr) { - return t1_getreg_full(wc, addr, 0, unit); + return t1_getreg_full(wc, addr, unit); } static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned int addr, const unsigned char val) { - return t1_setreg_full(wc, addr, val, 0, unit); + return t1_setreg_full(wc, addr, val, unit); } #endif @@ -1204,38 +1020,29 @@ static int t1_hardware_post_init(struct t1 *wc) } debug_printk(1, "spantype: %s\n", wc->spantype==1 ? "T1" : "E1"); - if (wc->spantype == TYPE_E1) { - if (unchannelized) - wc->chanmap = chanmap_e1uc; - else - wc->chanmap = chanmap_e1; - } else - wc->chanmap = chanmap_t1; /* what version of the FALC are we using? */ reg = t1_setreg(wc, 0x4a, 0xaa); - reg = t1_getreg(wc, 0x4a, 0); + reg = t1_getreg(wc, 0x4a); debug_printk(1, "FALC version: %08x\n", reg); /* make sure reads and writes work */ for (x = 0; x < 256; x++) { t1_setreg(wc, 0x14, x); - if ((reg = t1_getreg(wc, 0x14, 0)) != x) + reg = t1_getreg(wc, 0x14); + if (reg != x) module_printk("Wrote '%x' but read '%x'\n", x, reg); } - /* all LED's blank */ - wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg); - wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg); - t1_setleds(wc, wc->ledtestreg, 0); + t1_setleds(wc, wc->ledstate); #ifdef VPM_SUPPORT t1_vpm150m_init(wc); if (wc->vpm150m) { module_printk("VPM present and operational (Firmware version %x)\n", wc->vpm150m->version); - wc->ctlreg |= 0x10; /* turn on vpm (RX audio from vpm module) */ + set_bit(4, &wc->ctlreg); /* turn on vpm (RX audio from vpm module) */ if (vpmtsisupport) { debug_printk(1, "enabling VPM TSI pin\n"); - wc->ctlreg |= 0x01; /* turn on vpm timeslot interchange pin */ + set_bit(0, &wc->ctlreg); /* turn on vpm timeslot interchange pin */ } } #endif @@ -1243,32 +1050,19 @@ static int t1_hardware_post_init(struct t1 *wc) return 0; } -static inline void __t1_check_alarms_reads(struct t1 *wc) -{ - if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) - return; - - if (t1_getreg(wc, 0x4c, 1)) - wc->isrreaderrors++; - if (t1_getreg(wc, 0x20, 1)) - wc->isrreaderrors++; - if (t1_getreg(wc, 0x4d, 1)) - wc->isrreaderrors++; -} - -static inline void __t1_check_alarms(struct t1 *wc) +static inline void t1_check_alarms(struct t1 *wc) { unsigned char c,d; int alarms; int x,j; unsigned char fmr4; /* must read this always */ - if (!(wc->span.flags & DAHDI_FLAG_RUNNING)) + if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; - c = t1_getreg_isr(wc, 0x4c); - fmr4 = t1_getreg_isr(wc, 0x20); /* must read this even if we don't use it */ - d = t1_getreg_isr(wc, 0x4d); + c = t1_getreg(wc, 0x4c); + fmr4 = t1_getreg(wc, 0x20); /* must read this even if we don't use it */ + d = t1_getreg(wc, 0x4d); /* Assume no alarms */ alarms = 0; @@ -1282,16 +1076,16 @@ static inline void __t1_check_alarms(struct t1 *wc) we haven't found a multiframe since last loss of frame */ if (!wc->flags.nmf) { - t1_setreg_full(wc, 0x20, 0x9f | 0x20, 1, NOT_VPM); /* LIM0: Force RAI High */ + t1_setreg_full(wc, 0x20, 0x9f | 0x20, NOT_VPM); /* LIM0: Force RAI High */ wc->flags.nmf = 1; module_printk("NMF workaround on!\n"); } - t1_setreg_full(wc, 0x1e, 0xc3, 1, NOT_VPM); /* Reset to CRC4 mode */ - t1_setreg_full(wc, 0x1c, 0xf2, 1, NOT_VPM); /* Force Resync */ - t1_setreg_full(wc, 0x1c, 0xf0, 1, NOT_VPM); /* Force Resync */ + t1_setreg_full(wc, 0x1e, 0xc3, NOT_VPM); /* Reset to CRC4 mode */ + t1_setreg_full(wc, 0x1c, 0xf2, NOT_VPM); /* Force Resync */ + t1_setreg_full(wc, 0x1c, 0xf0, NOT_VPM); /* Force Resync */ } else if (!(c & 0x02)) { if (wc->flags.nmf) { - t1_setreg_full(wc, 0x20, 0x9f, 1, NOT_VPM); /* LIM0: Clear forced RAI */ + t1_setreg_full(wc, 0x20, 0x9f, NOT_VPM); /* LIM0: Clear forced RAI */ wc->flags.nmf = 0; module_printk("NMF workaround off!\n"); } @@ -1301,8 +1095,8 @@ static inline void __t1_check_alarms(struct t1 *wc) if ((!wc->span.mainttimer) && (d & 0x08)) { /* Loop-up code detected */ if ((wc->loopupcnt++ > 80) && (wc->span.maintstat != DAHDI_MAINT_REMOTELOOP)) { - t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM); /* LIM0: Disable any local loop */ - t1_setreg_full(wc, 0x37, 0xf6, 1, NOT_VPM); /* LIM1: Enable remote loop */ + t1_setreg_full(wc, 0x36, 0x08, NOT_VPM); /* LIM0: Disable any local loop */ + t1_setreg_full(wc, 0x37, 0xf6, NOT_VPM); /* LIM1: Enable remote loop */ wc->span.maintstat = DAHDI_MAINT_REMOTELOOP; } } else @@ -1311,8 +1105,8 @@ static inline void __t1_check_alarms(struct t1 *wc) if ((!wc->span.mainttimer) && (d & 0x10)) { /* Loop-down code detected */ if ((wc->loopdowncnt++ > 80) && (wc->span.maintstat == DAHDI_MAINT_REMOTELOOP)) { - t1_setreg_full(wc, 0x36, 0x08, 1, NOT_VPM); /* LIM0: Disable any local loop */ - t1_setreg_full(wc, 0x37, 0xf0, 1, NOT_VPM); /* LIM1: Disable remote loop */ + t1_setreg_full(wc, 0x36, 0x08, NOT_VPM); /* LIM0: Disable any local loop */ + t1_setreg_full(wc, 0x37, 0xf0, NOT_VPM); /* LIM1: Disable remote loop */ wc->span.maintstat = DAHDI_MAINT_NONE; } } else @@ -1341,7 +1135,7 @@ static inline void __t1_check_alarms(struct t1 *wc) /* Keep track of recovering */ if ((!alarms) && wc->span.alarms) - wc->alarmtimer = DAHDI_ALARMSETTLE_TIME; + wc->alarmtimer = jiffies + 5*HZ; if (wc->alarmtimer) alarms |= DAHDI_ALARM_RECOVER; @@ -1350,12 +1144,12 @@ static inline void __t1_check_alarms(struct t1 *wc) module_printk("Setting yellow alarm\n"); /* We manually do yellow alarm to handle RECOVER and NOTOPEN, otherwise it's auto anyway */ - t1_setreg_full(wc, 0x20, fmr4 | 0x20, 1, NOT_VPM); + t1_setreg_full(wc, 0x20, fmr4 | 0x20, NOT_VPM); wc->flags.sendingyellow = 1; } else if (!alarms && wc->flags.sendingyellow) { module_printk("Clearing yellow alarm\n"); /* We manually do yellow alarm to handle RECOVER */ - t1_setreg_full(wc, 0x20, fmr4 & ~0x20, 1, NOT_VPM); + t1_setreg_full(wc, 0x20, fmr4 & ~0x20, NOT_VPM); wc->flags.sendingyellow = 0; } @@ -1364,86 +1158,57 @@ static inline void __t1_check_alarms(struct t1 *wc) if (wc->span.mainttimer || wc->span.maintstat) alarms |= DAHDI_ALARM_LOOPBACK; wc->span.alarms = alarms; - spin_unlock(&wc->reglock); dahdi_alarm_notify(&wc->span); - spin_lock(&wc->reglock); } -static inline void __handle_leds(struct t1 *wc) +static void handle_leds(struct t1 *wc) { + unsigned char led; + unsigned long flags; + + led = wc->ledstate; + if (wc->span.alarms & (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE)) { - wc->blinktimer++; - if (wc->blinktimer == 160) - wc->ledtestreg = SET_LED_RED(wc->ledtestreg); - if (wc->blinktimer == 480) { - wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg); - wc->blinktimer = 0; + /* When we're in red alarm, blink the led once a second. */ + if (time_after(jiffies, wc->blinktimer)) { + led = (led & __LED_GREEN) ? SET_LED_RED(led) : UNSET_LED_REDGREEN(led); } } else if (wc->span.alarms & DAHDI_ALARM_YELLOW) { - wc->yellowtimer++; - if (!(wc->yellowtimer % 2)) - wc->ledtestreg = SET_LED_RED(wc->ledtestreg); - else - wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg); + led = (led & __LED_RED) ? SET_LED_GREEN(led) : SET_LED_RED(led); } else { if (wc->span.maintstat != DAHDI_MAINT_NONE) - wc->ledtestreg = SET_LED_ORANGE(wc->ledtestreg); + led = SET_LED_ORANGE(led); else - wc->ledtestreg = UNSET_LED_ORANGE(wc->ledtestreg); - if (wc->span.flags & DAHDI_FLAG_RUNNING) - wc->ledtestreg = SET_LED_GREEN(wc->ledtestreg); - else - wc->ledtestreg = UNSET_LED_REDGREEN(wc->ledtestreg); - } + led = UNSET_LED_ORANGE(led); - if (wc->ledtestreg != wc->ledlastvalue) { - t1_setleds(wc, wc->ledtestreg, 1); - wc->ledlastvalue = wc->ledtestreg; + if (test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags)) + led = SET_LED_GREEN(led); + else + led = UNSET_LED_REDGREEN(led); } -} - -static void __t1_do_counters(struct t1 *wc) -{ - if (wc->alarmtimer) { - if (!--wc->alarmtimer) { - wc->span.alarms &= ~(DAHDI_ALARM_RECOVER); - dahdi_alarm_notify(&wc->span); + if (led != wc->ledstate) { + struct command *cmd; + cmd = get_free_cmd(wc); + if (cmd) { + wc->blinktimer = jiffies + HZ/2; + cmd->flags |= __CMD_LEDS; + cmd->address = ~led & 0x0E; + submit_cmd(wc, cmd); + spin_lock_irqsave(&wc->reglock, flags); + wc->ledstate = led; + spin_unlock_irqrestore(&wc->reglock, flags); } } } -static inline void t1_isr_misc(struct t1 *wc) -{ - const unsigned int x = wc->intcount & 0x3f; - int buffer_count = voicebus_current_latency(wc->vb); - - if (unlikely(!wc->initialized)) return; - - __handle_leds(wc); - - __t1_do_counters(wc); - 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 void t1_do_counters(struct t1 *wc) +{ + if (wc->alarmtimer && time_after(jiffies, wc->alarmtimer)) { + wc->span.alarms &= ~(DAHDI_ALARM_RECOVER); + wc->alarmtimer = 0; + dahdi_alarm_notify(&wc->span); } } @@ -1454,14 +1219,12 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk) int chan; /* Calculate Transmission */ - if (likely(wc->initialized)) { - spin_unlock(&wc->reglock); + if (likely(test_bit(INITIALIZED, &wc->bit_flags))) { dahdi_transmit(&wc->span); - spin_lock(&wc->reglock); } for (x = 0; x < DAHDI_CHUNKSIZE; x++) { - if (likely(wc->initialized)) { + if (likely(test_bit(INITIALIZED, &wc->bit_flags))) { for (chan = 0; chan < wc->span.channels; chan++) writechunk[(chan+1)*2] = wc->chans[chan]->writechunk[x]; } @@ -1472,7 +1235,9 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk) } #ifdef VPM_SUPPORT if(likely(wc->vpm150m)) { + spin_lock(&wc->reglock); vpm150m_cmd_dequeue(wc, writechunk, x); + spin_unlock(&wc->reglock); } #endif @@ -1484,25 +1249,13 @@ static inline void t1_transmitprep(struct t1 *wc, unsigned char* writechunk) } } -static inline void cmd_retransmit(struct t1 *wc) -{ - unsigned int x; - - for (x = 0; x < sizeof(wc->cmdq.cmds) / sizeof(wc->cmdq.cmds[0]); x++) { - if (!(wc->cmdq.cmds[x].flags & __CMD_FIN)) { - wc->cmdq.cmds[x].flags &= ~(__CMD_TX) ; /* clear __CMD_TX */ - wc->cmdq.cmds[x].ident = 0; - } - } -} - static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk) { int x,chan; unsigned char expected; for (x = 0; x < DAHDI_CHUNKSIZE; x++) { - if (likely(wc->initialized)) { + if (likely(test_bit(INITIALIZED, &wc->bit_flags))) { for (chan = 0; chan < wc->span.channels; chan++) { wc->chans[chan]->readchunk[x]= readchunk[(chan+1)*2]; } @@ -1513,65 +1266,75 @@ static inline void t1_receiveprep(struct t1 *wc, unsigned char* readchunk) wc->statreg = readchunk[EFRAME_SIZE + 2]; if (wc->rxident != expected) { wc->span.irqmisses++; - cmd_retransmit(wc); - if (unlikely(debug && wc->initialized)) + resend_cmds(wc); + if (unlikely(debug && test_bit(INITIALIZED, &wc->bit_flags))) module_printk("oops: rxident=%d expected=%d x=%d\n", wc->rxident, expected, x); } } cmd_decipher(wc, readchunk); #ifdef VPM_SUPPORT - if(wc->vpm150m) + if (wc->vpm150m) { + spin_lock(&wc->reglock); vpm150m_cmd_decipher(wc, readchunk); + spin_unlock(&wc->reglock); + } #endif readchunk += (EFRAME_SIZE + EFRAME_GAP); } /* echo cancel */ - if (likely(wc->initialized)) { - spin_unlock(&wc->reglock); + if (likely(test_bit(INITIALIZED, &wc->bit_flags))) { for (x = 0; x < wc->span.channels; x++) { dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->ec_chunk2[x]); memcpy(wc->ec_chunk2[x],wc->ec_chunk1[x],DAHDI_CHUNKSIZE); memcpy(wc->ec_chunk1[x],wc->chans[x]->writechunk,DAHDI_CHUNKSIZE); } dahdi_receive(&wc->span); - spin_lock(&wc->reglock); } - - /* Wake up anyone sleeping to read/write a new register */ - wake_up_interruptible(&wc->regq); } static void t1_handle_transmit(void* vbb, void* context) { 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++; + atomic_inc(&wc->txints); t1_transmitprep(wc, vbb); - wc->intcount++; - t1_isr_misc(wc); - spin_unlock(&wc->reglock); voicebus_transmit(wc->vb, vbb); + handle_leds(wc); } static void t1_handle_receive(void* vbb, void* context) { 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); t1_receiveprep(wc, vbb); - spin_unlock(&wc->reglock); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void timer_work_func(void *param) +{ + struct t1 *wc = param; +#else +static void timer_work_func(struct work_struct *work) +{ + struct t1 *wc = container_of(work, struct t1, timer_work); +#endif + /* Called once every 100ms */ + if (unlikely(!test_bit(INITIALIZED, &wc->bit_flags))) + return; + t1_do_counters(wc); + t1_check_alarms(wc); + t1_check_sigbits(wc); + mod_timer(&wc->timer, jiffies + HZ/5); +} + +static void +te12xp_timer(unsigned long data) +{ + struct t1 *wc = (struct t1 *)data; + schedule_work(&wc->timer_work); + return; } static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1602,17 +1365,35 @@ retry: ifaces[index] = wc; memset(wc, 0, sizeof(*wc)); + wc->ledstate = -1; spin_lock_init(&wc->reglock); + spin_lock_init(&wc->cmd_list_lock); + INIT_LIST_HEAD(&wc->active_cmds); + INIT_LIST_HEAD(&wc->pending_cmds); + wc->variety = d->name; wc->txident = 1; - init_waitqueue_head(&wc->regq); +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) + wc->timer.function = te12xp_timer; + wc->timer.data = (unsigned long)wc; + init_timer(&wc->timer); +# else + setup_timer(&wc->timer, te12xp_timer, (unsigned long)wc); +# endif + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&wc->timer_work, timer_work_func, wc); +# else + INIT_WORK(&wc->timer_work, timer_work_func); +# endif + snprintf(wc->name, sizeof(wc->name)-1, "wcte12xp%d", index); if ((res = voicebus_init(pdev, SFRAME_SIZE, wc->name, t1_handle_receive, t1_handle_transmit, wc, debug, &wc->vb))) { WARN_ON(1); - kfree(wc); + free_wc(wc); ifaces[index] = NULL; return res; } @@ -1628,17 +1409,14 @@ retry: for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { if (!(wc->chans[x] = kmalloc(sizeof(*wc->chans[x]), GFP_KERNEL))) { - while (x) { - kfree(wc->chans[--x]); - } - - kfree(wc); + free_wc(wc); ifaces[index] = NULL; return -ENOMEM; } memset(wc->chans[x], 0, sizeof(*wc->chans[x])); } + mod_timer(&wc->timer, jiffies + HZ/5); t1_software_init(wc); if (voicebus_current_latency(wc->vb) > startinglatency) { /* The voicebus library increased the latency during @@ -1652,7 +1430,7 @@ retry: dahdi_unregister(&wc->span); voicebus_release(wc->vb); wc->vb = NULL; - kfree(wc); + free_wc(wc); wc = NULL; goto retry; } @@ -1680,14 +1458,15 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev) destroy_workqueue(vpm150m->wq); } #endif + clear_bit(INITIALIZED, &wc->bit_flags); + del_timer_sync(&wc->timer); + flush_scheduled_work(); + del_timer_sync(&wc->timer); BUG_ON(!wc->vb); voicebus_release(wc->vb); wc->vb = NULL; - if (debug && wc->isrreaderrors) - debug_printk(1, "isrreaderrors=%d\n", wc->isrreaderrors); - #ifdef VPM_SUPPORT if(vpm150m) { spin_lock_irqsave(&wc->reglock, flags); @@ -1697,11 +1476,7 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev) kfree(wc->vpm150m); } #endif - /* Release span, possibly delayed */ - if (!wc->usecount) - t1_release(wc); - else - wc->dead = 1; + t1_release(wc); } static struct pci_device_id te12xp_pci_tbl[] = { @@ -1724,15 +1499,34 @@ static int __init te12xp_init(void) { int res; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22) + SLAB_HWCACHE_ALIGN | SLAB_STORE_USER, NULL, NULL); +#else + SLAB_HWCACHE_ALIGN, NULL, NULL); +#endif +#else + cmd_cache = kmem_cache_create(THIS_MODULE->name, sizeof(struct command), 0, + SLAB_HWCACHE_ALIGN, NULL); +#endif + if (!cmd_cache) + return -ENOMEM; + res = dahdi_pci_module(&te12xp_driver); + if (res) { + kmem_cache_destroy(cmd_cache); + return -ENODEV; + } - return res ? -ENODEV : 0; + return 0; } static void __exit te12xp_cleanup(void) { pci_unregister_driver(&te12xp_driver); + kmem_cache_destroy(cmd_cache); } module_param(debug, int, S_IRUGO | S_IWUSR); |