diff options
Diffstat (limited to 'drivers/dahdi/wctdm24xxp/base.c')
-rw-r--r-- | drivers/dahdi/wctdm24xxp/base.c | 527 |
1 files changed, 292 insertions, 235 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c index 7f68473..1386e5f 100644 --- a/drivers/dahdi/wctdm24xxp/base.c +++ b/drivers/dahdi/wctdm24xxp/base.c @@ -162,17 +162,17 @@ static int ectrans[4] = { 0, 1, 3, 2 }; #include "fxo_modes.h" struct wctdm_desc { - char *name; - int flags; - int ports; + const char *name; + const int flags; + const int ports; }; -static struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 }; -static struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 }; -static struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 }; -static struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 }; -static struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 }; -static struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 }; +static const struct wctdm_desc wctdm2400 = { "Wildcard TDM2400P", 0, 24 }; +static const struct wctdm_desc wctdm800 = { "Wildcard TDM800P", 0, 8 }; +static const struct wctdm_desc wctdm410 = { "Wildcard TDM410P", 0, 4 }; +static const struct wctdm_desc wcaex2400 = { "Wildcard AEX2400", FLAG_EXPRESS, 24 }; +static const struct wctdm_desc wcaex800 = { "Wildcard AEX800", FLAG_EXPRESS, 8 }; +static const struct wctdm_desc wcaex410 = { "Wildcard AEX410", FLAG_EXPRESS, 4 }; static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 }; @@ -462,9 +462,8 @@ static int config_vpmadt032(struct vpmadt032 *vpm) } -static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writechunk, int whichframe) +static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *writechunk, int whichframe) { - unsigned long flags; struct vpmadt032_cmd *curcmd = NULL; struct vpmadt032 *vpmadt032 = wc->vpmadt032; int x; @@ -473,8 +472,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec /* Skip audio */ writechunk += 24; - spin_lock_irqsave(&wc->reglock, flags); - if (test_bit(VPM150M_SPIRESET, &vpmadt032->control) || test_bit(VPM150M_HPIRESET, &vpmadt032->control)) { if (debug & DEBUG_ECHOCAN) printk(KERN_INFO "HW Resetting VPMADT032...\n"); @@ -489,7 +486,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec writechunk[CMD_BYTE(x, 1, 0)] = 0; writechunk[CMD_BYTE(x, 2, 0)] = 0x00; } - spin_unlock_irqrestore(&wc->reglock, flags); return; } @@ -548,7 +544,6 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec writechunk[CMD_BYTE(27, 2, 0)] = 0; } } else if (test_and_clear_bit(VPM150M_SWRESET, &vpmadt032->control)) { - printk(KERN_INFO "Booting VPMADT032\n"); for (x = 24; x < 28; x++) { if (x == 24) writechunk[CMD_BYTE(x, 0, 0)] = (0x8 << 4); @@ -577,11 +572,9 @@ static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, unsigned char *writec if (test_bit(VPM150M_ACTIVE, &vpmadt032->control) && !whichframe && !(wc->intcount % 100)) { schedule_work(&vpmadt032->work); } - - spin_unlock_irqrestore(&wc->reglock, flags); } -static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writechunk, int card, int pos) +static inline void cmd_dequeue(struct wctdm *wc, unsigned char *writechunk, int card, int pos) { unsigned long flags; unsigned int curcmd=0; @@ -624,7 +617,7 @@ static inline void cmd_dequeue(struct wctdm *wc, volatile unsigned char *writech if (!curcmd) { /* If nothing else, use filler */ if (wc->modtype[card] == MOD_TYPE_FXS) - curcmd = CMD_RD(64); + curcmd = CMD_RD(LINE_STATE); else if (wc->modtype[card] == MOD_TYPE_FXO) curcmd = CMD_RD(12); else if (wc->modtype[card] == MOD_TYPE_QRV) @@ -752,7 +745,7 @@ static inline void cmd_decipher_vpmadt032(struct wctdm *wc, unsigned char *readc #endif } -static inline void cmd_decipher(struct wctdm *wc, volatile unsigned char *readchunk, int card) +static inline void cmd_decipher(struct wctdm *wc, u8 *readchunk, int card) { unsigned long flags; unsigned char ident; @@ -819,7 +812,7 @@ static inline void cmd_checkisr(struct wctdm *wc, int card) #ifdef PAQ_DEBUG wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(19); /* Transistor interrupts */ #else - wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(64); /* Battery mode */ + wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(LINE_STATE); #endif } else if (wc->modtype[card] == MOD_TYPE_FXO) { wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29); /* Battery */ @@ -850,7 +843,7 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechun } if (likely(wc->initialized)) { - if (y < wc->type) + if (y < wc->desc->ports) writechunk[y] = wc->chans[y]->writechunk[x]; } cmd_dequeue(wc, writechunk, y, x); @@ -878,7 +871,7 @@ static inline void wctdm_transmitprep(struct wctdm *wc, unsigned char *writechun writechunk[EFRAME_SIZE] = wc->ctlreg; writechunk[EFRAME_SIZE + 1] = wc->txident++; - if ((wc->type == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) { + if ((wc->desc->ports == 4) && ((wc->ctlreg & 0x10) || (wc->modtype[NUM_CARDS] == MOD_TYPE_NONE))) { writechunk[EFRAME_SIZE + 2] = 0; for (y = 0; y < 4; y++) { if (wc->modtype[y] == MOD_TYPE_NONE) @@ -1032,11 +1025,8 @@ static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk) } } for (y=0;y < wc->cards;y++) { - if (likely(wc->initialized)) { - if (y < wc->type) { - wc->chans[y]->readchunk[x] = readchunk[y]; - } - } + if (likely(wc->initialized) && (y < wc->desc->ports)) + wc->chans[y]->readchunk[x] = readchunk[y]; cmd_decipher(wc, readchunk, y); } if (wc->vpm100) { @@ -1050,7 +1040,7 @@ static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk) } /* XXX We're wasting 8 taps. We should get closer :( */ if (likely(wc->initialized)) { - for (x=0;x<wc->type;x++) { + for (x = 0; x < wc->desc->ports; x++) { if (wc->cardflag & (1 << x)) dahdi_ec_chunk(wc->chans[x], wc->chans[x]->readchunk, wc->chans[x]->writechunk); } @@ -1088,7 +1078,7 @@ static int wait_access(struct wctdm *wc, int card) static unsigned char translate_3215(unsigned char address) { int x; - for (x=0;x<sizeof(indirect_regs)/sizeof(indirect_regs[0]);x++) { + for (x = 0; x < ARRAY_SIZE(indirect_regs); x++) { if (indirect_regs[x].address == address) { address = indirect_regs[x].altaddr; break; @@ -1145,7 +1135,7 @@ static int wctdm_proslic_init_indirect_regs(struct wctdm *wc, int card) { unsigned char i; - for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) + for (i = 0; i < ARRAY_SIZE(indirect_regs); i++) { if(wctdm_proslic_setreg_indirect(wc, card, indirect_regs[i].address,indirect_regs[i].initial)) return -1; @@ -1160,7 +1150,7 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card) unsigned short i, initial; int j; - for (i=0; i<sizeof(indirect_regs) / sizeof(indirect_regs[0]); i++) + for (i = 0; i < ARRAY_SIZE(indirect_regs); i++) { if((j = wctdm_proslic_getreg_indirect(wc, card, (unsigned char) indirect_regs[i].address)) < 0) { printk(KERN_NOTICE "Failed to read indirect register %d\n", i); @@ -1188,56 +1178,55 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card) static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card) { + struct fxs *const fxs = &wc->mods[card].fxs; int res; + unsigned long flags; #ifdef PAQ_DEBUG res = wc->cmdq[card].isrshadow[1]; res &= ~0x3; if (res) { wc->cmdq[card].isrshadow[1]=0; - wc->mods[card].fxs.palarms++; - if (wc->mods[card].fxs.palarms < MAX_ALARMS) { + fxs->palarms++; + if (fxs->palarms < MAX_ALARMS) { printk(KERN_NOTICE "Power alarm (%02x) on module %d, resetting!\n", res, card + 1); - if (wc->mods[card].fxs.lasttxhook == 4) { - wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11; - } wc->sethook[card] = CMD_WR(19, res); -#if 0 - wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook); -#endif - - /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */ /* Update shadow register to avoid extra power alarms until next read */ wc->cmdq[card].isrshadow[1] = 0; } else { - if (wc->mods[card].fxs.palarms == MAX_ALARMS) + if (fxs->palarms == MAX_ALARMS) printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1); } } #else + spin_lock_irqsave(&fxs->lasttxhooklock, flags); res = wc->cmdq[card].isrshadow[1]; /* This makes sure the lasthook was put in reg 64 the linefeed reg */ - if (((res & 0x0f) | 0x10) == wc->mods[card].fxs.lasttxhook) - wc->mods[card].fxs.lasttxhook &= 0x0f; + if (((res & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING) == fxs->lasttxhook) + fxs->lasttxhook &= SLIC_LF_SETMASK; res = !res && /* reg 64 has to be zero at last isr read */ - !(wc->mods[card].fxs.lasttxhook & 0x10 ) && /* not a transition */ - wc->mods[card].fxs.lasttxhook; /* not an intended zero */ + !(fxs->lasttxhook & SLIC_LF_OPPENDING) && /* not a transition */ + fxs->lasttxhook; /* not an intended zero */ + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); if (res) { - wc->mods[card].fxs.palarms++; - if (wc->mods[card].fxs.palarms < MAX_ALARMS) { + fxs->palarms++; + if (fxs->palarms < MAX_ALARMS) { printk(KERN_NOTICE "Power alarm on module %d, resetting!\n", card + 1); - if (wc->mods[card].fxs.lasttxhook == 4) { - wc->mods[card].fxs.lasttxhook = POLARITY_XOR(card) ? 0x15 : 0x11;; + spin_lock_irqsave(&fxs->lasttxhooklock, flags); + if (fxs->lasttxhook == SLIC_LF_RINGING) { + fxs->lasttxhook = POLARITY_XOR(card) ? + SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD;; } - wc->mods[card].fxs.lasttxhook |= 0x10; - wc->sethook[card] = CMD_WR(64, wc->mods[card].fxs.lasttxhook); + fxs->lasttxhook |= SLIC_LF_OPPENDING; + wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook); + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); - /* wctdm_setreg_intr(wc, card, 64, wc->mods[card].fxs.lasttxhook); */ /* Update shadow register to avoid extra power alarms until next read */ - wc->cmdq[card].isrshadow[1] = wc->mods[card].fxs.lasttxhook; + wc->cmdq[card].isrshadow[1] = fxs->lasttxhook; } else { - if (wc->mods[card].fxs.palarms == MAX_ALARMS) + if (fxs->palarms == MAX_ALARMS) printk(KERN_NOTICE "Too many power alarms on card %d, NOT resetting!\n", card + 1); } } @@ -1404,6 +1393,21 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) } } + if (unlikely(DAHDI_RXSIG_INITIAL == wc->chans[card]->rxhooksig)) { + /* + * dahdi-base will set DAHDI_RXSIG_INITIAL after a + * DAHDI_STARTUP or DAHDI_CHANCONFIG ioctl so that new events + * will be queued on the channel with the current received + * hook state. Channels that use robbed-bit signalling always + * report the current received state via the dahdi_rbsbits + * call. Since we only call dahdi_hooksig when we've detected + * a change to report, let's forget our current state in order + * to force us to report it again via dahdi_hooksig. + * + */ + fxo->battery = BATTERY_UNKNOWN; + } + if (abs_voltage < battthresh) { /* possible existing states: battery lost, no debounce timer @@ -1568,8 +1572,40 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) #undef MS_PER_CHECK_HOOK } -static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) +static void wctdm_fxs_off_hook(struct wctdm *wc, const int card) +{ + struct fxs *const fxs = &wc->mods[card].fxs; + + if (debug & DEBUG_CARD) + printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card); + switch (fxs->lasttxhook) { + case SLIC_LF_RINGING: /* Ringing */ + case SLIC_LF_OHTRAN_FWD: /* Forward On Hook Transfer */ + case SLIC_LF_OHTRAN_REV: /* Reverse On Hook Transfer */ + /* just detected OffHook, during Ringing or OnHookTransfer */ + fxs->idletxhookstate = POLARITY_XOR(card) ? + SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD; + break; + } + dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); + if (robust) + wctdm_init_proslic(wc, card, 1, 0, 1); + fxs->oldrxhook = 1; +} + +static void wctdm_fxs_on_hook(struct wctdm *wc, const int card) +{ + struct fxs *const fxs = &wc->mods[card].fxs; + if (debug & DEBUG_CARD) + printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card); + dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); + fxs->oldrxhook = 0; +} + +static inline void wctdm_proslic_check_hook(struct wctdm *wc, const int card) { + struct fxs *const fxs = &wc->mods[card].fxs; char res; int hook; @@ -1579,46 +1615,36 @@ static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card) res = wc->cmdq[card].isrshadow[0]; /* Hook state */ hook = (res & 1); - if (hook != wc->mods[card].fxs.lastrxhook) { + if (hook != fxs->lastrxhook) { /* Reset the debounce (must be multiple of 4ms) */ - wc->mods[card].fxs.debounce = 8 * (4 * 8); + fxs->debounce = 8 * (4 * 8); #if 0 - printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", card, hook, wc->mods[card].fxs.debounce); + printk(KERN_DEBUG "Resetting debounce card %d hook %d, %d\n", + card, hook, fxs->debounce); #endif } else { - if (wc->mods[card].fxs.debounce > 0) { - wc->mods[card].fxs.debounce-= 4 * DAHDI_CHUNKSIZE; + if (fxs->debounce > 0) { + fxs->debounce -= 4 * DAHDI_CHUNKSIZE; #if 0 - printk(KERN_DEBUG "Sustaining hook %d, %d\n", hook, wc->mods[card].fxs.debounce); + printk(KERN_DEBUG "Sustaining hook %d, %d\n", + hook, fxs->debounce); #endif - if (!wc->mods[card].fxs.debounce) { + if (!fxs->debounce) { #if 0 printk(KERN_DEBUG "Counted down debounce, newhook: %d...\n", hook); #endif - wc->mods[card].fxs.debouncehook = hook; - } - if (!wc->mods[card].fxs.oldrxhook && wc->mods[card].fxs.debouncehook) { - /* Off hook */ - if (debug & DEBUG_CARD) - printk(KERN_DEBUG "wctdm: Card %d Going off hook\n", card); - dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_OFFHOOK); - if (robust) - wctdm_init_proslic(wc, card, 1, 0, 1); - wc->mods[card].fxs.oldrxhook = 1; - - } else if (wc->mods[card].fxs.oldrxhook && !wc->mods[card].fxs.debouncehook) { - /* On hook */ - if (debug & DEBUG_CARD) - printk(KERN_DEBUG "wctdm: Card %d Going on hook\n", card); - dahdi_hooksig(wc->chans[card], DAHDI_RXSIG_ONHOOK); - wc->mods[card].fxs.oldrxhook = 0; + fxs->debouncehook = hook; } + + if (!fxs->oldrxhook && fxs->debouncehook) + wctdm_fxs_off_hook(wc, card); + else if (fxs->oldrxhook && !fxs->debouncehook) + wctdm_fxs_on_hook(wc, card); } } - wc->mods[card].fxs.lastrxhook = hook; + fxs->lastrxhook = hook; } - static inline void wctdm_vpm_check(struct wctdm *wc, int x) { if (wc->cmdq[x].isrshadow[0]) { @@ -1706,7 +1732,50 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec unit, channel); wctdm_vpm_out(wc, unit, channel, 0x01); } else if (wc->vpmadt032) { - vpmadt032_echocan_free(wc->vpmadt032, chan, ec); + vpmadt032_echocan_free(wc->vpmadt032, chan->chanpos - 1, ec); + } +} + +static void wctdm_isr_misc_fxs(struct wctdm *wc, int card) +{ + struct fxs *const fxs = &wc->mods[card].fxs; + unsigned long flags; + + if (!(wc->intcount % 10000)) { + /* Accept an alarm once per 10 seconds */ + if (fxs->palarms) + fxs->palarms--; + } + wctdm_proslic_check_hook(wc, card); + if (!(wc->intcount & 0xfc)) + wctdm_proslic_recheck_sanity(wc, card); + if (SLIC_LF_RINGING == fxs->lasttxhook) { + /* RINGing, prepare for OHT */ + fxs->ohttimer = OHT_TIMER << 3; + /* OHT mode when idle */ + fxs->idletxhookstate = POLARITY_XOR(card) ? SLIC_LF_OHTRAN_REV : + SLIC_LF_OHTRAN_FWD; + } else if (fxs->ohttimer) { + fxs->ohttimer -= DAHDI_CHUNKSIZE; + if (fxs->ohttimer) + return; + + /* Switch to active */ + fxs->idletxhookstate = POLARITY_XOR(card) ? SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD; + spin_lock_irqsave(&fxs->lasttxhooklock, flags); + if (SLIC_LF_OHTRAN_FWD == fxs->lasttxhook) { + /* Apply the change if appropriate */ + fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_FWD; + /* Data enqueued here */ + wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook); + } else if (SLIC_LF_OHTRAN_REV == fxs->lasttxhook) { + /* Apply the change if appropriate */ + fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_ACTIVE_REV; + /* Data enqueued here */ + wc->sethook[card] = CMD_WR(LINE_STATE, fxs->lasttxhook); + } + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); } } @@ -1721,37 +1790,7 @@ static inline void wctdm_isr_misc(struct wctdm *wc) for (x=0;x<wc->cards;x++) { if (wc->cardflag & (1 << x)) { if (wc->modtype[x] == MOD_TYPE_FXS) { - if (!(wc->intcount % 10000)) { - /* Accept an alarm once per 10 seconds */ - if (wc->mods[x].fxs.palarms) - wc->mods[x].fxs.palarms--; - } - wctdm_proslic_check_hook(wc, x); - if (!(wc->intcount & 0xfc)) - wctdm_proslic_recheck_sanity(wc, x); - if (wc->mods[x].fxs.lasttxhook == 0x4) { - /* RINGing, prepare for OHT */ - wc->mods[x].fxs.ohttimer = OHT_TIMER << 3; - wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2; /* OHT mode when idle */ - } else { - if (wc->mods[x].fxs.ohttimer) { - wc->mods[x].fxs.ohttimer-= DAHDI_CHUNKSIZE; - if (!wc->mods[x].fxs.ohttimer) { - wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to active */ - if (wc->mods[x].fxs.lasttxhook == 0x2) { - /* Apply the change if appropriate */ - wc->mods[x].fxs.lasttxhook = 0x11; - wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */ - /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */ - } else if (wc->mods[x].fxs.lasttxhook == 0x6) { - /* Apply the change if appropriate */ - wc->mods[x].fxs.lasttxhook = 0x15; - wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */ - /* wctdm_setreg_intr(wc, x, 64, wc->mods[x].fxs.lasttxhook); */ - } - } - } - } + wctdm_isr_misc_fxs(wc, x); } else if (wc->modtype[x] == MOD_TYPE_FXO) { wctdm_voicedaa_check_hook(wc, x); } else if (wc->modtype[x] == MOD_TYPE_QRV) { @@ -1867,7 +1906,7 @@ static int wctdm_proslic_powerleak_test(struct wctdm *wc, int card) unsigned char vbat; /* Turn off linefeed */ - wctdm_setreg(wc, card, 64, 0); + wctdm_setreg(wc, card, LINE_STATE, 0); /* Power down */ wctdm_setreg(wc, card, 14, 0x10); @@ -2119,42 +2158,68 @@ static int wctdm_set_hwgain(struct wctdm *wc, int card, __s32 gain, __u32 tx) return 0; } +static int set_lasttxhook_interruptible(struct fxs *fxs, unsigned newval, int * psethook) +{ + int res = 0; + unsigned long flags; + int timeout = 0; + + do { + spin_lock_irqsave(&fxs->lasttxhooklock, flags); + if (SLIC_LF_OPPENDING & fxs->lasttxhook) { + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); + if (timeout++ > 100) + return -1; + msleep(1); + } else { + fxs->lasttxhook = (newval & SLIC_LF_SETMASK) | SLIC_LF_OPPENDING; + *psethook = CMD_WR(LINE_STATE, fxs->lasttxhook); + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); + break; + } + } while (1); + + return res; +} + +/* Must be called from within an interruptible context */ static int set_vmwi(struct wctdm *wc, int chan_idx) { int x; + struct fxs *const fxs = &wc->mods[chan_idx].fxs; + /* Presently only supports line reversal MWI */ - if (wc->mods[chan_idx].fxs.vmwi_active_messages && wc->mods[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_LREV){ - wc->mods[chan_idx].fxs.vmwi_linereverse = 1; - } else { - wc->mods[chan_idx].fxs.vmwi_linereverse = 0; - } + if ((fxs->vmwi_active_messages) && + (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV)) + fxs->vmwi_linereverse = 1; + else + fxs->vmwi_linereverse = 0; + /* Set line polarity for new VMWI state */ if (POLARITY_XOR(chan_idx)) { - wc->mods[chan_idx].fxs.idletxhookstate |= 0x14; + fxs->idletxhookstate |= SLIC_LF_OPPENDING | SLIC_LF_REVMASK; /* Do not set while currently ringing or open */ - if (wc->mods[chan_idx].fxs.lasttxhook != 0x04 && - wc->mods[chan_idx].fxs.lasttxhook != 0x00) { - wc->mods[chan_idx].fxs.lasttxhook |= 0x14; - wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook); - } + if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) && + ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) { + x = fxs->lasttxhook; + x |= SLIC_LF_REVMASK; + set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]); + } } else { - wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04; + fxs->idletxhookstate &= ~SLIC_LF_REVMASK; /* Do not set while currently ringing or open */ - if (wc->mods[chan_idx].fxs.lasttxhook != 0x04 && - wc->mods[chan_idx].fxs.lasttxhook != 0x00) { - x = wc->mods[chan_idx].fxs.lasttxhook; - x &= ~0x04; - x |= 0x10; - wc->mods[chan_idx].fxs.lasttxhook = x; - wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook); + if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) && + ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) { + x = fxs->lasttxhook; + x &= ~SLIC_LF_REVMASK; + set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan_idx]); } } if (debug) { - printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, lrev=%d\n", - chan_idx, - wc->mods[chan_idx].fxs.vmwi_active_messages, - wc->mods[chan_idx].fxs.vmwi_linereverse - ); + printk(KERN_DEBUG + "Setting VMWI on channel %d, messages=%d, lrev=%d\n", + chan_idx, fxs->vmwi_active_messages, + fxs->vmwi_linereverse); } return 0; } @@ -2282,11 +2347,10 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, /* By default, don't send on hook */ if (!reversepolarity != !wc->mods[card].fxs.reversepolarity) { - wc->mods[card].fxs.idletxhookstate = 5; + wc->mods[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_REV; } else { - wc->mods[card].fxs.idletxhookstate = 1; + wc->mods[card].fxs.idletxhookstate = SLIC_LF_ACTIVE_FWD; } - wc->mods[card].fxs.lasttxhook = 0x10; if (sane) { /* Make sure we turn off the DC->DC converter to prevent anything from blowing up */ @@ -2329,6 +2393,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, } if (!fast) { + spin_lock_init(&wc->mods[card].fxs.lasttxhooklock); /* Check for power leaks */ if (wctdm_proslic_powerleak_test(wc, card)) { @@ -2504,7 +2569,7 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual, printk(KERN_DEBUG "DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0")); wc->mods[card].fxs.lasttxhook = wc->mods[card].fxs.idletxhookstate; - wctdm_setreg(wc, card, 64, wc->mods[card].fxs.lasttxhook); + wctdm_setreg(wc, card, LINE_STATE, wc->mods[card].fxs.lasttxhook); return 0; } @@ -2653,6 +2718,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long struct dahdi_radio_stat s; struct dahdi_radio_param p; } stack; + struct fxs *const fxs = &wc->mods[chan->chanpos - 1].fxs; switch (cmd) { case DAHDI_ONHOOKTRANSFER: @@ -2660,19 +2726,27 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long return -EINVAL; if (get_user(x, (__user int *) data)) return -EFAULT; - wc->mods[chan->chanpos - 1].fxs.ohttimer = x << 3; - wc->mods[chan->chanpos - 1].fxs.idletxhookstate = 0x2; /* OHT mode when idle */ - if (wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mods[chan->chanpos - 1].fxs.lasttxhook == 0x5) { - /* Apply the change if appropriate */ - wc->mods[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos -1) ? 0x16 : 0x12; - wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); - /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */ + fxs->ohttimer = x << 3; + + /* Active mode when idle */ + fxs->idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? + SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD; + + if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) || + ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) { + + set_lasttxhook_interruptible(fxs, POLARITY_XOR(chan->chanpos - 1) + ? SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD , + &wc->sethook[chan->chanpos - 1]); } break; case DAHDI_VMWI_CONFIG: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; - if (copy_from_user(&(wc->mods[chan->chanpos - 1].fxs.vmwisetting), (__user void *) data, sizeof(wc->mods[chan->chanpos - 1].fxs.vmwisetting))) + if (copy_from_user(&(fxs->vmwisetting), + (__user void *)data, + sizeof(fxs->vmwisetting))) return -EFAULT; set_vmwi(wc, chan->chanpos - 1); break; @@ -2683,7 +2757,7 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long return -EFAULT; if (0 > x) return -EFAULT; - wc->mods[chan->chanpos - 1].fxs.vmwi_active_messages = x; + fxs->vmwi_active_messages = x; set_vmwi(wc, chan->chanpos - 1); break; case WCTDM_GET_STATS: @@ -2728,9 +2802,10 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long wctdm_proslic_setreg_indirect(wc, chan->chanpos - 1, regop.reg, regop.val); } else { regop.val &= 0xff; - if (regop.reg == 64) - wc->mods[chan->chanpos-1].fxs.lasttxhook = (regop.val & 0x0f) | 0x10; - + if (regop.reg == LINE_STATE) { + /* Set feedback register to indicate the new state that is being set */ + fxs->lasttxhook = (regop.val & 0x0f) | SLIC_LF_OPPENDING; + } printk(KERN_INFO "Setting direct %d to %04x on %d\n", regop.reg, regop.val, chan->chanpos); wctdm_setreg(wc, chan->chanpos - 1, regop.reg, regop.val); } @@ -2783,25 +2858,23 @@ static int wctdm_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; /* Can't change polarity while ringing or when open */ - if ((wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x04) || - (wc->mods[chan->chanpos -1 ].fxs.lasttxhook == 0x00)) + if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_RINGING) || + ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_OPEN)) return -EINVAL; - if (x) { - wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 1; - } else { - wc->mods[chan->chanpos -1 ].fxs.reversepolarity = 0; - } + + fxs->reversepolarity = (x) ? 1 : 0; + if (POLARITY_XOR(chan->chanpos -1)) { - wc->mods[chan->chanpos -1 ].fxs.idletxhookstate |= 0x14; - wc->mods[chan->chanpos -1 ].fxs.lasttxhook |= 0x14; + fxs->idletxhookstate |= SLIC_LF_REVMASK; + x = fxs->lasttxhook; + x |= SLIC_LF_REVMASK; + set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]); } else { - wc->mods[chan->chanpos -1 ].fxs.idletxhookstate &= ~0x04; - x = wc->mods[chan->chanpos -1 ].fxs.lasttxhook; - x &= ~0x04; - x |= 0x10; - wc->mods[chan->chanpos -1 ].fxs.lasttxhook = x; + fxs->idletxhookstate &= ~SLIC_LF_REVMASK; + x = fxs->lasttxhook; + x &= ~SLIC_LF_REVMASK; + set_lasttxhook_interruptible(fxs, x, &wc->sethook[chan->chanpos - 1]); } - wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); break; case DAHDI_RADIO_GETPARAM: if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV) @@ -2988,7 +3061,9 @@ static int wctdm_close(struct dahdi_chan *chan) module_put(THIS_MODULE); for (x=0;x<wc->cards;x++) { if (wc->modtype[x] == MOD_TYPE_FXS) { - wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 5 : 1; + wc->mods[x].fxs.idletxhookstate = + POLARITY_XOR(x) ? SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD; } if (wc->modtype[x] == MOD_TYPE_QRV) { @@ -3017,6 +3092,7 @@ static int wctdm_close(struct dahdi_chan *chan) static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wctdm *wc = chan->pvt; + int reg=0,qrvcard; if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) { qrvcard = (chan->chanpos - 1) & 0xfc; @@ -3052,21 +3128,26 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) default: printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig); } - } else { + } else { /* Else this is an fxs port */ + unsigned long flags; + struct fxs *const fxs = &wc->mods[chan->chanpos - 1].fxs; + spin_lock_irqsave(&fxs->lasttxhooklock, flags); switch(txsig) { case DAHDI_TXSIG_ONHOOK: switch(chan->sig) { case DAHDI_SIG_EM: case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 | - wc->mods[chan->chanpos - 1].fxs.idletxhookstate; + fxs->lasttxhook = SLIC_LF_OPPENDING | + fxs->idletxhookstate; break; case DAHDI_SIG_FXOGS: if (POLARITY_XOR(chan->chanpos -1)) { - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x17; + fxs->lasttxhook = SLIC_LF_OPPENDING | + SLIC_LF_RING_OPEN; } else { - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x13; + fxs->lasttxhook = SLIC_LF_OPPENDING | + SLIC_LF_TIP_OPEN; } break; } @@ -3075,32 +3156,32 @@ static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) switch(chan->sig) { case DAHDI_SIG_EM: if (POLARITY_XOR(chan->chanpos -1)) { - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x11; + fxs->lasttxhook = SLIC_LF_OPPENDING | + SLIC_LF_ACTIVE_FWD; } else { - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x15; + fxs->lasttxhook = SLIC_LF_OPPENDING | + SLIC_LF_ACTIVE_REV; } break; default: - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 | - wc->mods[chan->chanpos - 1].fxs.idletxhookstate; + fxs->lasttxhook = SLIC_LF_OPPENDING | + fxs->idletxhookstate; break; } break; case DAHDI_TXSIG_START: - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x14; + fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_RINGING; break; case DAHDI_TXSIG_KEWL: - wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10; + fxs->lasttxhook = SLIC_LF_OPPENDING | SLIC_LF_OPEN; break; default: printk(KERN_NOTICE "wctdm24xxp: Can't set tx state to %d\n", txsig); } + wc->sethook[chan->chanpos - 1] = CMD_WR(LINE_STATE, fxs->lasttxhook); + spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); if (debug & DEBUG_CARD) printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, reg); - - - wc->sethook[chan->chanpos - 1] = CMD_WR(64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); - /* wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mods[chan->chanpos - 1].fxs.lasttxhook); */ } return 0; } @@ -3208,12 +3289,14 @@ static int wctdm_initialize(struct wctdm *wc) /* DAHDI stuff */ sprintf(wc->span.name, "WCTDM/%d", wc->pos); - snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); + snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, + "%s Board %d", wc->desc->name, wc->pos + 1); snprintf(wc->span.location, sizeof(wc->span.location) - 1, "PCI%s Bus %02d Slot %02d", (wc->flags[0] & FLAG_EXPRESS) ? " Express" : "", pdev->bus->number, PCI_SLOT(pdev->devfn) + 1); wc->span.manufacturer = "Digium"; - strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1); + strncpy(wc->span.devicetype, wc->desc->name, + sizeof(wc->span.devicetype) - 1); if (alawoverride) { printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n"); wc->span.deflaw = DAHDI_LAW_ALAW; @@ -3228,7 +3311,7 @@ static int wctdm_initialize(struct wctdm *wc) wc->chans[x]->pvt = wc; } wc->span.chans = wc->chans; - wc->span.channels = wc->type; + wc->span.channels = wc->desc->ports; wc->span.irq = pdev->irq; wc->span.hooksig = wctdm_hooksig; wc->span.open = wctdm_open; @@ -3387,7 +3470,7 @@ static int wctdm_vpm_init(struct wctdm *wc) } printk(KERN_INFO "Enabling VPM100 gain adjustments on any FXO ports found\n"); - for (i = 0; i < wc->type; i++) { + for (i = 0; i < wc->desc->ports; i++) { if (wc->modtype[i] == MOD_TYPE_FXO) { /* Apply negative Tx gain of 4.5db to DAA */ wctdm_setreg(wc, i, 38, 0x14); /* 4db */ @@ -3477,7 +3560,6 @@ static int wctdm_locate_modules(struct wctdm *wc) { int x; unsigned long flags; - unsigned int startinglatency = voicebus_current_latency(wc->vb); wc->ctlreg = 0x00; /* Make sure all units go into daisy chain mode */ @@ -3503,16 +3585,13 @@ static int wctdm_locate_modules(struct wctdm *wc) #endif /* Now that all the cards have been reset, we can stop checking them all if there aren't as many */ spin_lock_irqsave(&wc->reglock, flags); - wc->cards = wc->type; + wc->cards = wc->desc->ports; spin_unlock_irqrestore(&wc->reglock, flags); /* Reset modules */ for (x=0;x<wc->cards;x++) { int sane=0,ret=0,readi=0; retry: - if (voicebus_current_latency(wc->vb) > startinglatency) { - return -EAGAIN; - } /* Init with Auto Calibration */ if (!(ret = wctdm_init_proslic(wc, x, 0, 0, sane))) { wc->cardflag |= (1 << x); @@ -3545,10 +3624,11 @@ retry: wc->cardflag |= 1 << x; printk(KERN_INFO "Port %d: Installed -- QRV DRI card\n",x + 1); } else { - if ((wc->type != 24) && ((x & 0x3) == 1) && !wc->altcs[x]) { - spin_lock_irqsave(&wc->reglock, flags); + if ((wc->desc->ports != 24) && + ((x & 0x3) == 1) && !wc->altcs[x]) { + spin_lock_irqsave(&wc->reglock, flags); wc->altcs[x] = 2; - if (wc->type == 4) { + if (wc->desc->ports == 4) { wc->altcs[x+1] = 3; wc->altcs[x+2] = 3; } @@ -3601,12 +3681,6 @@ retry: wc->vpmadt032->span = &wc->span; get_default_portconfig(&portconfig); res = vpmadt032_init(wc->vpmadt032, wc->vb); - /* In case there was an error while we were loading the VPM module. */ - if (voicebus_current_latency(wc->vb) > startinglatency) { - vpmadt032_free(wc->vpmadt032); - wc->vpmadt032 = NULL; - return -EAGAIN; - } if (res) { vpmadt032_free(wc->vpmadt032); wc->vpmadt032 = NULL; @@ -3636,7 +3710,7 @@ static void free_wc(struct wctdm *wc) { unsigned int x; - for (x = 0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); x++) { + for (x = 0; x < ARRAY_SIZE(wc->chans); x++) { if (wc->chans[x]) { kfree(wc->chans[x]); } @@ -3649,19 +3723,18 @@ static void free_wc(struct wctdm *wc) static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct wctdm *wc; - struct wctdm_desc *d = (struct wctdm_desc *)ent->driver_data; int i; int y; int ret; neonmwi_offlimit_cycles = neonmwi_offlimit /MS_PER_HOOKCHECK; -retry: if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { return -ENOMEM; } memset(wc, 0, sizeof(*wc)); + wc->desc = (struct wctdm_desc *)ent->driver_data; spin_lock(&ifacelock); /* \todo this is a candidate for removal... */ for (i = 0; i < WC_MAX_IFACES; ++i) { @@ -3689,12 +3762,10 @@ retry: spin_lock_init(&wc->reglock); wc->curcard = -1; wc->cards = NUM_CARDS; - wc->type = d->ports; wc->pos = i; - wc->variety = d->name; wc->txident = 1; for (y=0;y<NUM_CARDS;y++) { - wc->flags[y] = d->flags; + wc->flags[y] = wc->desc->flags; wc->dacssrc[y] = -1; } @@ -3721,29 +3792,14 @@ retry: return -EIO; } + voicebus_lock_latency(wc->vb); - /* Keep track of which device we are */ - pci_set_drvdata(pdev, wc); - - /* Start the hardware processing. */ if (voicebus_start(wc->vb)) { BUG_ON(1); } /* Now track down what modules are installed */ - ret = wctdm_locate_modules(wc); - if (-EAGAIN == ret ) { - /* The voicebus library increased the latency during - * initialization. There is a chance that the hardware is in - * an inconsistent state, so lets increase the default latency - * and start the initialization over. - */ - printk(KERN_NOTICE "%s: Restarting board initialization " \ - "after increasing latency.\n", wc->board_name); - latency = voicebus_current_latency(wc->vb); - wctdm_release(wc); - goto retry; - } + wctdm_locate_modules(wc); /* Final initialization */ wctdm_post_initialize(wc); @@ -3756,10 +3812,11 @@ retry: wc->initialized = 1; - printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n", wc->variety, wc->type); - ret = 0; + printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n", + wc->desc->name, wc->desc->ports); - return ret; + voicebus_unlock_latency(wc->vb); + return 0; } static void wctdm_release(struct wctdm *wc) @@ -3785,7 +3842,7 @@ static void wctdm_release(struct wctdm *wc) static void __devexit wctdm_remove_one(struct pci_dev *pdev) { - struct wctdm *wc = pci_get_drvdata(pdev); + struct wctdm *wc = voicebus_pci_dev_to_context(pdev); struct vpmadt032 *vpm = wc->vpmadt032; if (wc) { @@ -3837,15 +3894,15 @@ static int __init wctdm_init(void) int res; int x; - for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) { + for (x = 0; x < ARRAY_SIZE(fxo_modes); x++) { if (!strcmp(fxo_modes[x].name, opermode)) break; } - if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) { + if (x < ARRAY_SIZE(fxo_modes)) { _opermode = x; } else { printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified. Please choose one of:\n", opermode); - for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++) + for (x = 0; x < ARRAY_SIZE(fxo_modes); x++) printk(KERN_NOTICE " %s\n", fxo_modes[x].name); printk(KERN_NOTICE "Note this option is CASE SENSITIVE!\n"); return -ENODEV; |