diff -up svn/base.c new/base.c --- svn/base.c 2009-01-31 21:14:47.000000000 +1300 +++ new/base.c 2009-02-11 22:41:35.000000000 +1300 @@ -87,7 +87,7 @@ static int loopcurrent = 20; * polarity reversal for the port, * and the state of the line reversal MWI indicator */ -#define POLARITY_XOR(card) ( (reversepolarity != 0) ^ (wc->mods[(card)].fxs.reversepolarity != 0) ^ (wc->mods[(card)].fxs.vmwi_linereverse != 0) ) +#define POLARITY_XOR(card) ( (reversepolarity != 0) ^ (wc->mods[(card)].fxs.reversepolarity != 0) ^ (wc->mods[(card)].fxs.vmwi_linereverse != 0) ^ ((wc->mods[card].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVAC)!=0) ) static int reversepolarity = 0; static alpha indirect_regs[] = @@ -235,6 +235,8 @@ static int vpmnlpmaxsupp = 0; #endif static int wctdm_init_proslic(struct wctdm *wc, int card, int fast , int manual, int sane); +static int wctdm_init_ring_generator_mode(struct wctdm *wc, int card); +static int wctdm_set_ring_generator_mode(struct wctdm *wc, int card, int mode); static inline int CMD_BYTE(int card, int bit, int altcs) { @@ -1551,26 +1553,35 @@ static inline void wctdm_isr_misc(struct wctdm_proslic_check_hook(wc, x); if (!(wc->intcount & 0xfc)) wctdm_proslic_recheck_sanity(wc, x); - if (wc->mods[x].fxs.lasttxhook == 0x4) { + if ( (wc->mods[x].fxs.lasttxhook == 0x4) && !wc->mods[x].fxs.neonringing ) { /* 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); */ - } + /* check if still OnHook */ + if (!wc->mods[x].fxs.oldrxhook){ + 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 : Reverse Forward */ + /* if currently OHT */ + if ((wc->mods[x].fxs.lasttxhook == 0x2) || (wc->mods[x].fxs.lasttxhook == 0x6)) { + if (wc->mods[x].fxs.vmwi_hvac){ + /* force idle polarity Forward if ringing */ + wc->mods[x].fxs.idletxhookstate = 0x1; + /* Set ring generator for neon */ + wctdm_set_ring_generator_mode(wc, x, 1); + wc->mods[x].fxs.lasttxhook = 0x14; + wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */ + } else { + wc->mods[x].fxs.lasttxhook = (wc->mods[x].fxs.idletxhookstate | 0x10); + wc->sethook[x] = CMD_WR(64, wc->mods[x].fxs.lasttxhook); /* Data enqueued here */ + } + } + } + } else { + wc->mods[x].fxs.ohttimer = 0; + wc->mods[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */ } } } @@ -1946,33 +1957,64 @@ static int wctdm_set_hwgain(struct wctdm static int set_vmwi(struct wctdm *wc, int chan_idx) { int x; - /* 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; + /* Presently only supports Line reversal and Neon HV pulses*/ + if (wc->mods[chan_idx].fxs.vmwi_active_messages){ + wc->mods[chan_idx].fxs.vmwi_linereverse = (wc->mods[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_LREV)?1:0; + wc->mods[chan_idx].fxs.vmwi_hvac = (wc->mods[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVAC)?1:0; +/* wc->mods[chan_idx].fxs.vmwi_hvdc = (wc->mods[chan_idx].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVDC)?1:0; */ } else { wc->mods[chan_idx].fxs.vmwi_linereverse = 0; + wc->mods[chan_idx].fxs.vmwi_hvac = 0; +/* wc->mods[chan_idx].fxs.vmwi_hvdc = 0; */ } - /* Set line polarity for new VMWI state */ - if (POLARITY_XOR(chan_idx)) { - wc->mods[chan_idx].fxs.idletxhookstate |= 0x14; - /* 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; + + if (wc->mods[chan_idx].fxs.vmwi_hvac){ + /* Can't change ring generator while On Hook Transfer might be happening */ + if (!wc->mods[chan_idx].fxs.ohttimer) { + if (POLARITY_XOR(chan_idx)) { + wc->mods[chan_idx].fxs.idletxhookstate |= 0x04; + } else { + wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04; + } + /* Set ring generator for neon */ + wctdm_set_ring_generator_mode(wc, chan_idx, 1); + wc->mods[chan_idx].fxs.lasttxhook = 0x14; wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook); - } + } } else { - wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04; - /* Do not set while currently ringing or open */ - if (wc->mods[chan_idx].fxs.lasttxhook != 0x04 && - wc->mods[chan_idx].fxs.lasttxhook != 0x00) { + if (wc->mods[chan_idx].fxs.neonringing){ + /* Set ring generator for normal ringer */ + wctdm_set_ring_generator_mode(wc, chan_idx, 0); + wc->mods[chan_idx].fxs.lasttxhook = 1; /* ACTIVE, polarity determined later */ + } else { + /* Can't change polarity while ringing or when open */ + if ((wc->mods[chan_idx].fxs.lasttxhook == 0x04) || (wc->mods[chan_idx].fxs.lasttxhook == 0x00)){ + if (POLARITY_XOR(chan_idx)) { + wc->mods[chan_idx].fxs.idletxhookstate |= 0x04; + } else { + wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04; + } + printk(KERN_DEBUG "Unable to change polarity on channel %d, lasttxhook=0x%X\n", + chan_idx, + wc->mods[chan_idx].fxs.lasttxhook + ); + return 0; + } + } + /* Set line polarity for new VMWI state */ + if (POLARITY_XOR(chan_idx)) { + wc->mods[chan_idx].fxs.idletxhookstate |= 0x04; + wc->mods[chan_idx].fxs.lasttxhook |= 0x14; + } else { + wc->mods[chan_idx].fxs.idletxhookstate &= ~0x04; 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); } - } + wc->sethook[chan_idx] = CMD_WR(64, wc->mods[chan_idx].fxs.lasttxhook); + } + if (debug) { printk(KERN_DEBUG "Setting VMWI on channel %d, messages=%d, lrev=%d\n", chan_idx, @@ -2244,10 +2286,6 @@ static int wctdm_init_proslic(struct wct if (fxshonormode) { fxsmode = acim2tiss[fxo_modes[_opermode].acim]; wctdm_setreg(wc, card, 10, 0x08 | fxsmode); - if (fxo_modes[_opermode].ring_osc) - wctdm_proslic_setreg_indirect(wc, card, 20, fxo_modes[_opermode].ring_osc); - if (fxo_modes[_opermode].ring_x) - wctdm_proslic_setreg_indirect(wc, card, 21, fxo_modes[_opermode].ring_x); } if (lowpower) wctdm_setreg(wc, card, 72, 0x10); @@ -2266,34 +2304,8 @@ static int wctdm_init_proslic(struct wct wctdm_setreg(wc, card, 1, 0x08); #endif - if (fastringer) { - /* Speed up Ringer */ - wctdm_proslic_setreg_indirect(wc, card, 20, 0x7e6d); - wctdm_proslic_setreg_indirect(wc, card, 21, 0x01b9); - /* Beef up Ringing voltage to 89V */ - if (boostringer) { - wctdm_setreg(wc, card, 74, 0x3f); - if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x247)) - return -1; - printk(KERN_INFO "Boosting fast ringer on slot %d (89V peak)\n", card + 1); - } else if (lowpower) { - if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x14b)) - return -1; - printk(KERN_INFO "Reducing fast ring power on slot %d (50V peak)\n", card + 1); - } else - printk(KERN_INFO "Speeding up ringer on slot %d (25Hz)\n", card + 1); - } else { - /* Beef up Ringing voltage to 89V */ - if (boostringer) { - wctdm_setreg(wc, card, 74, 0x3f); - if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x1d1)) - return -1; - printk(KERN_INFO "Boosting ringer on slot %d (89V peak)\n", card + 1); - } else if (lowpower) { - if (wctdm_proslic_setreg_indirect(wc, card, 21, 0x108)) - return -1; - printk(KERN_INFO "Reducing ring power on slot %d (50V peak)\n", card + 1); - } + if (wctdm_init_ring_generator_mode(wc, card)){ + return -1; } if (fxstxgain || fxsrxgain) { @@ -2485,12 +2497,19 @@ static int wctdm_ioctl(struct dahdi_chan 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; + /* OHT mode when idle */ + wc->mods[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; + + if (wc->mods[chan->chanpos - 1].fxs.neonringing) { + /* keep same Forward polarity */ + wc->mods[chan->chanpos - 1].fxs.lasttxhook = 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); */ + } else { + 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); + } } break; case DAHDI_VMWI_CONFIG: @@ -2621,10 +2640,10 @@ static int wctdm_ioctl(struct dahdi_chan return 0; #endif case DAHDI_SETPOLARITY: - if (get_user(x, (__user int *) data)) - return -EFAULT; if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_FXS) return -EINVAL; + if (get_user(x, (__user int *) data)) + return -EFAULT; /* 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)) @@ -2857,6 +2876,114 @@ static int wctdm_close(struct dahdi_chan return 0; } +static int wctdm_init_ring_generator_mode(struct wctdm *wc, int card) +{ + wctdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ + + /* neon trapezoid timers */ + wctdm_setreg(wc, card, 48, 0xe0); /* Active Timer low byte */ + wctdm_setreg(wc, card, 49, 0x01); /* Active Timer high byte */ + wctdm_setreg(wc, card, 50, 0xf0); /* Inactive Timer low byte */ + wctdm_setreg(wc, card, 51, 0x05); /* Inactive Timer high byte */ + + wctdm_set_ring_generator_mode(wc, card, 0); + + return 0; +} + +static int wctdm_set_ring_generator_mode(struct wctdm *wc, int card, int mode) +{ + int reg20,reg21,reg74; /* RCO, RNGX, VBATH */ + + wc->mods[card].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", card, wc->mods[card].fxs.lasttxhook); + wc->mods[card].fxs.lasttxhook = 0x1; /* Must be in FORWARD ACTIVE before setting ringer */ + wctdm_setreg(wc, card, 64, wc->mods[card].fxs.lasttxhook); + + wctdm_proslic_setreg_indirect(wc, card, 22, 0x03e8); /* RNGY (4 HZ) */ + wctdm_proslic_setreg_indirect(wc, card, 21, 0x7bef); /* RNGX (91.5Vpk) */ + wctdm_proslic_setreg_indirect(wc, card, 20, 0x009f); /* RCO (RNGX, t rise) */ + + wctdm_setreg(wc, card, 34, 0x19); /* Ringing Osc. Control */ + wctdm_setreg(wc, card, 74, 0x3f); /* VBATH 94.5V */ + wctdm_proslic_setreg_indirect(wc, card, 29, 0x4600); /* RPTP */ + /* A write of 0x04 to register 64 will turn on the VM led */ + } else { + wctdm_setreg(wc, card, 34, 0x00); /* Ringing Osc. Control */ + + wctdm_proslic_setreg_indirect(wc, card, 22, 0x0000); /* RNGY Initial Phase */ + wctdm_proslic_setreg_indirect(wc, card, 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", card); + } else if (lowpower) { + reg21 = 0x014b; /* RNGX */ + if (debug) + printk(KERN_DEBUG "Reducing fast ring power on channel %d (50V peak)\n", 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", card); + } else { + reg21 = 0x01b9; + if (debug) + printk(KERN_DEBUG "Speeding up ringer on channel %d (25Hz)\n", card); + } + wctdm_setreg(wc, card, 74, reg74); /* VBATH */ + wctdm_proslic_setreg_indirect(wc, card, 20, reg20); /* RCO */ + wctdm_proslic_setreg_indirect(wc, card, 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", 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", card); + } else if (lowpower) { + reg21 = 0x108; + if (debug) + printk(KERN_DEBUG "Reducing ring power on channel %d (50V peak)\n", 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", card); + } else { + reg21 = 0x160; + if (debug) + printk(KERN_DEBUG "Normal ring power on channel %d\n", card); + } + wctdm_setreg(wc, card, 74, reg74); /* VBATH */ + wctdm_proslic_setreg_indirect(wc, card, 20, reg20); /* RCO */ + wctdm_proslic_setreg_indirect(wc, card, 21, reg21); /* RNGX */ + } + } + return 0; +} + static int wctdm_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) { struct wctdm *wc = chan->pvt; @@ -2899,9 +3026,19 @@ static int wctdm_hooksig(struct dahdi_ch switch(txsig) { case DAHDI_TXSIG_ONHOOK: switch(chan->sig) { - case DAHDI_SIG_EM: case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: + /* Can't change Ring Generator during OHT */ + if (!wc->mods[chan->chanpos - 1].fxs.ohttimer){ + wctdm_set_ring_generator_mode(wc, chan->chanpos - 1, wc->mods[chan->chanpos - 1].fxs.vmwi_hvac); + wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 | + (wc->mods[chan->chanpos - 1].fxs.vmwi_hvac ? 4 : wc->mods[chan->chanpos - 1].fxs.idletxhookstate); + }else{ + wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 | + wc->mods[chan->chanpos - 1].fxs.idletxhookstate; + } + break; + case DAHDI_SIG_EM: wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x10 | wc->mods[chan->chanpos - 1].fxs.idletxhookstate; break; @@ -2930,6 +3067,7 @@ static int wctdm_hooksig(struct dahdi_ch } break; case DAHDI_TXSIG_START: + wctdm_set_ring_generator_mode(wc, chan->chanpos - 1, 0); /* Set ringer mode */ wc->mods[chan->chanpos - 1].fxs.lasttxhook = 0x14; break; case DAHDI_TXSIG_KEWL: diff -up svn/wctdm24xxp.h new/wctdm24xxp.h --- svn/wctdm24xxp.h 2009-01-31 21:14:47.000000000 +1300 +++ new/wctdm24xxp.h 2009-02-11 20:47:14.000000000 +1300 @@ -251,6 +251,10 @@ struct wctdm { struct dahdi_vmwi_info vmwisetting; int vmwi_active_messages; int vmwi_linereverse; + int vmwi_hvdc; + int vmwi_hvac; + int neonringing:1; /* Ring Generator is set for NEON */ + int reversepolarity; /* polarity reversal */ struct calregs calregs; } fxs;