summaryrefslogtreecommitdiff
path: root/wcfxs.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-04-08 07:03:40 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-04-08 07:03:40 +0000
commit838f8a00a1cf12e5554905c669690d91a5751312 (patch)
treede175ea8f23657ac7b84e5c193d5196a4b82d241 /wcfxs.c
parentd2024e07e133925ce297b288a1e0f4750a0fed9c (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 'wcfxs.c')
-rwxr-xr-xwcfxs.c274
1 files changed, 218 insertions, 56 deletions
diff --git a/wcfxs.c b/wcfxs.c
index e6a1860..a1f9740 100755
--- a/wcfxs.c
+++ b/wcfxs.c
@@ -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;