From 29c38b862560126b6bd9150838be7c422f4f321d Mon Sep 17 00:00:00 2001 From: dbailey Date: Wed, 13 Aug 2008 19:06:04 +0000 Subject: Port in the NEON MWI detection from the AA50 into the wctdm24xxp driver git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4479 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/wctdm24xxp/base.c | 138 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 20 deletions(-) (limited to 'kernel/wctdm24xxp/base.c') diff --git a/kernel/wctdm24xxp/base.c b/kernel/wctdm24xxp/base.c index bfd40b5..1de74da 100644 --- a/kernel/wctdm24xxp/base.c +++ b/kernel/wctdm24xxp/base.c @@ -193,6 +193,17 @@ static int nativebridge = 0; static int ringdebounce = DEFAULT_RING_DEBOUNCE; static int fwringdetect = 0; static int latency = VOICEBUS_DEFAULT_LATENCY; + +#define NEONMWI_ON_DEBOUNCE (3) +#define MS_PER_HOOKCHECK (1) + +static int neonmwi_monitor = 0; /* Note: this causes use of full wave ring detect */ +static int neonmwi_level = 75; /* neon mwi trip voltage */ +static int neonmwi_envelope = 10; +static int neonmwi_offlimit = 16000; /* Time in milliseconds the monitor is checked before saying no message is waiting */ + +static int neonmwi_offlimit_cycles; /* Time in milliseconds the monitor is checked before saying no message is waiting */ + #ifdef VPM_SUPPORT static int vpmsupport = 1; static int vpmdtmfsupport = 0; @@ -1130,6 +1141,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) unsigned char res; signed char b; struct fxo *fxo = &wc->mods[card].fxo; + unsigned int abs_voltage; /* Try to track issues that plague slot one FXO's */ b = wc->cmdq[card].isrshadow[0]; /* Hook/Ring state */ @@ -1142,29 +1154,52 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) wctdm_setreg_intr(wc, card, 5, 0x8); } if (!fxo->offhook) { - if (fwringdetect) { + if(fwringdetect || neonmwi_monitor) { + /* Look for ring status bits (Ring Detect Signal Negative and + * Ring Detect Signal Positive) to transition back and forth + * some number of times to indicate that a ring is occurring. + * Provide some number of samples to allow for the transitions + * to occur before ginving up. + * NOTE: neon mwi voltages will trigger one of these bits to go active + * but not to have transitions between the two bits (i.e. no negative + * to positive or positive to negative transversals ) + */ res = wc->cmdq[card].isrshadow[0] & 0x60; - if (fxo->ringdebounce--) { - if (res && (res != fxo->lastrdtx) && (fxo->battery == 1)) { - if (!fxo->wasringing) { + if (0 == wc->mods[card].fxo.wasringing) { + if (res) { + /* Look for positive/negative crossings in ring status reg */ + fxo->wasringing = 2; + fxo->ringdebounce = ringdebounce /16; + fxo->lastrdtx = res; + fxo->lastrdtx_count = 0; + } + } else if (2 == fxo->wasringing) { + /* If ring detect signal has transversed */ + if (res && res != fxo->lastrdtx) { + /* if there are at least 3 ring polarity transversals */ + if(++fxo->lastrdtx_count >= 2) { fxo->wasringing = 1; if (debug) - printk("RING on %d/%d!\n", wc->span.spanno, card + 1); + printk("FW RING on %d/%d!\n", wc->span.spanno, card + 1); zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); + fxo->ringdebounce = ringdebounce / 16; + } else { + fxo->lastrdtx = res; + fxo->ringdebounce = ringdebounce / 16; } - fxo->lastrdtx = res; - fxo->ringdebounce = 10; - } else if (!res) { - if ((fxo->ringdebounce == 0) && fxo->wasringing) { - fxo->wasringing = 0; - if (debug) - printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1); - zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); - } + /* ring indicator (positve or negative) has not transitioned, check debounce count */ + } else if (--fxo->ringdebounce == 0) { + fxo->wasringing = 0; + } + } else { /* I am in ring state */ + if (res) { /* If any ringdetect bits are still active */ + fxo->ringdebounce = ringdebounce / 16; + } else if (--fxo->ringdebounce == 0) { + fxo->wasringing = 0; + if (debug) + printk("FW NO RING on %d/%d!\n", wc->span.spanno, card + 1); + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); } - } else if (res && (fxo->battery == BATTERY_PRESENT)) { - fxo->lastrdtx = res; - fxo->ringdebounce = 10; } } else { res = wc->cmdq[card].isrshadow[0]; @@ -1196,6 +1231,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) } b = wc->cmdq[card].isrshadow[1]; /* Voltage */ + abs_voltage = abs(b); if (fxovoltage) { if (!(wc->intcount % 100)) { @@ -1204,7 +1240,7 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) } } - if (abs(b) < battthresh) { + if (abs_voltage < battthresh) { /* possible existing states: battery lost, no debounce timer battery lost, debounce timer (going to battery present) @@ -1324,6 +1360,48 @@ static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card) } } } + + /* Look for neon mwi pulse */ + if (neonmwi_monitor && !wc->mods[card].fxo.offhook) { + /* Look for 4 consecutive voltage readings + * where the voltage is over the neon limit but + * does not vary greatly from the last reading + */ + if (fxo->battery == 1 && + abs_voltage > neonmwi_level && + (0 == fxo->neonmwi_last_voltage || + (b >= fxo->neonmwi_last_voltage - neonmwi_envelope && + b <= fxo->neonmwi_last_voltage + neonmwi_envelope ))) { + fxo->neonmwi_last_voltage = b; + if (NEONMWI_ON_DEBOUNCE == fxo->neonmwi_debounce) { + fxo->neonmwi_offcounter = neonmwi_offlimit_cycles; + if(0 == fxo->neonmwi_state) { + zt_qevent_lock(&wc->chans[card], ZT_EVENT_NEONMWI_ACTIVE); + fxo->neonmwi_state = 1; + if (debug) + printk("NEON MWI active for card %d\n", card+1); + } + fxo->neonmwi_debounce++; /* terminate the processing */ + } else if (NEONMWI_ON_DEBOUNCE > fxo->neonmwi_debounce) { + fxo->neonmwi_debounce++; + } else { /* Insure the count gets reset */ + fxo->neonmwi_offcounter = neonmwi_offlimit_cycles; + } + } else { + fxo->neonmwi_debounce = 0; + fxo->neonmwi_last_voltage = 0; + } + /* If no neon mwi pulse for given period of time, indicte no neon mwi state */ + if (fxo->neonmwi_state && 0 < fxo->neonmwi_offcounter ) { + fxo->neonmwi_offcounter--; + if (0 == fxo->neonmwi_offcounter) { + zt_qevent_lock(&wc->chans[card], ZT_EVENT_NEONMWI_INACTIVE); + fxo->neonmwi_state = 0; + if (debug) + printk("NEON MWI cleared for card %d\n", card+1); + } + } + } #undef MS_PER_CHECK_HOOK } @@ -1876,7 +1954,7 @@ static int wctdm_init_voicedaa(struct wctdm *wc, int card, int fast, int manual, reg16 |= (fxo_modes[_opermode].rt); wctdm_setreg(wc, card, 16, reg16); - if(fwringdetect) { + if(fwringdetect || neonmwi_monitor) { /* Enable ring detector full-wave rectifier mode */ wctdm_setreg(wc, card, 18, 2); wctdm_setreg(wc, card, 24, 0); @@ -2599,6 +2677,9 @@ static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat static int wctdm_open(struct zt_chan *chan) { struct wctdm *wc = chan->pvt; + int channo = chan->chanpos - 1; + unsigned long flags; + if (!(wc->cardflag & (1 << (chan->chanpos - 1)))) return -ENODEV; if (wc->dead) @@ -2608,7 +2689,14 @@ static int wctdm_open(struct zt_chan *chan) MOD_INC_USE_COUNT; #else try_module_get(THIS_MODULE); -#endif +#endif + /* Reset the mwi indicators */ + spin_lock_irqsave(&wc->reglock, flags); + wc->mods[channo].fxo.neonmwi_debounce = 0; + wc->mods[channo].fxo.neonmwi_offcounter = 0; + wc->mods[channo].fxo.neonmwi_state = 0; + spin_unlock_irqrestore(&wc->reglock, flags); + return 0; } @@ -3762,6 +3850,8 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic int y; int ret; + neonmwi_offlimit_cycles = neonmwi_offlimit /MS_PER_HOOKCHECK; + retry: wc = kmalloc(sizeof(struct wctdm), GFP_KERNEL); if (!wc) { @@ -4012,6 +4102,10 @@ module_param(fxsrxgain, int, 0600); module_param(ringdebounce, int, 0600); module_param(fwringdetect, int, 0600); module_param(latency, int, 0600); +module_param(neonmwi_monitor, int, 0600); +module_param(neonmwi_level, int, 0600); +module_param(neonmwi_envelope, int, 0600); +module_param(neonmwi_offlimit, int, 0600); #ifdef VPM_SUPPORT module_param(vpmsupport, int, 0600); module_param(vpmdtmfsupport, int, 0600); @@ -4041,6 +4135,10 @@ MODULE_PARM(fxstxgain, "i"); MODULE_PARM(fxsrxgain, "i"); MODULE_PARM(ringdebounce, "i"); MODULE_PARM(fwringdetect, "i"); +MODULE_PARM(neonmwi_monitor, "i"); +MODULE_PARM(neonmwi_level, "i"); +MODULE_PARM(neonmwi_envelope, "i"); +MODULE_PARM(neonmwi_offlimit, "i"); #ifdef VPM_SUPPORT MODULE_PARM(vpmsupport, "i"); MODULE_PARM(vpmdtmfsupport, "i"); -- cgit v1.2.3