Index: drivers/dahdi/wctdm24xxp/wctdm24xxp.h =================================================================== --- drivers/dahdi/wctdm24xxp/wctdm24xxp.h (revision 9867) +++ drivers/dahdi/wctdm24xxp/wctdm24xxp.h (working copy) @@ -186,6 +186,8 @@ struct dahdi_vmwi_info vmwisetting; int vmwi_active_messages; int vmwi_linereverse; + int vmwi_hvac; + int neonringing:1; /* Ring Generator is set for NEON */ int reversepolarity; /* polarity reversal */ struct calregs calregs; }; Index: drivers/dahdi/wctdm24xxp/base.c =================================================================== --- drivers/dahdi/wctdm24xxp/base.c (revision 9867) +++ drivers/dahdi/wctdm24xxp/base.c (working copy) @@ -109,7 +109,7 @@ */ #define POLARITY_XOR(fxs) \ ((reversepolarity != 0) ^ ((fxs)->reversepolarity != 0) ^ \ - ((fxs)->vmwi_linereverse != 0)) + ((fxs)->vmwi_linereverse != 0) ^ (((fxs)->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC) != 0)) static int reversepolarity = 0; @@ -262,6 +262,9 @@ wctdm_init_proslic(struct wctdm *wc, struct wctdm_module *const mod, int fast, int manual, int sane); +static int wctdm_init_ring_generator_mode(struct wctdm *wc, struct wctdm_module *const mod); +static int wctdm_set_ring_generator_mode(struct wctdm *wc, struct wctdm_module *const mod, int mode); + static void set_offsets(struct wctdm_module *const mod, int altcs) { int card = mod->card; @@ -1435,6 +1438,25 @@ } static int +wctdm_proslic_setreg_indirect_intr(struct wctdm *wc, struct wctdm_module *const mod, + unsigned char address, unsigned short data) +{ + int res = -1; + + address = translate_3215(address); + if (address == 255) + return 0; + +// if (!wait_access(wc, mod)) { + wctdm_setreg_intr(wc, mod, IDA_LO, (u8)(data & 0xFF)); + wctdm_setreg_intr(wc, mod, IDA_HI, (u8)((data & 0xFF00)>>8)); + wctdm_setreg_intr(wc, mod, IAA, address); + res = 0; +// }; + return res; +} + +static int wctdm_proslic_getreg_indirect(struct wctdm *wc, struct wctdm_module *const mod, unsigned char address) { @@ -1621,7 +1643,7 @@ if (fxs->lasttxhook == SLIC_LF_RINGING) { fxs->lasttxhook = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : - SLIC_LF_ACTIVE_FWD;; + SLIC_LF_ACTIVE_FWD; } fxs->lasttxhook |= SLIC_LF_OPPENDING; mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); @@ -2013,12 +2035,21 @@ case DAHDI_TXSIG_ONHOOK: switch (mod->chan->chan.sig) { case DAHDI_SIG_EM: + x = fxs->idletxhookstate; + break; case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: - x = fxs->idletxhookstate; + /* Can't change Ring Generator during OHT */ + if (!fxs->ohttimer){ + wctdm_set_ring_generator_mode(wc, mod, fxs->vmwi_hvac); + x = fxs->vmwi_hvac ? + SLIC_LF_RINGING : fxs->idletxhookstate; + } else + x = fxs->idletxhookstate; + break; case DAHDI_SIG_FXOGS: - x = (POLARITY_XOR(fxs)) ? + x = POLARITY_XOR(fxs) ? SLIC_LF_RING_OPEN : SLIC_LF_TIP_OPEN; break; @@ -2027,7 +2058,7 @@ case DAHDI_TXSIG_OFFHOOK: switch (mod->chan->chan.sig) { case DAHDI_SIG_EM: - x = (POLARITY_XOR(fxs)) ? + x = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_FWD : SLIC_LF_ACTIVE_REV; break; @@ -2037,6 +2068,7 @@ } break; case DAHDI_TXSIG_START: + wctdm_set_ring_generator_mode(wc, mod, 0); /* Set ringer mode */ x = SLIC_LF_RINGING; break; case DAHDI_TXSIG_KEWL: @@ -2215,12 +2247,13 @@ if (!(wc->intcount & 0xfc)) /* every 256ms */ wctdm_proslic_recheck_sanity(wc, mod); - if (SLIC_LF_RINGING == fxs->lasttxhook) { + if ((SLIC_LF_RINGING == fxs->lasttxhook) && fxs->neonringing) { /* RINGing, prepare for OHT */ fxs->ohttimer = OHT_TIMER << 3; /* OHT mode when idle */ - fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_OHTRAN_REV : - SLIC_LF_OHTRAN_FWD; + fxs->idletxhookstate = POLARITY_XOR(fxs) ? + SLIC_LF_OHTRAN_REV : + SLIC_LF_OHTRAN_FWD; } else if (fxs->ohttimer) { /* check if still OnHook */ if (!fxs->oldrxhook) { @@ -2229,12 +2262,24 @@ return; /* Switch to active */ - fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : - SLIC_LF_ACTIVE_FWD; + fxs->idletxhookstate = POLARITY_XOR(fxs) ? + 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; + + if ((SLIC_LF_OHTRAN_FWD == fxs->lasttxhook) || + (SLIC_LF_OHTRAN_REV == fxs->lasttxhook)) { + if (fxs->vmwi_hvac){ + /* force idle polarity Forward if ringing */ + fxs->idletxhookstate = SLIC_LF_ACTIVE_FWD; + /* Set ring generator for neon */ + wctdm_set_ring_generator_mode(wc, mod, 1); + fxs->lasttxhook = (SLIC_LF_OPPENDING | + SLIC_LF_RINGING); + } else + fxs->lasttxhook = (SLIC_LF_OPPENDING | + fxs->idletxhookstate); + /* Data enqueued here */ mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); if (debug & DEBUG_CARD) { @@ -2242,29 +2287,20 @@ "Channel %d OnHookTransfer " "stop\n", mod->card); } - } 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 */ - mod->sethook = CMD_WR(LINE_STATE, fxs->lasttxhook); - if (debug & DEBUG_CARD) { - dev_info(&wc->vb.pdev->dev, - "Channel %d OnHookTransfer " - "stop\n", mod->card); - } } spin_unlock_irqrestore(&fxs->lasttxhooklock, flags); } else { fxs->ohttimer = 0; /* Switch to active */ - fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; + fxs->idletxhookstate = POLARITY_XOR(fxs) ? + SLIC_LF_ACTIVE_REV : + SLIC_LF_ACTIVE_FWD; if (debug & DEBUG_CARD) { dev_info(&wc->vb.pdev->dev, "Channel %d OnHookTransfer abort\n", mod->card); } } - } } @@ -2759,38 +2795,71 @@ int x; struct fxs *const fxs = &mod->mod.fxs; - /* Presently only supports line reversal MWI */ - if ((fxs->vmwi_active_messages) && - (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV)) - fxs->vmwi_linereverse = 1; - else + /* Presently supports line reversal MWI and NEON dc pulses */ + if (fxs->vmwi_active_messages) { + fxs->vmwi_linereverse = (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_LREV)?1:0; + fxs->vmwi_hvac = (fxs->vmwisetting.vmwi_type & DAHDI_VMWI_HVAC)?1:0; + } else { fxs->vmwi_linereverse = 0; + fxs->vmwi_hvac = 0; + } - /* Set line polarity for new VMWI state */ - if (POLARITY_XOR(fxs)) { - fxs->idletxhookstate |= SLIC_LF_OPPENDING | SLIC_LF_REVMASK; - /* Do not set while currently ringing or open */ - 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, &mod->sethook); + if (fxs->vmwi_hvac) { + /* Can't change ring generator while On Hook Transfer might be happening */ + if (!fxs->ohttimer) { + /* Set line polarity for new VMWI state */ + if (POLARITY_XOR(fxs)) + fxs->idletxhookstate |= SLIC_LF_RINGING; + else + fxs->idletxhookstate &= ~SLIC_LF_RINGING; + + /* Set ring generator for neon */ + wctdm_set_ring_generator_mode(wc, mod, 1); + set_lasttxhook_interruptible(fxs, fxs->lasttxhook, &mod->sethook); } } else { - fxs->idletxhookstate &= ~SLIC_LF_REVMASK; - /* Do not set while currently ringing or open */ - if (((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_RINGING) && - ((fxs->lasttxhook & SLIC_LF_SETMASK) != SLIC_LF_OPEN)) { + if (fxs->neonringing){ + /* Set ring generator for normal ringer */ + wctdm_set_ring_generator_mode(wc, mod, 0); + /* ACTIVE, polarity determined later */ + fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; + } else { + /* Can't change polarity while ringing or when open */ + if ((fxs->lasttxhook == SLIC_LF_RINGING) || + (fxs->lasttxhook == SLIC_LF_OPEN)) { + /* Set line polarity for new VMWI state */ + if (POLARITY_XOR(fxs)) + fxs->idletxhookstate |= SLIC_LF_REVMASK; + else + fxs->idletxhookstate &= ~SLIC_LF_REVMASK; + + dev_info(&wc->vb.pdev->dev, + "Unable to change polarity on channel %d, lasttxhook=0x%X\n", + mod->card, + fxs->lasttxhook + ); + return 0; + } + } + + /* Set line polarity for new VMWI state */ + if (POLARITY_XOR(fxs)) { + fxs->idletxhookstate |= SLIC_LF_REVMASK; + fxs->lasttxhook |= SLIC_LF_REVMASK; + } else { + fxs->idletxhookstate &= ~SLIC_LF_REVMASK; + x = fxs->lasttxhook; x &= ~SLIC_LF_REVMASK; - set_lasttxhook_interruptible(fxs, x, &mod->sethook); + fxs->lasttxhook = x; } + set_lasttxhook_interruptible(fxs, fxs->lasttxhook, &mod->sethook); } if (debug) { dev_info(&wc->vb.pdev->dev, - "Setting VMWI on channel %d, messages=%d, lrev=%d\n", + "Setting VMWI on channel %d, messages=%d, lrev=%d hvac=%d\n", mod->card, fxs->vmwi_active_messages, - fxs->vmwi_linereverse); + fxs->vmwi_linereverse, fxs->vmwi_hvac); } return 0; } @@ -3147,45 +3216,8 @@ wctdm_setreg(wc, card, 1, 0x08); #endif - if (fastringer) { - /* Speed up Ringer */ - wctdm_proslic_setreg_indirect(wc, mod, 20, 0x7e6d); - wctdm_proslic_setreg_indirect(wc, mod, 21, 0x01b9); - /* Beef up Ringing voltage to 89V */ - if (boostringer) { - wctdm_setreg(wc, mod, 74, 0x3f); - if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x247)) - return -1; - dev_info(&wc->vb.pdev->dev, - "Boosting fast ringer on slot %d (89V peak)\n", - mod->card + 1); - } else if (lowpower) { - if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x14b)) - return -1; - dev_info(&wc->vb.pdev->dev, - "Reducing fast ring power on slot %d " - "(50V peak)\n", mod->card + 1); - } else - dev_info(&wc->vb.pdev->dev, - "Speeding up ringer on slot %d (25Hz)\n", - mod->card + 1); - } else { - /* Beef up Ringing voltage to 89V */ - if (boostringer) { - wctdm_setreg(wc, mod, 74, 0x3f); - if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x1d1)) - return -1; - dev_info(&wc->vb.pdev->dev, - "Boosting ringer on slot %d (89V peak)\n", - mod->card + 1); - } else if (lowpower) { - if (wctdm_proslic_setreg_indirect(wc, mod, 21, 0x108)) - return -1; - dev_info(&wc->vb.pdev->dev, - "Reducing ring power on slot %d " - "(50V peak)\n", mod->card + 1); - } - } + if (wctdm_init_ring_generator_mode(wc, mod)) + return -1; if (fxstxgain || fxsrxgain) { r9 = wctdm_getreg(wc, mod, 9); @@ -3467,28 +3499,33 @@ fxs->idletxhookstate = POLARITY_XOR(fxs) ? SLIC_LF_ACTIVE_REV : SLIC_LF_ACTIVE_FWD; + if (fxs->neonringing) { + /* keep same Forward polarity */ + fxs->lasttxhook = SLIC_LF_OHTRAN_FWD; + set_lasttxhook_interruptible(fxs, fxs->lasttxhook, &mod->sethook); + } else { - if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) || - ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) { + if (((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_FWD) || + ((fxs->lasttxhook & SLIC_LF_SETMASK) == SLIC_LF_ACTIVE_REV)) { - x = set_lasttxhook_interruptible(fxs, - (POLARITY_XOR(fxs) ? - SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD), - &mod->sethook); + x = set_lasttxhook_interruptible(fxs, + (POLARITY_XOR(fxs) ? + SLIC_LF_OHTRAN_REV : SLIC_LF_OHTRAN_FWD), + &mod->sethook); - if (debug & DEBUG_CARD) { - if (x) { - dev_info(&wc->vb.pdev->dev, - "Channel %d TIMEOUT: " - "OnHookTransfer start\n", - chan->chanpos - 1); - } else { - dev_info(&wc->vb.pdev->dev, - "Channel %d OnHookTransfer " - "start\n", chan->chanpos - 1); + if (debug & DEBUG_CARD) { + if (x) { + dev_info(&wc->vb.pdev->dev, + "Channel %d TIMEOUT: " + "OnHookTransfer start\n", + chan->chanpos - 1); + } else { + dev_info(&wc->vb.pdev->dev, + "Channel %d OnHookTransfer " + "start\n", chan->chanpos - 1); + } } } - } break; case DAHDI_VMWI_CONFIG: @@ -3865,6 +3902,122 @@ return 0; } +static int wctdm_init_ring_generator_mode(struct wctdm *wc, struct wctdm_module *const mod) +{ + wctdm_setreg(wc, mod, 34, 0x00); /* Ringing Osc. Control */ + + /* neon trapezoid timers */ + wctdm_setreg(wc, mod, 48, 0xe0); /* Active Timer low byte */ + wctdm_setreg(wc, mod, 49, 0x01); /* Active Timer high byte */ + wctdm_setreg(wc, mod, 50, 0xf0); /* Inactive Timer low byte */ + wctdm_setreg(wc, mod, 51, 0x05); /* Inactive Timer high byte */ + + wctdm_set_ring_generator_mode(wc, mod, 0); + + return 0; +} + +static int wctdm_set_ring_generator_mode(struct wctdm *wc, struct wctdm_module *const mod, int mode) +{ + struct fxs *const fxs = &mod->mod.fxs; + int reg20,reg21,reg74; /* RCO, RNGX, VBATH */ +#if 1 + fxs->neonringing = mode; /* track ring generator mode */ + + if (mode) { /* Neon */ + if (debug) + printk(KERN_DEBUG "NEON ring on channel %d, lasttxhook was 0x%x\n", mod->card, fxs->lasttxhook); + fxs->lasttxhook = SLIC_LF_ACTIVE_FWD; /* Must be in FORWARD ACTIVE before setting ringer */ + wctdm_setreg_intr(wc, mod, 64, fxs->lasttxhook); + + wctdm_proslic_setreg_indirect_intr(wc, mod, 22, 0x03e8); /* RNGY (4 HZ) */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 21, 0x7bef); /* RNGX (91.5Vpk) */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 20, 0x009f); /* RCO (RNGX, t rise) */ + + wctdm_setreg_intr(wc, mod, 34, 0x19); /* Ringing Osc. Control */ + wctdm_setreg_intr(wc, mod, 74, 0x3f); /* VBATH 94.5V */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 29, 0x4600); /* RPTP */ + /* A write of 0x04 to register 64 will turn on the VM led */ + } else { + if (debug) + printk(KERN_DEBUG "NORMAL ring on channel %d, lasttxhook was 0x%x\n", mod->card, fxs->lasttxhook); + + wctdm_setreg_intr(wc, mod, 34, 0x00); /* Ringing Osc. Control */ + + wctdm_proslic_setreg_indirect_intr(wc, mod, 22, 0x0000); /* RNGY Initial Phase */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 29, 0x3600); /* RPTP */ + /* A write of 0x04 to register 64 will turn on the ringer */ + + if (fastringer) { + /* Speed up Ringer */ + reg20 = 0x7e6d; + + reg74 = 0x32; /* Default */ + /* Beef up Ringing voltage to 89V */ + if (boostringer) { + reg74 = 0x3f; + reg21 = 0x0247; /* RNGX */ + if (debug) + printk(KERN_DEBUG "Boosting fast ringer on channel %d (89V peak)\n", mod->card); + } else if (lowpower) { + reg21 = 0x014b; /* RNGX */ + if (debug) + printk(KERN_DEBUG "Reducing fast ring power on channel %d (50V peak)\n", mod->card); + } else if (fxshonormode && fxo_modes[_opermode].ring_x) { + reg21 = fxo_modes[_opermode].ring_x; + if (debug) + printk(KERN_DEBUG "fxshonormode: fast ring_x power on channel %d\n", mod->card); + } else { + reg21 = 0x01b9; + if (debug) + printk(KERN_DEBUG "Speeding up ringer on channel %d (25Hz)\n", mod->card); + } + wctdm_setreg_intr(wc, mod, 74, reg74); /* VBATH */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 20, reg20); /* RCO */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 21, reg21); /* RNGX */ + + } else { + /* Ringer Speed */ + if (fxshonormode && fxo_modes[_opermode].ring_osc){ + reg20 = fxo_modes[_opermode].ring_osc; + if (debug) + printk(KERN_DEBUG "fxshonormode: ring_osc speed on channel %d\n", mod->card); + } else { + reg20 = 0x7ef0; /* Default */ + } + + reg74 = 0x32; /* Default */ + /* Beef up Ringing voltage to 89V */ + if (boostringer) { + reg74 = 0x3f; + reg21 = 0x1d1; + if (debug) + printk(KERN_DEBUG "Boosting ringer on channel %d (89V peak)\n", mod->card); + } else if (lowpower) { + reg21 = 0x108; + if (debug) + printk(KERN_DEBUG "Reducing ring power on channel %d (50V peak)\n", mod->card); + } else if (fxshonormode && fxo_modes[_opermode].ring_x) { + reg21 = fxo_modes[_opermode].ring_x; + if (debug) + printk(KERN_DEBUG "fxshonormode: ring_x power on channel %d\n", mod->card); + } else { + reg21 = 0x160; + if (debug) + printk(KERN_DEBUG "Normal ring power on channel %d\n", mod->card); + } + wctdm_setreg_intr(wc, mod, 74, reg74); /* VBATH */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 20, reg20); /* RCO */ + wctdm_proslic_setreg_indirect_intr(wc, mod, 21, reg21); /* RNGX */ + } + } +#endif + if (debug) + printk(KERN_DEBUG "DONE ringgen on channel %d\n", mod->card); + return 0; +} + + static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wctdm *wc = chan->pvt;