--- wctdm.c.svn 2009-02-01 09:04:29.000000000 +1300 +++ wctdm.c 2009-02-06 01:24:04.000000000 +1300 @@ -55,7 +55,7 @@ 0x07 : 41mA */ static int loopcurrent = 20; -#define POLARITY_XOR(card) ((reversepolarity!=0) ^ (wc->mod[(card)].fxs.reversepolarity!=0) ^ (wc->mod[(card)].fxs.vmwi_lrev!=0)) +#define POLARITY_XOR(card) ((reversepolarity!=0) ^ (wc->mod[(card)].fxs.reversepolarity!=0) ^ (wc->mod[(card)].fxs.vmwi_lrev!=0) ^ ((wc->mod[card].fxs.vmwisetting.vmwi_type & DAHDI_VMWI_HVAC)!=0)) static int reversepolarity = 0; @@ -244,6 +244,7 @@ struct wctdm { int vmwi_lrev:1; /* MWI Line Reversal*/ int vmwi_hvdc:1; /* MWI High Voltage DC Idle line */ int vmwi_hvac:1; /* MWI Neon High Voltage AC Idle line */ + int neonringing:1; /* Ring Generator is set for NEON */ struct calregs calregs; } fxs; } mod[NUM_CARDS]; @@ -301,6 +302,8 @@ static int fxstxgain = 0; static int fxsrxgain = 0; 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 void wctdm_transmitprep(struct wctdm *wc, unsigned char ints) { @@ -1045,7 +1048,7 @@ DAHDI_IRQ_HANDLER(wctdm_interrupt) for (x=0;x<4;x++) { if (wc->cardflag & (1 << x) && (wc->modtype[x] == MOD_TYPE_FXS)) { - if (wc->mod[x].fxs.lasttxhook == 0x4) { + if ( (wc->mod[x].fxs.lasttxhook == 0x4) && !wc->mod[x].fxs.neonringing ) { /* RINGing, prepare for OHT */ wc->mod[x].fxs.ohttimer = OHT_TIMER << 3; @@ -1057,14 +1060,29 @@ DAHDI_IRQ_HANDLER(wctdm_interrupt) wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x6 : 0x2;/* OHT mode when idle */ } else { if (wc->mod[x].fxs.ohttimer) { - wc->mod[x].fxs.ohttimer-= DAHDI_CHUNKSIZE; - if (!wc->mod[x].fxs.ohttimer) { - wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */ - if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) { - /* Apply the change if appropriate */ - wc->mod[x].fxs.lasttxhook = POLARITY_XOR(x) ? 0x5 : 0x1; - wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook); + /* check if still OnHook */ + if (!wc->mod[x].fxs.oldrxhook){ + wc->mod[x].fxs.ohttimer-= DAHDI_CHUNKSIZE; + if (!wc->mod[x].fxs.ohttimer) { + wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */ + /* if currently OHT */ + if ((wc->mod[x].fxs.lasttxhook == 0x2) || (wc->mod[x].fxs.lasttxhook == 0x6)) { + if (wc->mod[x].fxs.vmwi_hvac){ + /* force idle polarity Forward if ringing */ + wc->mod[x].fxs.idletxhookstate = 0x1; + /* Set ring generator for neon */ + wctdm_set_ring_generator_mode(wc, x, 1); + wc->mod[x].fxs.lasttxhook = 4; + } else { + wc->mod[x].fxs.lasttxhook = wc->mod[x].fxs.idletxhookstate; + } + /* Apply the change as appropriate */ + wctdm_setreg(wc, x, 64, wc->mod[x].fxs.lasttxhook); + } } + } else { + wc->mod[x].fxs.ohttimer = 0; + wc->mod[x].fxs.idletxhookstate = POLARITY_XOR(x) ? 0x5 : 0x1; /* Switch to Active : Reverse Forward */ } } } @@ -1472,22 +1490,46 @@ static int set_vmwi(struct wctdm * wc, i wc->mod[chan_idx].fxs.vmwi_hvac ); } - if (POLARITY_XOR(chan_idx)) { - wc->mod[chan_idx].fxs.idletxhookstate |= 0x4; - /* Do not set while currently ringing or open */ - if (wc->mod[chan_idx].fxs.lasttxhook != 0x04 && - wc->mod[chan_idx ].fxs.lasttxhook != 0x00) { - wc->mod[chan_idx ].fxs.lasttxhook |= 0x4; + + if (wc->mod[chan_idx].fxs.vmwi_hvac){ + /* Can't change ring generator while On Hook Transfer might be happening */ + if (!wc->mod[chan_idx].fxs.ohttimer) { + if (POLARITY_XOR(chan_idx)) { + wc->mod[chan_idx].fxs.idletxhookstate |= 0x04; + } else { + wc->mod[chan_idx].fxs.idletxhookstate &= ~0x04; + } + wctdm_set_ring_generator_mode(wc, chan_idx, 1); /* Set ring generator for neon */ + wc->mod[chan_idx].fxs.lasttxhook = 4; wctdm_setreg(wc, chan_idx, 64, wc->mod[chan_idx].fxs.lasttxhook); - } - } else { - wc->mod[chan_idx].fxs.idletxhookstate &= ~0x04; - /* Do not set while currently ringing or open */ - if (wc->mod[chan_idx].fxs.lasttxhook != 0x04 && - wc->mod[chan_idx].fxs.lasttxhook != 0x00) { + } + }else{ + if (wc->mod[chan_idx].fxs.neonringing){ + wctdm_set_ring_generator_mode(wc, chan_idx, 0); /* Set ring generator for normal ringer */ + wc->mod[chan_idx].fxs.lasttxhook = 1; /* ACTIVE, polarity determined later */ + } else { + /* Can't change polarity while ringing or when open */ + if ((wc->mod[chan_idx].fxs.lasttxhook == 0x04) || (wc->mod[chan_idx].fxs.lasttxhook == 0x00)){ + if (POLARITY_XOR(chan_idx)) { + wc->mod[chan_idx].fxs.idletxhookstate |= 0x04; + } else { + wc->mod[chan_idx].fxs.idletxhookstate &= ~0x04; + } + printk(KERN_DEBUG "Unable to change polarity on channel %d, lasttxhook=0x%X\n", + chan_idx, + wc->mod[chan_idx].fxs.lasttxhook + ); + return 0; + } + } + if (POLARITY_XOR(chan_idx)) { + wc->mod[chan_idx].fxs.idletxhookstate |= 0x04; + wc->mod[chan_idx].fxs.lasttxhook |= 0x04; + } else { + wc->mod[chan_idx].fxs.idletxhookstate &= ~0x04; wc->mod[chan_idx].fxs.lasttxhook &= ~0x04; - wctdm_setreg(wc, chan_idx, 64, wc->mod[chan_idx].fxs.lasttxhook); - } + } + wctdm_setreg(wc, chan_idx, 64, wc->mod[chan_idx].fxs.lasttxhook); } return 0; } @@ -1753,10 +1795,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); @@ -1774,35 +1812,8 @@ static int wctdm_init_proslic(struct wct wctdm_setreg(wc, card, 64, 0x0); 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) { @@ -1857,21 +1868,29 @@ static int wctdm_ioctl(struct dahdi_chan if (get_user(x, (__user int *) data)) return -EFAULT; wc->mod[chan->chanpos - 1].fxs.ohttimer = x << 3; - wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; /* OHT mode when idle */ - if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) { - /* Apply the change if appropriate */ - wc->mod[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; + /* OHT mode when idle */ + wc->mod[chan->chanpos - 1].fxs.idletxhookstate = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; + + if (wc->mod[chan->chanpos - 1].fxs.neonringing) { + /* keep same Forward polarity */ + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0x02; wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); + } else { + if (wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x1 || wc->mod[chan->chanpos - 1].fxs.lasttxhook == 0x5) { + /* Apply the change if appropriate */ + wc->mod[chan->chanpos - 1].fxs.lasttxhook = POLARITY_XOR(chan->chanpos - 1) ? 0x6 : 0x2; + wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); + } } break; 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->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x04) || - (wc->mod[chan->chanpos -1 ].fxs.lasttxhook == 0x00)) + if ((wc->mod[chan->chanpos - 1 ].fxs.lasttxhook == 0x04) || + (wc->mod[chan->chanpos - 1 ].fxs.lasttxhook == 0x00)) return -EINVAL; wc->mod[chan->chanpos - 1].fxs.reversepolarity = x; @@ -2017,10 +2036,117 @@ 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->mod[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->mod[card].fxs.lasttxhook); + wc->mod[card].fxs.lasttxhook = 0x1; /* Must be in FORWARD ACTIVE before setting ringer */ + wctdm_setreg(wc, card, 64, wc->mod[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; - if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) { /* XXX Enable hooksig for FXO XXX */ switch(txsig) { @@ -2042,40 +2168,47 @@ static int wctdm_hooksig(struct dahdi_ch switch(chan->sig) { case DAHDI_SIG_FXOKS: case DAHDI_SIG_FXOLS: - wc->mod[chan->chanpos-1].fxs.lasttxhook = (wc->mod[chan->chanpos-1].fxs.vmwi_hvac ? 4 : wc->mod[chan->chanpos-1].fxs.idletxhookstate); + /* Can't change Ring Generator during OHT */ + if (!wc->mod[chan->chanpos - 1].fxs.ohttimer){ + wctdm_set_ring_generator_mode(wc, chan->chanpos - 1, wc->mod[chan->chanpos - 1].fxs.vmwi_hvac); + wc->mod[chan->chanpos - 1].fxs.lasttxhook = (wc->mod[chan->chanpos - 1].fxs.vmwi_hvac ? 4 : wc->mod[chan->chanpos - 1].fxs.idletxhookstate); + }else{ + wc->mod[chan->chanpos - 1].fxs.lasttxhook = wc->mod[chan->chanpos - 1].fxs.idletxhookstate; + } break; case DAHDI_SIG_EM: - wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate; + wc->mod[chan->chanpos - 1].fxs.lasttxhook = wc->mod[chan->chanpos - 1].fxs.idletxhookstate; break; case DAHDI_SIG_FXOGS: - wc->mod[chan->chanpos-1].fxs.lasttxhook = 3; + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 3; break; } break; case DAHDI_TXSIG_OFFHOOK: switch(chan->sig) { case DAHDI_SIG_EM: - wc->mod[chan->chanpos-1].fxs.lasttxhook = 5; + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 5; break; default: - wc->mod[chan->chanpos-1].fxs.lasttxhook = wc->mod[chan->chanpos-1].fxs.idletxhookstate; + wc->mod[chan->chanpos - 1].fxs.lasttxhook = wc->mod[chan->chanpos - 1].fxs.idletxhookstate; break; } break; case DAHDI_TXSIG_START: - wc->mod[chan->chanpos-1].fxs.lasttxhook = 4; + wctdm_set_ring_generator_mode(wc, chan->chanpos - 1, 0); /* Set ringer mode */ + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 4; break; case DAHDI_TXSIG_KEWL: - wc->mod[chan->chanpos-1].fxs.lasttxhook = 0; + wc->mod[chan->chanpos - 1].fxs.lasttxhook = 0; break; default: printk(KERN_NOTICE "wctdm: Can't set tx state to %d\n", txsig); } if (debug) - printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, wc->mod[chan->chanpos-1].fxs.lasttxhook); + printk(KERN_DEBUG "Setting FXS hook state to %d (%02x)\n", txsig, wc->mod[chan->chanpos - 1].fxs.lasttxhook); #if 1 - wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos-1].fxs.lasttxhook); + wctdm_setreg(wc, chan->chanpos - 1, 64, wc->mod[chan->chanpos - 1].fxs.lasttxhook); #endif } return 0;