diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-04-08 07:03:40 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-04-08 07:03:40 +0000 |
commit | 838f8a00a1cf12e5554905c669690d91a5751312 (patch) | |
tree | de175ea8f23657ac7b84e5c193d5196a4b82d241 /wctdm.c | |
parent | d2024e07e133925ce297b288a1e0f4750a0fed9c (diff) |
Add RING detect, work on battery loss detection
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@348 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wctdm.c')
-rwxr-xr-x | wctdm.c | 274 |
1 files changed, 218 insertions, 56 deletions
@@ -145,6 +145,11 @@ static alpha indirect_regs[] = #define MOD_TYPE_FXS 0 #define MOD_TYPE_FXO 1 +#define MINPEGTIME 10 * 8 /* 30 ms peak to peak gets us no more than 100 Hz */ +#define PEGTIME 50 * 8 /* 50ms peak to peak gets us rings of 10 Hz or more */ +#define PEGCOUNT 5 /* 5 cycles of pegging means RING */ + + struct wcfxs { struct pci_dev *dev; char *variety; @@ -162,17 +167,38 @@ struct wcfxs { int cardflag; /* Bit-map of present cards */ spinlock_t lock; + /* FXO Stuff */ + union { + struct { +#ifdef AUDIO_RINGCHECK + unsigned int pegtimer[NUM_CARDS]; + int pegcount[NUM_CARDS]; + int peg[NUM_CARDS]; + int ring[NUM_CARDS]; + int ringdebounce[NUM_CARDS]; +#endif + int offhook[NUM_CARDS]; + int wasringing[NUM_CARDS]; + int battdebounce[NUM_CARDS]; + int nobatttimer[NUM_CARDS]; + int ringdebounce[NUM_CARDS]; + int battery[NUM_CARDS]; + } fxo; + struct { + int oldrxhook[NUM_CARDS]; + int debouncehook[NUM_CARDS]; + int lastrxhook[NUM_CARDS]; + int debounce[NUM_CARDS]; + int ohttimer[NUM_CARDS]; + int idletxhookstate[NUM_CARDS]; /* IDLE changing hook state */ + int lasttxhook[NUM_CARDS]; + int palarms[NUM_CARDS]; + } fxs; + }; + /* Receive hook state and debouncing */ int modtype[NUM_CARDS]; - int oldrxhook[NUM_CARDS]; - int debouncehook[NUM_CARDS]; - int lastrxhook[NUM_CARDS]; - int debounce[NUM_CARDS]; - int ohttimer[NUM_CARDS]; - - int idletxhookstate[NUM_CARDS]; /* IDLE changing hook state */ - int lasttxhook[NUM_CARDS]; - int palarms[NUM_CARDS]; + unsigned long ioaddr; dma_addr_t readdma; dma_addr_t writedma; @@ -227,6 +253,55 @@ static inline void wcfxs_transmitprep(struct wcfxs *wc, unsigned char ints) } +#ifdef AUDIO_RINGCHECK +static inline void ring_check(struct wcfxs *wc, int card) +{ + int x; + short sample; + if (wc->modtype[card] != MOD_TYPE_FXO) + return; + for (x=0;x<ZT_CHUNKSIZE;x++) { + /* Look for pegging to indicate ringing */ + sample = ZT_XLAW(wc->chans[card].readchunk[x], (&(wc->chans[card]))); + if ((sample > 32000) && (wc->fxo.peg[card] != 1)) { + printk("High peg!\n"); + if ((wc->fxo.pegtimer[card] < PEGTIME) && (wc->fxo.pegtimer[card] > MINPEGTIME)) + wc->fxo.pegcount[card]++; + wc->fxo.pegtimer[card] = 0; + wc->fxo.peg[card] = 1; + } else if ((sample < -32000) && (wc->fxo.peg[card] != -1)) { + printk("Low peg!\n"); + if ((wc->fxo.pegtimer[card] < PEGTIME) && (wc->fxo.pegtimer[card] > MINPEGTIME)) + wc->fxo.pegcount[card]++; + wc->fxo.pegtimer[card] = 0; + wc->fxo.peg[card] = -1; + } + } + if (wc->fxo.pegtimer[card] > PEGTIME) { + /* Reset pegcount if our timer expires */ + wc->fxo.pegcount[card] = 0; + } + /* Decrement debouncer if appropriate */ + if (wc->fxo.ringdebounce[card]) + wc->fxo.ringdebounce[card]--; + if (!wc->fxo.offhook[card] && !wc->fxo.ringdebounce[card]) { + if (!wc->fxo.ring[card] && (wc->fxo.pegcount[card] > PEGCOUNT)) { + /* It's ringing */ + if (debug) + printk("RING!\n"); + zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); + wc->fxo.ring[card] = 1; + } + if (wc->fxo.ring[card] && !wc->fxo.pegcount[card]) { + /* No more ring */ + if (debug) + printk("NO RING!\n"); + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + wc->fxo.ring[card] = 0; + } + } +} +#endif static inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints) { volatile unsigned int *readchunk; @@ -247,6 +322,10 @@ static inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints) if (wc->cardflag & (1 << 0)) wc->chans[0].readchunk[x] = (readchunk[x]) & 0xff; } +#ifdef AUDIO_RINGCHECK + for (x=0;x<wc->cards;x++) + ring_check(wc, x); +#endif /* XXX We're wasting 8 taps. We should get closer :( */ for (x=0;x<wc->cards;x++) { if (wc->cardflag & (1 << x)) @@ -255,6 +334,7 @@ static inline void wcfxs_receiveprep(struct wcfxs *wc, unsigned char ints) zt_receive(&wc->span); } +static inline void wcfxs_voicedaa_check_hook(struct wcfxs *wc, int card); static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card); static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card); @@ -567,19 +647,19 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) for (x=0;x<4;x++) { if ((x < wc->cards) && (wc->cardflag & (1 << x)) && (wc->modtype[x] == MOD_TYPE_FXS)) { - if (wc->lasttxhook[x] == 0x4) { + if (wc->fxs.lasttxhook[x] == 0x4) { /* RINGing, prepare for OHT */ - wc->ohttimer[x] = OHT_TIMER << 3; - wc->idletxhookstate[x] = 0x2; /* OHT mode when idle */ + wc->fxs.ohttimer[x] = OHT_TIMER << 3; + wc->fxs.idletxhookstate[x] = 0x2; /* OHT mode when idle */ } else { - if (wc->ohttimer[x]) { - wc->ohttimer[x]-= ZT_CHUNKSIZE; - if (!wc->ohttimer[x]) { - wc->idletxhookstate[x] = 0x1; /* Switch to active */ - if (wc->lasttxhook[x] == 0x2) { + if (wc->fxs.ohttimer[x]) { + wc->fxs.ohttimer[x]-= ZT_CHUNKSIZE; + if (!wc->fxs.ohttimer[x]) { + wc->fxs.idletxhookstate[x] = 0x1; /* Switch to active */ + if (wc->fxs.lasttxhook[x] == 0x2) { /* Apply the change if appropriate */ - wc->lasttxhook[x] = 0x1; - wcfxs_setreg(wc, x, 64, wc->lasttxhook[x]); + wc->fxs.lasttxhook[x] = 0x1; + wcfxs_setreg(wc, x, 64, wc->fxs.lasttxhook[x]); } } } @@ -595,14 +675,16 @@ static void wcfxs_interrupt(int irq, void *dev_id, struct pt_regs *regs) wcfxs_proslic_check_hook(wc, x); if (!(wc->intcount & 0xfc)) wcfxs_proslic_recheck_sanity(wc, x); + } else if (wc->modtype[x] == MOD_TYPE_FXO) { + wcfxs_voicedaa_check_hook(wc, x); } } if (!(wc->intcount % 10000)) { /* Accept an alarm once per 10 seconds */ for (x=0;x<4;x++) if (wc->modtype[x] == MOD_TYPE_FXS) { - if (wc->palarms[x]) - wc->palarms[x]--; + if (wc->fxs.palarms[x]) + wc->fxs.palarms[x]--; } } wcfxs_receiveprep(wc, ints); @@ -927,7 +1009,7 @@ static int wcfxs_init_voicedaa(struct wcfxs *wc, int card, int fast, int manual, wcfxs_getreg(wc, card, 11) >> 4, (wcfxs_getreg(wc, card, 13) >> 2) & 0xf); /* Enable on-hook line monitor */ - wcfxs_setreg(wc, card, 5, 0x40); + wcfxs_setreg(wc, card, 5, 0x08); return 0; } @@ -939,7 +1021,7 @@ static int wcfxs_init_proslic(struct wcfxs *wc, int card, int fast, int manual, int x; /* By default, don't send on hook */ - wc->idletxhookstate [card] = 1; + wc->fxs.idletxhookstate [card] = 1; /* Sanity check the ProSLIC */ if (!sane && wcfxs_proslic_insane(wc, card)) @@ -1088,20 +1170,98 @@ static inline void wcfxs_proslic_recheck_sanity(struct wcfxs *wc, int card) wcfxs_init_proslic(wc, card, 1, 0, 1); } else { res = wcfxs_getreg(wc, card, 64); - if (!res && (res != wc->lasttxhook[card])) { - if (wc->palarms[card]++ < MAX_ALARMS) { + if (!res && (res != wc->fxs.lasttxhook[card])) { + if (wc->fxs.palarms[card]++ < MAX_ALARMS) { printk("Power alarm on module %d, resetting!\n", card + 1); - if (wc->lasttxhook[card] == 4) - wc->lasttxhook[card] = 1; - wcfxs_setreg(wc, card, 64, wc->lasttxhook[card]); + if (wc->fxs.lasttxhook[card] == 4) + wc->fxs.lasttxhook[card] = 1; + wcfxs_setreg(wc, card, 64, wc->fxs.lasttxhook[card]); } else { - if (wc->palarms[card] == MAX_ALARMS) + if (wc->fxs.palarms[card] == MAX_ALARMS) printk("Too many power alarms on card %d, NOT resetting!\n", card + 1); } } } } +static inline void wcfxs_voicedaa_check_hook(struct wcfxs *wc, int card) +{ + unsigned char res, b; + if (!wc->fxo.offhook[card]) { + res = wcfxs_getreg(wc, card, 5); + if (res & 0x60) { + if (!wc->fxo.wasringing[card]) { + zt_hooksig(&wc->chans[card], ZT_RXSIG_RING); + if (debug) + printk("RING!\n"); + } + wc->fxo.wasringing[card] = 100 * 8; + } else { + if (wc->fxo.wasringing[card]) { + wc->fxo.wasringing[card] -= ZT_CHUNKSIZE; + if (wc->fxo.wasringing[card] < 0) + wc->fxo.wasringing[card] = 0; + if (!wc->fxo.wasringing[card]) { + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + if (debug) + printk("NO RING!\n"); + } + } + + } + } + b = wcfxs_getreg(wc, card, 12) & 0x1f; + if (!b) { + wc->fxo.nobatttimer[card]++; +#if 0 + if (wc->fxo.battery[card]) + printk("Battery loss: %d (%d debounce)\n", b, wc->fxo.battdebounce[card]); +#endif + if (wc->fxo.battery[card] && !wc->fxo.battdebounce[card]) { + if (debug) + printk("NO BATTERY!\n"); + wc->fxo.battery[card] = 0; +#ifdef JAPAN + if ((!wc->ohdebounce) && wc->offhook) { + zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); + if (debug) + printk("Signalled On Hook\n"); +#ifdef ZERO_BATT_RING + wc->onhook++; +#endif + } +#else + zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); +#endif + wc->fxo.battdebounce[card] = BATT_DEBOUNCE; + } else if (!wc->fxo.battery[card]) + wc->fxo.battdebounce[card] = BATT_DEBOUNCE; + } else if (b >= 0x40) { + if (!wc->fxo.battery[card] && !wc->fxo.battdebounce[card]) { + if (debug) + printk("BATTERY!\n"); +#ifdef ZERO_BATT_RING + if (wc->onhook) { + wc->onhook = 0; + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); + if (debug) + printk("Signalled Off Hook\n"); + } +#else + zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); +#endif + wc->fxo.battery[card] = 1; + wc->fxo.nobatttimer[card] = 0; + wc->fxo.battdebounce[card] = BATT_DEBOUNCE; + } else if (wc->fxo.battery[card]) + wc->fxo.battdebounce[card] = BATT_DEBOUNCE; + } else { + /* It's something else... */ + wc->fxo.battdebounce[card] = BATT_DEBOUNCE; + } + +} + static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card) { char res; @@ -1112,25 +1272,25 @@ static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card) res = wcfxs_getreg(wc, card, 68); hook = (res & 1); - if (hook != wc->lastrxhook[card]) { + if (hook != wc->fxs.lastrxhook[card]) { /* Reset the debounce (must be multiple of 4ms) */ - wc->debounce[card] = 3 * 4 * 8; + wc->fxs.debounce[card] = 3 * 4 * 8; #if 0 - printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->debounce[card]); + printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->fxs.debounce[card]); #endif } else { - if (wc->debounce[card] > 0) { - wc->debounce[card]-= 4 * ZT_CHUNKSIZE; + if (wc->fxs.debounce[card] > 0) { + wc->fxs.debounce[card]-= 4 * ZT_CHUNKSIZE; #if 0 - printk("Sustaining hook %d, %d\n", hook, wc->debounce[card]); + printk("Sustaining hook %d, %d\n", hook, wc->fxs.debounce[card]); #endif - if (!wc->debounce[card]) { + if (!wc->fxs.debounce[card]) { #if 0 printk("Counted down debounce, newhook: %d...\n", hook); #endif - wc->debouncehook[card] = hook; + wc->fxs.debouncehook[card] = hook; } - if (!wc->oldrxhook[card] && wc->debouncehook[card]) { + if (!wc->fxs.oldrxhook[card] && wc->fxs.debouncehook[card]) { /* Off hook */ #if 1 if (debug) @@ -1139,20 +1299,20 @@ static inline void wcfxs_proslic_check_hook(struct wcfxs *wc, int card) zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK); if (robust) wcfxs_init_proslic(wc, card, 1, 0, 1); - wc->oldrxhook[card] = 1; + wc->fxs.oldrxhook[card] = 1; - } else if (wc->oldrxhook[card] && !wc->debouncehook[card]) { + } else if (wc->fxs.oldrxhook[card] && !wc->fxs.debouncehook[card]) { /* On hook */ #if 1 if (debug) #endif printk("wcfxs: Card %d Going on hook\n", card); zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK); - wc->oldrxhook[card] = 0; + wc->fxs.oldrxhook[card] = 0; } } } - wc->lastrxhook[card] = hook; + wc->fxs.lastrxhook[card] = hook; } @@ -1170,12 +1330,12 @@ static int wcfxs_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long dat return -EINVAL; if (get_user(x, (int *)data)) return -EFAULT; - wc->ohttimer[chan->chanpos - 1] = x << 3; - wc->idletxhookstate[chan->chanpos - 1] = 0x2; /* OHT mode when idle */ - if (wc->lasttxhook[chan->chanpos - 1] == 0x1) { + wc->fxs.ohttimer[chan->chanpos - 1] = x << 3; + wc->fxs.idletxhookstate[chan->chanpos - 1] = 0x2; /* OHT mode when idle */ + if (wc->fxs.lasttxhook[chan->chanpos - 1] == 0x1) { /* Apply the change if appropriate */ - wc->lasttxhook[chan->chanpos - 1] = 0x2; - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos - 1]); + wc->fxs.lasttxhook[chan->chanpos - 1] = 0x2; + wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->fxs.lasttxhook[chan->chanpos - 1]); } break; case WCFXS_GET_STATS: @@ -1249,7 +1409,7 @@ static int wcfxs_close(struct zt_chan *chan) wc->usecount--; MOD_DEC_USE_COUNT; for (x=0;x<wc->cards;x++) - wc->idletxhookstate[x] = 1; + wc->fxs.idletxhookstate[x] = 1; /* If we're dead, release us now */ if (!wc->usecount && wc->dead) wcfxs_release(wc); @@ -1265,10 +1425,12 @@ static int wcfxs_hooksig(struct zt_chan *chan, zt_txsig_t txsig) switch(txsig) { case ZT_TXSIG_START: case ZT_TXSIG_OFFHOOK: - wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x41); + wc->fxo.offhook[chan->chanpos - 1] = 1; + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x9); break; case ZT_TXSIG_ONHOOK: - wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x40); + wc->fxo.offhook[chan->chanpos - 1] = 0; + wcfxs_setreg(wc, chan->chanpos - 1, 5, 0x8); break; default: printk("wcfxo: Can't set tx state to %d\n", txsig); @@ -1279,21 +1441,21 @@ static int wcfxs_hooksig(struct zt_chan *chan, zt_txsig_t txsig) switch(chan->sig) { case ZT_SIG_FXOKS: case ZT_SIG_FXOLS: - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; + wc->fxs.lasttxhook[chan->chanpos-1] = wc->fxs.idletxhookstate[chan->chanpos-1]; break; case ZT_SIG_FXOGS: - wc->lasttxhook[chan->chanpos-1] = 3; + wc->fxs.lasttxhook[chan->chanpos-1] = 3; break; } break; case ZT_TXSIG_OFFHOOK: - wc->lasttxhook[chan->chanpos-1] = wc->idletxhookstate[chan->chanpos-1]; + wc->fxs.lasttxhook[chan->chanpos-1] = wc->fxs.idletxhookstate[chan->chanpos-1]; break; case ZT_TXSIG_START: - wc->lasttxhook[chan->chanpos-1] = 4; + wc->fxs.lasttxhook[chan->chanpos-1] = 4; break; case ZT_TXSIG_KEWL: - wc->lasttxhook[chan->chanpos-1] = 0; + wc->fxs.lasttxhook[chan->chanpos-1] = 0; break; default: printk("wcfxs: Can't set tx state to %d\n", txsig); @@ -1302,7 +1464,7 @@ static int wcfxs_hooksig(struct zt_chan *chan, zt_txsig_t txsig) printk("Setting FXS hook state to %d (%02x)\n", txsig, reg); #if 1 - wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->lasttxhook[chan->chanpos-1]); + wcfxs_setreg(wc, chan->chanpos - 1, 64, wc->fxs.lasttxhook[chan->chanpos-1]); #endif } return 0; |