[Asterisk-cvs] zaptel wcfxs.c,1.43,1.44

markster at lists.digium.com markster at lists.digium.com
Thu Apr 8 03:02:50 CDT 2004


Update of /usr/cvsroot/zaptel
In directory mongoose.digium.com:/tmp/cvs-serv5953

Modified Files:
	wcfxs.c 
Log Message:
Add RING detect, work on battery loss detection


Index: wcfxs.c
===================================================================
RCS file: /usr/cvsroot/zaptel/wcfxs.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- wcfxs.c	4 Apr 2004 14:53:14 -0000	1.43
+++ wcfxs.c	8 Apr 2004 07:03:40 -0000	1.44
@@ -145,6 +145,11 @@
 #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 @@
 	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 @@
 
 }
 
+#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 @@
 		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 @@
 	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 @@
 	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 @@
 				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 @@
 		       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 @@
 	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 @@
 		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 @@
 
 	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 @@
 				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 @@
 			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 @@
 	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 @@
 		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 @@
 			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 @@
 			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;




More information about the svn-commits mailing list