From 5e850c02b8a4410d607ae23d78a121100406997b Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Sat, 19 Mar 2011 23:33:52 -0500 Subject: wctdm24xxp: Use time interval for debouncing ring detect. We do not necessarily want to assume that the ring dection function is called for every frame. Also, use a state machine for ring detection. Signed-off-by: Shaun Ruffell --- drivers/dahdi/wctdm24xxp/base.c | 211 +++++++++++++++++++++------------- drivers/dahdi/wctdm24xxp/wctdm24xxp.h | 23 ++-- 2 files changed, 147 insertions(+), 87 deletions(-) diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c index b65f868..3535ed5 100644 --- a/drivers/dahdi/wctdm24xxp/base.c +++ b/drivers/dahdi/wctdm24xxp/base.c @@ -163,6 +163,8 @@ static alpha indirect_regs[] = {43,66,"LOOP_CLOSE_TRES_LOW",0x1000}, }; +#define DEBUG + /* names of HWEC modules */ static const char *vpmadt032_name = "VPMADT032"; static const char *noec_name = "NONE"; @@ -1730,101 +1732,150 @@ static void wctdm_qrvdri_check_hook(struct wctdm *wc, int card) return; } +static inline bool is_fxo_ringing(const struct fxo *const fxo) +{ + return ((fxo->hook_ring_shadow & 0x60) && + (fxo->battery_state == BATTERY_PRESENT)); +} + +static inline bool is_fxo_ringing_positive(const struct fxo *const fxo) +{ + return (((fxo->hook_ring_shadow & 0x60) == 0x20) && + (fxo->battery_state == BATTERY_PRESENT)); +} + +static inline bool is_fxo_ringing_negative(const struct fxo *const fxo) +{ + return (((fxo->hook_ring_shadow & 0x60) == 0x40) && + (fxo->battery_state == BATTERY_PRESENT)); +} + +#ifdef DEBUG +static inline void set_ring(struct fxo *fxo, enum ring_detector_state new) +{ + union modtypes *modtypes = container_of(fxo, union modtypes, fxo); + fxo->ring_state = new; +} +#else +static inline void set_ring(struct fxo *fxo, enum ring_detector_state new) +{ + fxo->ring_state = new; +} +#endif + +static void wctdm_fxo_ring_detect(struct wctdm *wc, struct wctdm_module *mod) +{ + struct fxo *const fxo = &mod->mod.fxo; + + /* 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 giving 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 traversals) */ + + switch (fxo->ring_state) { + case DEBOUNCING_RINGING_POSITIVE: + if (is_fxo_ringing_negative(fxo)) { + if (++fxo->ring_polarity_change_count > 4) { + dahdi_hooksig(&mod->chan->chan, + DAHDI_RXSIG_RING); + set_ring(fxo, RINGING); + if (debug) { + dev_info(&wc->vb.pdev->dev, + "RING on %s!\n", + mod->chan->chan.name); + } + } else { + set_ring(fxo, DEBOUNCING_RINGING_NEGATIVE); + } + + } else if (time_after(wc->framecount, + fxo->ringdebounce_timer)) { + set_ring(fxo, RINGOFF); + } + break; + case DEBOUNCING_RINGING_NEGATIVE: + if (is_fxo_ringing_positive(fxo)) { + if (++fxo->ring_polarity_change_count > 4) { + dahdi_hooksig(&mod->chan->chan, + DAHDI_RXSIG_RING); + set_ring(fxo, RINGING); + if (debug) { + dev_info(&wc->vb.pdev->dev, + "RING on %s!\n", + mod->chan->chan.name); + } + } else { + set_ring(fxo, DEBOUNCING_RINGING_POSITIVE); + } + + } else if (time_after(wc->framecount, + fxo->ringdebounce_timer)) { + set_ring(fxo, RINGOFF); + } + break; + case RINGING: + if (!is_fxo_ringing(fxo)) { + set_ring(fxo, DEBOUNCING_RINGOFF); + fxo->ringdebounce_timer = + wc->framecount + ringdebounce / 2; + } + break; + case DEBOUNCING_RINGOFF: + if (!is_fxo_ringing(fxo)) { + if (time_after(wc->framecount, + fxo->ringdebounce_timer)) { + if (debug) { + dev_info(&wc->vb.pdev->dev, + "NO RING on %s!\n", + mod->chan->chan.name); + } + dahdi_hooksig(&mod->chan->chan, + DAHDI_RXSIG_OFFHOOK); + set_ring(fxo, RINGOFF); + } + } else { + set_ring(fxo, RINGING); + } + break; + case RINGOFF: + if (is_fxo_ringing(fxo)) { + /* Look for positive/negative crossings in ring status + * reg */ + if (is_fxo_ringing_positive(fxo)) + set_ring(fxo, DEBOUNCING_RINGING_POSITIVE); + else + set_ring(fxo, DEBOUNCING_RINGING_NEGATIVE); + fxo->ringdebounce_timer = + wc->framecount + ringdebounce / 8; + fxo->ring_polarity_change_count = 0; + } + break; + } +} + static void wctdm_voicedaa_check_hook(struct wctdm *wc, struct wctdm_module *const mod) { #define MS_PER_CHECK_HOOK 1 - unsigned char res; signed char b; unsigned int abs_voltage; struct fxo *const fxo = &mod->mod.fxo; /* Try to track issues that plague slot one FXO's */ - b = fxo->hook_ring_shadow; - b &= 0x9b; + b = fxo->hook_ring_shadow & 0x9b; + if (fxo->offhook) { if (b != 0x9) wctdm_setreg_intr(wc, mod, 5, 0x9); } else { if (b != 0x8) wctdm_setreg_intr(wc, mod, 5, 0x8); - } - if (!fxo->offhook) { - 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 = fxo->hook_ring_shadow & 0x60; - if (0 == 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) - dev_info(&wc->vb.pdev->dev, "FW RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); - dahdi_hooksig(&mod->chan->chan, DAHDI_RXSIG_RING); - fxo->ringdebounce = ringdebounce / 16; - } else { - fxo->lastrdtx = res; - fxo->ringdebounce = ringdebounce / 16; - } - /* 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) - dev_info(&wc->vb.pdev->dev, "FW NO RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); - dahdi_hooksig(&mod->chan->chan, DAHDI_RXSIG_OFFHOOK); - } - } - } else { - res = fxo->hook_ring_shadow; - if ((res & 0x60) && (fxo->battery == BATTERY_PRESENT)) { - fxo->ringdebounce += (DAHDI_CHUNKSIZE * 16); - if (fxo->ringdebounce >= DAHDI_CHUNKSIZE * ringdebounce) { - if (!fxo->wasringing) { - fxo->wasringing = 1; - dahdi_hooksig(&mod->chan->chan, DAHDI_RXSIG_RING); - if (debug) - dev_info(&wc->vb.pdev->dev, "RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); - } - fxo->ringdebounce = DAHDI_CHUNKSIZE * ringdebounce; - } - } else { - fxo->ringdebounce -= DAHDI_CHUNKSIZE * 4; - if (fxo->ringdebounce <= 0) { - if (fxo->wasringing) { - fxo->wasringing = 0; - dahdi_hooksig(&mod->chan->chan, DAHDI_RXSIG_OFFHOOK); - if (debug) - dev_info(&wc->vb.pdev->dev, "NO RING on %d/%d!\n", wc->aspan->span.spanno, mod->card + 1); - } - fxo->ringdebounce = 0; - } - - } - } + + wctdm_fxo_ring_detect(wc, mod); } b = fxo->line_voltage_status; @@ -2111,7 +2162,7 @@ static void wctdm_fxs_off_hook(struct wctdm *wc, struct wctdm_module *const mod) #ifdef DEBUG if (robust) - wctdm_init_proslic(wc, card, 1, 0, 1); + wctdm_init_proslic(wc, mod, 1, 0, 1); #endif } diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h index 2ce703c..47e72af 100644 --- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h +++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h @@ -116,6 +116,15 @@ enum hook_state { DEBOUNCING_OFF_HOOK, }; +enum ring_detector_state { + RINGOFF = 0, + DEBOUNCING_RINGING_POSITIVE, + DEBOUNCING_RINGING_NEGATIVE, + DEBOUNCING_RINGING_OFF, + RINGING, + DEBOUNCING_RINGOFF, +}; + struct wctdm_cmd { struct list_head node; struct completion *complete; @@ -150,10 +159,11 @@ struct wctdm_chan { }; struct fxo { - int wasringing; - int lastrdtx; - int lastrdtx_count; - int ringdebounce; + enum ring_detector_state ring_state:4; + enum battery_state battery_state:4; + u8 ring_polarity_change_count:4; + u8 hook_ring_shadow; + s8 line_voltage_status; int offhook; int battdebounce; int battalarm; @@ -166,8 +176,7 @@ struct fxo { unsigned int neonmwi_debounce; unsigned int neonmwi_offcounter; unsigned long display_fxovoltage; - u8 hook_ring_shadow; - s8 line_voltage_status; + unsigned long ringdebounce_timer; }; struct fxs { @@ -226,7 +235,7 @@ enum module_type { }; struct wctdm_module { - union { + union modtypes { struct fxo fxo; struct fxs fxs; struct qrv qrv; -- cgit v1.2.3