[svn-commits] mattf: branch 1.4 r2762 - in /branches/1.4: ./ wctdm24xxp/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Fri Jul 20 13:54:21 CDT 2007


Author: mattf
Date: Fri Jul 20 13:54:20 2007
New Revision: 2762

URL: http://svn.digium.com/view/zaptel?view=rev&rev=2762
Log:
Merged revisions 2761 via svnmerge from 
https://origsvn.digium.com/svn/zaptel/branches/1.2

........
r2761 | mattf | 2007-07-20 11:19:47 -0500 (Fri, 20 Jul 2007) | 1 line

New product support, new echo canceler and new boards
........

Added:
    branches/1.4/wctdm24xxp/
      - copied from r2761, branches/1.2/wctdm24xxp/
    branches/1.4/wctdm24xxp/GpakApi.c
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/GpakApi.c
    branches/1.4/wctdm24xxp/GpakApi.h
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/GpakApi.h
    branches/1.4/wctdm24xxp/GpakCust.c
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/GpakCust.c
    branches/1.4/wctdm24xxp/GpakCust.h
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/GpakCust.h
    branches/1.4/wctdm24xxp/GpakHpi.h
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/GpakHpi.h
    branches/1.4/wctdm24xxp/Makefile
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/Makefile
    branches/1.4/wctdm24xxp/Makefile.kernel26
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/Makefile.kernel26
    branches/1.4/wctdm24xxp/base.c
      - copied, changed from r2761, branches/1.2/wctdm24xxp/base.c
    branches/1.4/wctdm24xxp/gpakErrs.h
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/gpakErrs.h
    branches/1.4/wctdm24xxp/gpakenum.h
      - copied unchanged from r2761, branches/1.2/wctdm24xxp/gpakenum.h
    branches/1.4/wctdm24xxp/wctdm24xxp.h
      - copied, changed from r2761, branches/1.2/wctdm24xxp/wctdm24xxp.h
Removed:
    branches/1.4/wctdm24xxp.c
Modified:
    branches/1.4/   (props changed)
    branches/1.4/Makefile
    branches/1.4/zaptel-base.c

Propchange: branches/1.4/
------------------------------------------------------------------------------
Binary property 'branch-1.2-merged' - no diff available.

Modified: branches/1.4/Makefile
URL: http://svn.digium.com/view/zaptel/branches/1.4/Makefile?view=diff&rev=2762&r1=2761&r2=2762
==============================================================================
--- branches/1.4/Makefile (original)
+++ branches/1.4/Makefile Fri Jul 20 13:54:20 2007
@@ -98,8 +98,8 @@
   BUILD_XPP:=yes
 endif
 
-TOPDIR_MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode wcte12xp
-SUBDIR_MODULES:=wct4xxp wctc4xxp xpp
+TOPDIR_MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode wcte12xp
+SUBDIR_MODULES:=wct4xxp wctc4xxp xpp wctdm24xxp
 BUILD_TOPDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(TOPDIR_MODULES))
 BUILD_SUBDIR_MODULES:=$(filter-out $(MENUSELECT_MODULES),$(SUBDIR_MODULES))
 BUILD_MODULES:=$(BUILD_TOPDIR_MODULES) $(BUILD_SUBDIR_MODULES)

Copied: branches/1.4/wctdm24xxp/base.c (from r2761, branches/1.2/wctdm24xxp/base.c)
URL: http://svn.digium.com/view/zaptel/branches/1.4/wctdm24xxp/base.c?view=diff&rev=2762&p1=branches/1.2/wctdm24xxp/base.c&r1=2761&p2=branches/1.4/wctdm24xxp/base.c&r2=2762
==============================================================================
--- branches/1.2/wctdm24xxp/base.c (original)
+++ branches/1.4/wctdm24xxp/base.c Fri Jul 20 13:54:20 2007
@@ -4,8 +4,11 @@
  * Written by Mark Spencer <markster at digium.com>
  * Support for TDM800P and VPM150M by Matthew Fredrickson <creslin at digium.com>
  *
- * Copyright (C) 2005, 2006, Digium, Inc.
+ * Copyright (C) 2005,2006, Digium, Inc.
+ * All rights reserved.
  *
+ * Sections for QRV cards written by Jim Dixon <jim at lambdatel.com>
+ * Copyright (C) 2006, Jim Dixon and QRV Communications
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,6 +26,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  */
+/* For QRV DRI cards, gain is signed short, expressed in hundredths of
+db (in reference to 1v Peak @ 1000Hz) , as follows:
+
+Rx Gain: -11.99 to 15.52 db
+Tx Gain - No Pre-Emphasis: -35.99 to 12.00 db
+Tx Gain - W/Pre-Emphasis: -23.99 to 0.00 db
+*/
 
 #include <linux/version.h>
 #include <linux/kernel.h>
@@ -225,7 +235,7 @@
 #ifdef STANDALONE_ZAPATA
 #include "zaptel.h"
 #else
-#include <linux/zaptel.h>
+#include <zaptel/zaptel.h>
 #endif
 
 #ifdef LINUX26
@@ -266,6 +276,11 @@
 static int fxshonormode = 0;
 static int alawoverride = 0;
 static int fxo_addrs[4] = { 0x00, 0x08, 0x04, 0x0c };
+static int fxotxgain = 0;
+static int fxorxgain = 0;
+static int fxstxgain = 0;
+static int fxsrxgain = 0;
+static int nativebridge = 1;
 #ifdef VPM_SUPPORT
 static int vpmsupport = 1;
 static int vpmdtmfsupport = 0;
@@ -470,8 +485,14 @@
 	ecval = ecval % EC_SIZE;
 #endif
 
+ 	/* if a QRV card, map it to its first channel */  
+ 	if ((wc->modtype[card] ==  MOD_TYPE_QRV) && (card & 3))
+ 	{
+ 		return;
+ 	}
  	if (wc->altcs[card])
  		subaddr = 0;
+ 
 
  
 	/* Skip audio */
@@ -497,6 +518,8 @@
 			curcmd = CMD_RD(64);
 		else if (wc->modtype[card] == MOD_TYPE_FXO)
 			curcmd = CMD_RD(12);
+		else if (wc->modtype[card] == MOD_TYPE_QRV)
+			curcmd = CMD_RD(3);
 		else if (wc->modtype[card] == MOD_TYPE_VPM) {
 #ifdef FANCY_ECHOCAN
 			if (wc->blinktimer >= 0xf) {
@@ -543,6 +566,22 @@
  		writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
 	} else if (wc->modtype[card] == MOD_TYPE_VPM150M) {
 #endif
+ 	} else if (wc->modtype[card] == MOD_TYPE_QRV) {
+ 
+ 		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
+ 		if (!curcmd)
+ 		{
+ 			writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
+ 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = 0x00;
+ 		}
+ 		else
+ 		{
+ 			if (curcmd & __CMD_WR)
+ 				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x40 | ((curcmd >> 8) & 0x3f);
+ 			else
+ 				writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0xc0 | ((curcmd >> 8) & 0x3f);
+ 			writechunk[CMD_BYTE(card, 2, wc->altcs[card])] = curcmd & 0xff;
+ 		}
 	} else if (wc->modtype[card] == MOD_TYPE_NONE) {
  		writechunk[CMD_BYTE(card, 0, wc->altcs[card])] = 0x00;
  		writechunk[CMD_BYTE(card, 1, wc->altcs[card])] = 0x00;
@@ -601,6 +640,11 @@
 	unsigned char ident;
 	int x;
 
+	/* if a QRV card, map it to its first channel */  
+	if ((wc->modtype[card] ==  MOD_TYPE_QRV) && (card & 3))
+	{
+		return;
+	}
 	/* Skip audio */
 	readchunk += 24;
 	spin_lock_irqsave(&wc->reglock, flags);
@@ -644,6 +688,8 @@
 			wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(68);	/* Hook state */
 		} else if (wc->modtype[card] == MOD_TYPE_FXO) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(5);	/* Hook/Ring state */
+		} else if (wc->modtype[card] == MOD_TYPE_QRV) {
+			wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 0] = CMD_RD(3);	/* COR/CTCSS state */
 #ifdef VPM_SUPPORT
 		} else if (wc->modtype[card] == MOD_TYPE_VPM) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 0] = CMD_RD(0xb9); /* DTMF interrupt */
@@ -659,6 +705,8 @@
 #endif
 		} else if (wc->modtype[card] == MOD_TYPE_FXO) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(29);	/* Battery */
+		} else if (wc->modtype[card] == MOD_TYPE_QRV) {
+			wc->cmdq[card & 0xfc].cmds[USER_COMMANDS + 1] = CMD_RD(3);	/* Battery */
 #ifdef VPM_SUPPORT
 		} else if (wc->modtype[card] == MOD_TYPE_VPM) {
 			wc->cmdq[card].cmds[USER_COMMANDS + 1] = CMD_RD(0xbd); /* DTMF interrupt */
@@ -742,6 +790,12 @@
 	unsigned long flags;
 	int hit=0;
 	int ret;
+
+	/* if a QRV card, use only its first channel */  
+	if (wc->modtype[card] ==  MOD_TYPE_QRV)
+	{
+		if (card & 3) return(0);
+	}
 	do {
 		spin_lock_irqsave(&wc->reglock, flags);
 		hit = empty_slot(wc, card);
@@ -773,6 +827,12 @@
 	unsigned long flags;
 	int hit;
 	int ret=0;
+
+	/* if a QRV card, use only its first channel */  
+	if (wc->modtype[card] ==  MOD_TYPE_QRV)
+	{
+		if (card & 3) return(0);
+	}
 	do {
 		spin_lock_irqsave(&wc->reglock, flags);
 		hit = empty_slot(wc, card);
@@ -1162,6 +1222,60 @@
 		}
 	}
 #endif
+}
+
+static inline void wctdm_qrvdri_check_hook(struct wctdm *wc, int card)
+{
+	signed char b,b1;
+	int qrvcard = card & 0xfc;
+
+	
+	if (wc->qrvdebtime[card] >= 2) wc->qrvdebtime[card]--;
+	b = wc->cmdq[qrvcard].isrshadow[0];	/* Hook/Ring state */
+	b &= 0xcc; /* use bits 3-4 and 6-7 only */
+
+	if (wc->radmode[qrvcard] & RADMODE_IGNORECOR) b &= ~4;
+	else if (!(wc->radmode[qrvcard] & RADMODE_INVERTCOR)) b ^= 4;
+	if (wc->radmode[qrvcard + 1] | RADMODE_IGNORECOR) b &= ~0x40;
+	else if (!(wc->radmode[qrvcard + 1] | RADMODE_INVERTCOR)) b ^= 0x40;
+
+	if ((wc->radmode[qrvcard] & RADMODE_IGNORECT) || 
+		(!(wc->radmode[qrvcard] & RADMODE_EXTTONE))) b &= ~8;
+	else if (!(wc->radmode[qrvcard] & RADMODE_EXTINVERT)) b ^= 8;
+	if ((wc->radmode[qrvcard + 1] & RADMODE_IGNORECT) || 
+		(!(wc->radmode[qrvcard + 1] & RADMODE_EXTTONE))) b &= ~0x80;
+	else if (!(wc->radmode[qrvcard + 1] & RADMODE_EXTINVERT)) b ^= 0x80;
+	/* now b & MASK should be zero, if its active */
+	/* check for change in chan 0 */
+	if ((!(b & 0xc)) != wc->qrvhook[qrvcard + 2])
+	{
+		wc->qrvdebtime[qrvcard] = wc->debouncetime[qrvcard];
+		wc->qrvhook[qrvcard + 2] = !(b & 0xc);
+	} 
+	/* if timed-out and ready */
+	if (wc->qrvdebtime[qrvcard] == 1)
+	{
+		b1 = wc->qrvhook[qrvcard + 2];
+if (debug) printk("QRV channel %d rx state changed to %d\n",qrvcard,wc->qrvhook[qrvcard + 2]);
+		zt_hooksig(&wc->chans[qrvcard], 
+			(b1) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK);
+		wc->qrvdebtime[card] = 0;
+	}
+	/* check for change in chan 1 */
+	if ((!(b & 0xc0)) != wc->qrvhook[qrvcard + 3])
+	{
+		wc->qrvdebtime[qrvcard + 1] = QRV_DEBOUNCETIME;
+		wc->qrvhook[qrvcard + 3] = !(b & 0xc0);
+	}
+	if (wc->qrvdebtime[qrvcard + 1] == 1)
+	{
+		b1 = wc->qrvhook[qrvcard + 3];
+if (debug) printk("QRV channel %d rx state changed to %d\n",qrvcard + 1,wc->qrvhook[qrvcard + 3]);
+		zt_hooksig(&wc->chans[qrvcard + 1], 
+			(b1) ? ZT_RXSIG_OFFHOOK : ZT_RXSIG_ONHOOK);
+		wc->qrvdebtime[card] = 0;
+	}
+	return;
 }
 
 static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
@@ -1408,6 +1522,7 @@
 static inline void wctdm_isr_misc(struct wctdm *wc)
 {
 	int x;
+
 	for (x=0;x<wc->cards;x++) {
 		if (wc->cardflag & (1 << x)) {
 			if (wc->modtype[x] == MOD_TYPE_FXS) {
@@ -1439,6 +1554,8 @@
 				}
 			} else if (wc->modtype[x] == MOD_TYPE_FXO) {
 				wctdm_voicedaa_check_hook(wc, x);
+			} else if (wc->modtype[x] == MOD_TYPE_QRV) {
+				wctdm_qrvdri_check_hook(wc, x);
 			}
 		}
 	}
@@ -1846,6 +1963,8 @@
 	unsigned char reg16=0, reg26=0, reg30=0, reg31=0;
 	long newjiffies;
 
+	if (wc->modtype[card & 0xfc] == MOD_TYPE_QRV) return -2;
+
 	wc->modtype[card] = MOD_TYPE_NONE;
 	/* Wait just a bit */
 	wait_just_a_bit(HZ/10);
@@ -1923,6 +2042,40 @@
 	/* Apply negative Rx gain of 4.5db to DAA */
 	wctdm_setreg(wc, card, 39, 0x14);	/* 4db */
 	wctdm_setreg(wc, card, 41, 0x15);	/* 0.5db */
+
+	
+	/* Take values for fxotxgain and fxorxgain and apply them to module */
+	if (fxotxgain) {
+		if (fxotxgain >=  -150 && fxotxgain < 0) {
+			wctdm_setreg(wc, card, 38, 16 + (fxotxgain/-10));
+			if(fxotxgain % 10) {
+				wctdm_setreg(wc, card, 40, 16 + (-fxotxgain%10));
+			}
+		}
+		else if (fxotxgain <= 120 && fxotxgain > 0) {
+			wctdm_setreg(wc, card, 38, fxotxgain/10);
+			if(fxotxgain % 10) {
+				wctdm_setreg(wc, card, 40, (fxotxgain%10));
+			}
+		}
+	}
+	if (fxorxgain) {
+		if (fxorxgain >=  -150 && fxorxgain < 0) {
+			wctdm_setreg(wc, card, 39, 16+ (fxorxgain/-10));
+			if(fxotxgain % 10) {
+				wctdm_setreg(wc, card, 41, 16 + (-fxorxgain%10));
+			}
+		}
+		else if (fxorxgain <= 120 && fxorxgain > 0) {
+			wctdm_setreg(wc, card, 39, fxorxgain/10);
+			if(fxorxgain % 10) {
+				wctdm_setreg(wc, card, 41, (fxorxgain%10));
+			}
+		}
+	}
+	
+	if(debug)
+		printk("DEBUG fxotxgain:%i.%i fxorxgain:%i.%i\n", (wctdm_getreg(wc, card, 38)/16) ? -(wctdm_getreg(wc, card, 38) - 16) : wctdm_getreg(wc, card, 38), (wctdm_getreg(wc, card, 40)/16) ? -(wctdm_getreg(wc, card, 40) - 16) : wctdm_getreg(wc, card, 40), (wctdm_getreg(wc, card, 39)/16) ? -(wctdm_getreg(wc, card, 39) - 16): wctdm_getreg(wc, card, 39), (wctdm_getreg(wc, card, 41)/16)?-(wctdm_getreg(wc, card, 41) - 16) : wctdm_getreg(wc, card, 41));
 	
 	return 0;
 		
@@ -1932,9 +2085,11 @@
 {
 
 	unsigned short tmp[5];
-	unsigned char r19;
+	unsigned char r19,r9;
 	int x;
 	int fxsmode=0;
+
+	if (wc->modtype[card & 0xfc] == MOD_TYPE_QRV) return -2;
 
 	/* By default, don't send on hook */
 	wc->mods[card].fxs.idletxhookstate = 1;
@@ -2125,11 +2280,174 @@
 			printk("Reducing ring power on slot %d (50V peak)\n", card + 1);
 		}
 	}
+
+	if(fxstxgain || fxsrxgain) {
+		r9 = wctdm_getreg(wc, card, 9);
+		switch (fxstxgain) {
+		
+			case 35:
+				r9+=8;
+				break;
+			case -35:
+				r9+=4;
+				break;
+			case 0: 
+				break;
+		}
+	
+		switch (fxsrxgain) {
+			
+			case 35:
+				r9+=2;
+				break;
+			case -35:
+				r9+=1;
+				break;
+			case 0:
+				break;
+		}
+		wctdm_setreg(wc,card,9,r9);
+	}
+
+	if(debug)
+			printk("DEBUG: fxstxgain:%s fxsrxgain:%s\n",((wctdm_getreg(wc, card, 9)/8) == 1)?"3.5":(((wctdm_getreg(wc,card,9)/4) == 1)?"-3.5":"0.0"),((wctdm_getreg(wc, card, 9)/2) == 1)?"3.5":((wctdm_getreg(wc,card,9)%2)?"-3.5":"0.0"));
+
 	wctdm_setreg(wc, card, 64, 0x01);
 	wc->mods[card].fxs.lasttxhook = 1;
 	return 0;
 }
 
+static int wctdm_init_qrvdri(struct wctdm *wc, int card)
+{
+	unsigned char x,y;
+	unsigned long endjif;
+
+	/* have to set this, at least for now */
+	wc->modtype[card] = MOD_TYPE_QRV;
+	if (!(card & 3)) /* if at base of card, reset and write it */
+	{
+		wctdm_setreg(wc,card,0,0x80); 
+		wctdm_setreg(wc,card,0,0x55);
+		wctdm_setreg(wc,card,1,0x69);
+		wc->qrvhook[card] = wc->qrvhook[card + 1] = 0;
+		wc->qrvhook[card + 2] = wc->qrvhook[card + 3] = 0xff;
+		wc->debouncetime[card] = wc->debouncetime[card + 1] = QRV_DEBOUNCETIME;
+		wc->qrvdebtime[card] = wc->qrvdebtime[card + 1] = 0;
+		wc->radmode[card] = wc->radmode[card + 1] = 0;
+		wc->txgain[card] = wc->txgain[card + 1] = 3599;
+		wc->rxgain[card] = wc->rxgain[card + 1] = 1199;
+	} else { /* channel is on same card as base, no need to test */
+		if (wc->modtype[card & 0x7c] == MOD_TYPE_QRV) 
+		{
+			/* only lower 2 are valid */
+			if (!(card & 2)) return 0;
+		}
+		wc->modtype[card] = MOD_TYPE_NONE;
+		return 1;
+	}
+	x = wctdm_getreg(wc,card,0);
+	y = wctdm_getreg(wc,card,1);
+	/* if not a QRV card, return as such */
+	if ((x != 0x55) || (y != 0x69))
+	{
+		wc->modtype[card] = MOD_TYPE_NONE;
+		return 1;
+	}
+	for(x = 0; x < 0x30; x++)
+	{
+		if ((x >= 0x1c) && (x <= 0x1e)) wctdm_setreg(wc,card,x,0xff);
+		else wctdm_setreg(wc,card,x,0);
+	}
+	wctdm_setreg(wc,card,0,0x80); 
+	endjif = jiffies + (HZ/10);
+	while(endjif > jiffies);
+	wctdm_setreg(wc,card,0,0x10); 
+	wctdm_setreg(wc,card,0,0x10); 
+	endjif = jiffies + (HZ/10);
+	while(endjif > jiffies);
+	/* set up modes */
+	wctdm_setreg(wc,card,0,0x1c); 
+	/* set up I/O directions */
+	wctdm_setreg(wc,card,1,0x33); 
+	wctdm_setreg(wc,card,2,0x0f); 
+	wctdm_setreg(wc,card,5,0x0f); 
+	/* set up I/O to quiescent state */
+	wctdm_setreg(wc,card,3,0x11);  /* D0-7 */
+	wctdm_setreg(wc,card,4,0xa);  /* D8-11 */
+	wctdm_setreg(wc,card,7,0);  /* CS outputs */
+	/* set up timeslots */
+	wctdm_setreg(wc,card,0x13,card + 0x80);  /* codec 2 tx, ts0 */
+	wctdm_setreg(wc,card,0x17,card + 0x80);  /* codec 0 rx, ts0 */
+	wctdm_setreg(wc,card,0x14,card + 0x81);  /* codec 1 tx, ts1 */
+	wctdm_setreg(wc,card,0x18,card + 0x81);  /* codec 1 rx, ts1 */
+	/* set up for max gains */
+	wctdm_setreg(wc,card,0x26,0x24); 
+	wctdm_setreg(wc,card,0x27,0x24); 
+	wctdm_setreg(wc,card,0x0b,0x01);  /* "Transmit" gain codec 0 */
+	wctdm_setreg(wc,card,0x0c,0x01);  /* "Transmit" gain codec 1 */
+	wctdm_setreg(wc,card,0x0f,0xff);  /* "Receive" gain codec 0 */
+	wctdm_setreg(wc,card,0x10,0xff);  /* "Receive" gain codec 1 */
+	return 0;
+}
+
+static void qrv_dosetup(struct zt_chan *chan,struct wctdm *wc)
+{
+int qrvcard;
+unsigned char r;
+long l;
+
+	/* actually do something with the values */
+	qrvcard = (chan->chanpos - 1) & 0xfc;
+	if (debug) printk("@@@@@ radmodes: %d,%d  rxgains: %d,%d   txgains: %d,%d\n",
+	wc->radmode[qrvcard],wc->radmode[qrvcard + 1],
+		wc->rxgain[qrvcard],wc->rxgain[qrvcard + 1],
+			wc->txgain[qrvcard],wc->txgain[qrvcard + 1]);
+	r = 0;
+	if (wc->radmode[qrvcard] & RADMODE_DEEMP) r |= 4;		
+	if (wc->radmode[qrvcard + 1] & RADMODE_DEEMP) r |= 8;		
+	if (wc->rxgain[qrvcard] < 1200) r |= 1;
+	if (wc->rxgain[qrvcard + 1] < 1200) r |= 2;
+	wctdm_setreg(wc, qrvcard, 7, r);
+	if (debug) printk("@@@@@ setting reg 7 to %02x hex\n",r);
+	r = 0;
+	if (wc->radmode[qrvcard] & RADMODE_PREEMP) r |= 3;
+	else if (wc->txgain[qrvcard] >= 3600) r |= 1;
+	else if (wc->txgain[qrvcard] >= 1200) r |= 2;
+	if (wc->radmode[qrvcard + 1] & RADMODE_PREEMP) r |= 0xc;
+	else if (wc->txgain[qrvcard + 1] >= 3600) r |= 4;
+	else if (wc->txgain[qrvcard + 1] >= 1200) r |= 8;
+	wctdm_setreg(wc, qrvcard, 4, r);
+	if (debug) printk("@@@@@ setting reg 4 to %02x hex\n",r);
+	r = 0;
+	if (wc->rxgain[qrvcard] >= 2400) r |= 1; 
+	if (wc->rxgain[qrvcard + 1] >= 2400) r |= 2; 
+	wctdm_setreg(wc, qrvcard, 0x25, r);
+	if (debug) printk("@@@@@ setting reg 0x25 to %02x hex\n",r);
+	r = 0;
+	if (wc->txgain[qrvcard] < 2400) r |= 1; else r |= 4;
+	if (wc->txgain[qrvcard + 1] < 2400) r |= 8; else r |= 0x20;
+	wctdm_setreg(wc, qrvcard, 0x26, r);
+	if (debug) printk("@@@@@ setting reg 0x26 to %02x hex\n",r);
+	l = ((long)(wc->rxgain[qrvcard] % 1200) * 10000) / 46875;
+	if (l == 0) l = 1;
+	if (wc->rxgain[qrvcard] >= 2400) l += 181;
+	wctdm_setreg(wc, qrvcard, 0x0b, (unsigned char)l);
+	if (debug) printk("@@@@@ setting reg 0x0b to %02x hex\n",(unsigned char)l);
+	l = ((long)(wc->rxgain[qrvcard + 1] % 1200) * 10000) / 46875;
+	if (l == 0) l = 1;
+	if (wc->rxgain[qrvcard + 1] >= 2400) l += 181;
+	wctdm_setreg(wc, qrvcard, 0x0c, (unsigned char)l);
+	if (debug) printk("@@@@@ setting reg 0x0c to %02x hex\n",(unsigned char)l);
+	l = ((long)(wc->txgain[qrvcard] % 1200) * 10000) / 46875;
+	if (l == 0) l = 1;
+	wctdm_setreg(wc, qrvcard, 0x0f, (unsigned char)l);
+	if (debug) printk("@@@@@ setting reg 0x0f to %02x hex\n", (unsigned char)l);
+	l = ((long)(wc->txgain[qrvcard + 1] % 1200) * 10000) / 46875;
+	if (l == 0) l = 1;
+	wctdm_setreg(wc, qrvcard, 0x10,(unsigned char)l);
+	if (debug) printk("@@@@@ setting reg 0x10 to %02x hex\n",(unsigned char)l);
+	return;
+}
 
 static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
 {
@@ -2139,6 +2457,10 @@
 	struct wctdm_echo_coefs echoregs;
 	struct wctdm *wc = chan->pvt;
 	int x;
+	union {
+		struct zt_radio_stat s;
+		struct zt_radio_param p;
+	} stack;
 
 #if 0
 	/* XXX */
@@ -2202,6 +2524,10 @@
 				regs.indirect[x] = wctdm_proslic_getreg_indirect(wc, chan->chanpos -1, x);
 			for (x=0;x<NUM_REGS;x++)
 				regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
+		} else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
+			memset(&regs, 0, sizeof(regs));
+			for (x=0;x<0x32;x++)
+				regs.direct[x] = wctdm_getreg(wc, chan->chanpos - 1, x);
 		} else {
 			memset(&regs, 0, sizeof(regs));
 			for (x=0;x<NUM_FXO_REGS;x++)
@@ -2275,12 +2601,150 @@
 		}
 		return 0;
 #endif
+	case ZT_RADIO_GETPARAM:
+		if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV) 
+			return -ENOTTY;
+		if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+		stack.p.data = 0; /* start with 0 value in output */
+		switch(stack.p.radpar) {
+		case ZT_RADPAR_INVERTCOR:
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_INVERTCOR)
+				stack.p.data = 1;
+			break;
+		case ZT_RADPAR_IGNORECOR:
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_IGNORECOR)
+				stack.p.data = 1;
+			break;
+		case ZT_RADPAR_IGNORECT:
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_IGNORECT)
+				stack.p.data = 1;
+			break;
+		case ZT_RADPAR_EXTRXTONE:
+			stack.p.data = 0;
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_EXTTONE)
+			{
+				stack.p.data = 1;
+				if (wc->radmode[chan->chanpos - 1] & RADMODE_EXTINVERT)
+				{
+					stack.p.data = 2;
+				}
+			}
+			break;
+		case ZT_RADPAR_DEBOUNCETIME:
+			stack.p.data = wc->debouncetime[chan->chanpos - 1];
+			break;
+		case ZT_RADPAR_RXGAIN:
+			stack.p.data = wc->rxgain[chan->chanpos - 1] - 1199;
+			break;
+		case ZT_RADPAR_TXGAIN:
+			stack.p.data = wc->txgain[chan->chanpos - 1] - 3599;
+			break;
+		case ZT_RADPAR_DEEMP:
+			stack.p.data = 0;
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_DEEMP)
+			{
+				stack.p.data = 1;
+			}
+			break;
+		case ZT_RADPAR_PREEMP:
+			stack.p.data = 0;
+			if (wc->radmode[chan->chanpos - 1] & RADMODE_PREEMP)
+			{
+				stack.p.data = 1;
+			}
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (copy_to_user((struct zt_radio_param *)data,&stack.p,sizeof(struct zt_radio_param))) return -EFAULT;
+		break;
+	case ZT_RADIO_SETPARAM:
+		if (wc->modtype[chan->chanpos - 1] != MOD_TYPE_QRV) 
+			return -ENOTTY;
+		if (copy_from_user(&stack.p,(struct zt_radio_param *)data,sizeof(struct zt_radio_param))) return -EFAULT;
+		switch(stack.p.radpar) {
+		case ZT_RADPAR_INVERTCOR:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_INVERTCOR;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_INVERTCOR;
+			return 0;
+		case ZT_RADPAR_IGNORECOR:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_IGNORECOR;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECOR;
+			return 0;
+		case ZT_RADPAR_IGNORECT:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_IGNORECT;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_IGNORECT;
+			return 0;
+		case ZT_RADPAR_EXTRXTONE:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_EXTTONE;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_EXTTONE;
+			if (stack.p.data > 1)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_EXTINVERT;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_EXTINVERT;
+			return 0;
+		case ZT_RADPAR_DEBOUNCETIME:
+			wc->debouncetime[chan->chanpos - 1] = stack.p.data;
+			return 0;
+		case ZT_RADPAR_RXGAIN:
+			/* if out of range */
+			if ((stack.p.data <= -1200) || (stack.p.data > 1552))
+			{
+				return -EINVAL;
+			}
+			wc->rxgain[chan->chanpos - 1] = stack.p.data + 1199;
+			break;
+		case ZT_RADPAR_TXGAIN:
+			/* if out of range */
+			if (wc->radmode[chan->chanpos -1] & RADMODE_PREEMP)
+			{
+				if ((stack.p.data <= -2400) || (stack.p.data > 0))
+				{
+					return -EINVAL;
+				}
+			}
+			else
+			{
+				if ((stack.p.data <= -3600) || (stack.p.data > 1200))
+				{
+					return -EINVAL;
+				}
+			}
+			wc->txgain[chan->chanpos - 1] = stack.p.data + 3599;
+			break;
+		case ZT_RADPAR_DEEMP:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_DEEMP;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_DEEMP;
+			wc->rxgain[chan->chanpos - 1] = 1199;
+			break;
+		case ZT_RADPAR_PREEMP:
+			if (stack.p.data)
+				wc->radmode[chan->chanpos - 1] |= RADMODE_PREEMP;
+			else
+				wc->radmode[chan->chanpos - 1] &= ~RADMODE_PREEMP;
+			wc->txgain[chan->chanpos - 1] = 3599;
+			break;
+		default:
+			return -EINVAL;
+		}
+		qrv_dosetup(chan,wc);
+		return 0;				
 	default:
 		return -ENOTTY;
 	}
 	return 0;
-
-}
+}
+
 static int wctdm_open(struct zt_chan *chan)
 {
 	struct wctdm *wc = chan->pvt;
@@ -2308,6 +2772,7 @@
 {
 	struct wctdm *wc = chan->pvt;
 	int x;
+	signed char reg;
 	wc->usecount--;
 #ifndef LINUX26
 	MOD_DEC_USE_COUNT;
@@ -2317,6 +2782,23 @@
 	for (x=0;x<wc->cards;x++) {
 		if (wc->modtype[x] == MOD_TYPE_FXS)
 			wc->mods[x].fxs.idletxhookstate = 1;
+		if (wc->modtype[x] == MOD_TYPE_QRV)
+		{
+			int qrvcard = x & 0xfc;
+
+			wc->qrvhook[x] = 0;
+			wc->qrvhook[x + 2] = 0xff;
+			wc->debouncetime[x] = QRV_DEBOUNCETIME;
+			wc->qrvdebtime[x] = 0;
+			wc->radmode[x] = 0;
+			wc->txgain[x] = 3599;
+			wc->rxgain[x] = 1199;
+			reg = 0;
+			if (!wc->qrvhook[qrvcard]) reg |= 1;
+			if (!wc->qrvhook[qrvcard + 1]) reg |= 0x10;
+			wc->sethook[qrvcard] = CMD_WR(3, reg);
+			qrv_dosetup(chan,wc);
+		}
 	}
 	/* If we're dead, release us now */
 	if (!wc->usecount && wc->dead) 
@@ -2327,8 +2809,26 @@
 static int wctdm_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
 {
 	struct wctdm *wc = chan->pvt;
-	int reg=0;
-	if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
+	int reg=0,qrvcard;
+	if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_QRV) {
+		qrvcard = (chan->chanpos - 1) & 0xfc;
+		switch(txsig) {
+		case ZT_TXSIG_START:
+		case ZT_TXSIG_OFFHOOK:
+			wc->qrvhook[chan->chanpos - 1] = 1;
+			break;
+		case ZT_TXSIG_ONHOOK:
+			wc->qrvhook[chan->chanpos - 1] = 0;
+			break;
+		default:
+			printk("wctdm24xxp: Can't set tx state to %d\n", txsig);
+		}
+		reg = 0;
+		if (!wc->qrvhook[qrvcard]) reg |= 1;
+		if (!wc->qrvhook[qrvcard + 1]) reg |= 0x10;
+		wc->sethook[qrvcard] = CMD_WR(3, reg);
+		/* wctdm_setreg(wc, qrvcard, 3, reg); */
+	} else if (wc->modtype[chan->chanpos - 1] == MOD_TYPE_FXO) {
 		switch(txsig) {
 		case ZT_TXSIG_START:
 		case ZT_TXSIG_OFFHOOK:
@@ -2387,6 +2887,102 @@
 	return 0;
 }
 
+static void wctdm_dacs_connect(struct wctdm *wc, int srccard, int dstcard)
+{
+
+	if (wc->dacssrc[dstcard] > - 1) {
+		printk("wctdm_dacs_connect: Can't have double sourcing yet!\n");
+		return;
+	}
+	if (!((wc->modtype[srccard] == MOD_TYPE_FXS)||(wc->modtype[srccard] == MOD_TYPE_FXO))){
+		printk("wctdm_dacs_connect: Unsupported modtype for card %d\n", srccard);
+		return;
+	}
+	if (!((wc->modtype[dstcard] == MOD_TYPE_FXS)||(wc->modtype[dstcard] == MOD_TYPE_FXO))){
+		printk("wctdm_dacs_connect: Unsupported modtype for card %d\n", dstcard);
+		return;
+	}
+	if (debug)
+		printk("connect %d => %d\n", srccard, dstcard);
+	wc->dacssrc[dstcard] = srccard;
+
+	/* make srccard transmit to srccard+24 on the TDM bus */
+	if (wc->modtype[srccard] == MOD_TYPE_FXS) {
+		/* proslic */
+		wctdm_setreg(wc, srccard, PCM_XMIT_START_COUNT_LSB, ((srccard+24) * 8) & 0xff); 
+		wctdm_setreg(wc, srccard, PCM_XMIT_START_COUNT_MSB, ((srccard+24) * 8) >> 8);
+	} else if(wc->modtype[srccard] == MOD_TYPE_FXO) { 
+		/* daa */
+		wctdm_setreg(wc, srccard, 34, ((srccard+24) * 8) & 0xff); /* TX */
+		wctdm_setreg(wc, srccard, 35, ((srccard+24) * 8) >> 8);   /* TX */
+	}
+
+	/* have dstcard receive from srccard+24 on the TDM bus */
+	if (wc->modtype[dstcard] == MOD_TYPE_FXS) {
+		/* proslic */
+    	wctdm_setreg(wc, dstcard, PCM_RCV_START_COUNT_LSB,  ((srccard+24) * 8) & 0xff);
+		wctdm_setreg(wc, dstcard, PCM_RCV_START_COUNT_MSB,  ((srccard+24) * 8) >> 8);
+	} else if(wc->modtype[dstcard] == MOD_TYPE_FXO) {
+		/* daa */
+		wctdm_setreg(wc, dstcard, 36, ((srccard+24) * 8) & 0xff); /* RX */
+		wctdm_setreg(wc, dstcard, 37, ((srccard+24) * 8) >> 8);   /* RX */
+	}
+
+}
+
+static void wctdm_dacs_disconnect(struct wctdm *wc, int card)
+{
+	if (wc->dacssrc[card] > -1) {
+		if (debug)
+			printk("wctdm_dacs_disconnect: restoring TX for %d and RX for %d\n",wc->dacssrc[card], card);
+
+		/* restore TX (source card) */
+		if(wc->modtype[wc->dacssrc[card]] == MOD_TYPE_FXS){
+			wctdm_setreg(wc, wc->dacssrc[card], PCM_XMIT_START_COUNT_LSB, (wc->dacssrc[card] * 8) & 0xff);
+			wctdm_setreg(wc, wc->dacssrc[card], PCM_XMIT_START_COUNT_MSB, (wc->dacssrc[card] * 8) >> 8);
+		} else if(wc->modtype[wc->dacssrc[card]] == MOD_TYPE_FXO){
+			wctdm_setreg(wc, card, 34, (card * 8) & 0xff);
+			wctdm_setreg(wc, card, 35, (card * 8) >> 8);
+		} else {
+			printk("WARNING: wctdm_dacs_disconnect() called on unsupported modtype\n");
+		}
+
+		/* restore RX (this card) */
+		if(wc->modtype[card] == MOD_TYPE_FXS){
+	   		wctdm_setreg(wc, card, PCM_RCV_START_COUNT_LSB, (card * 8) & 0xff);
+	    	wctdm_setreg(wc, card, PCM_RCV_START_COUNT_MSB, (card * 8) >> 8);
+		} else if(wc->modtype[card] == MOD_TYPE_FXO){
+			wctdm_setreg(wc, card, 36, (card * 8) & 0xff);
+			wctdm_setreg(wc, card, 37, (card * 8) >> 8);
+		} else {
+			printk("WARNING: wctdm_dacs_disconnect() called on unsupported modtype\n");
+		}
+
+		wc->dacssrc[card] = -1;
+	}
+}
+
+static int wctdm_dacs(struct zt_chan *dst, struct zt_chan *src)
+{
+	struct wctdm *wc;
+
+	if(!nativebridge)
+		return 0; /* should this return -1 since unsuccessful? */
+
+	wc = dst->pvt;
+
+	if(src) {
+		wctdm_dacs_connect(wc, src->chanpos - 1, dst->chanpos - 1);
+		if (debug)
+			printk("dacs connecct: %d -> %d!\n\n", src->chanpos, dst->chanpos);
+	} else {
+		wctdm_dacs_disconnect(wc, dst->chanpos - 1);
+		if (debug)
+			printk("dacs disconnect: %d!\n", dst->chanpos);
+	}
+	return 0;
+}
+
 static int wctdm_initialize(struct wctdm *wc)
 {
 	int x;
@@ -2414,6 +3010,7 @@
 	wc->span.flags = ZT_FLAG_RBS;
 	wc->span.ioctl = wctdm_ioctl;
 	wc->span.watchdog = wctdm_watchdog;
+	wc->span.dacs= wctdm_dacs;
 #ifdef VPM_SUPPORT
 	wc->span.echocan = wctdm_echocan;
 #endif	
@@ -2437,6 +3034,8 @@
 				wc->chans[x].sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF | ZT_SIG_CLEAR;
 			else if (wc->modtype[x] == MOD_TYPE_FXS)
 				wc->chans[x].sigcap = ZT_SIG_FXOKS | ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
+			else if (wc->modtype[x] == MOD_TYPE_QRV)
+				wc->chans[x].sigcap = ZT_SIG_SF | ZT_SIG_EM | ZT_SIG_CLEAR;
 		}
 	}
 }
@@ -3237,7 +3836,7 @@
 			if (debug & DEBUG_CARD) {
 				readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
 				printk("Proslic module %d loop current is %dmA\n",x,
-				((readi*3)+20));
+					((readi*3)+20));
 			}
 			printk("Port %d: Installed -- AUTO FXS/DPO\n", x + 1);
 		} else {
@@ -3249,7 +3848,7 @@
                                 if (debug & DEBUG_CARD) {
                                         readi = wctdm_getreg(wc,x,LOOP_I_LIMIT);
                                         printk("Proslic module %d loop current is %dmA\n",x,
-                                        ((readi*3)+20));
+                                 	       ((readi*3)+20));
                                 }
 					printk("Port %d: Installed -- MANUAL FXS\n",x + 1);
 				} else {
@@ -3258,6 +3857,9 @@
 			} else if (!(ret = wctdm_init_voicedaa(wc, x, 0, 0, sane))) {
 				wc->cardflag |= (1 << x);
 				printk("Port %d: Installed -- AUTO FXO (%s mode)\n",x + 1, fxo_modes[_opermode].name);
+ 			} else if (!wctdm_init_qrvdri(wc,x)) {
+ 				wc->cardflag |= 1 << x;
+ 				printk("Port %d: Installed -- QRV DRI card\n",x + 1);
 			} else {
  				if ((wc->type == 8) && ((x & 0x3) == 1) && !wc->altcs[x]) {
  					spin_lock_irqsave(&wc->reglock, flags);
@@ -3327,8 +3929,10 @@
 			wc->dev = pdev;
 			wc->pos = x;
 			wc->variety = d->name;
-			for (y=0;y<NUM_CARDS;y++)
+			for (y=0;y<NUM_CARDS;y++) {
 				wc->flags[y] = d->flags;
+				wc->dacssrc[y] = -1;
+			}
 			/* Keep track of whether we need to free the region */
 			if (request_region(wc->iobase, 0xff, "wctdm24xxp")) 
 				wc->freeregion = 1;
@@ -3509,6 +4113,7 @@
 {
 	int res;
 	int x;
+
 	for (x=0;x<(sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
 		if (!strcmp(fxo_modes[x].name, opermode))
 			break;
@@ -3549,6 +4154,11 @@
 module_param(battdebounce, int, 0600);
 module_param(battthresh, int, 0600);
 module_param(alawoverride, int, 0600);
+module_param(nativebridge, int, 0600);
+module_param(fxotxgain, int, 0600);
+module_param(fxorxgain, int, 0600);
+module_param(fxstxgain, int, 0600);
+module_param(fxsrxgain, int, 0600);
 #ifdef VPM_SUPPORT
 module_param(vpmsupport, int, 0600);
 module_param(vpmdtmfsupport, int, 0600);
@@ -3567,6 +4177,11 @@
 MODULE_PARM(battdebounce, "i");
 MODULE_PARM(battthresh, "i");
 MODULE_PARM(alawoverride, "i");
+MODULE_PARM(nativebridge, "i");
+MODULE_PARM(fxotxgain, "i");
+MODULE_PARM(fxorxgain, "i");
+MODULE_PARM(fxstxgain, "i");
+MODULE_PARM(fxsrxgain, "i");
 #ifdef VPM_SUPPORT
 MODULE_PARM(vpmsupport, "i");
 MODULE_PARM(vpmdtmfsupport, "i");

Copied: branches/1.4/wctdm24xxp/wctdm24xxp.h (from r2761, branches/1.2/wctdm24xxp/wctdm24xxp.h)
URL: http://svn.digium.com/view/zaptel/branches/1.4/wctdm24xxp/wctdm24xxp.h?view=diff&rev=2762&p1=branches/1.2/wctdm24xxp/wctdm24xxp.h&r1=2761&p2=branches/1.4/wctdm24xxp/wctdm24xxp.h&r2=2762
==============================================================================
--- branches/1.2/wctdm24xxp/wctdm24xxp.h (original)
+++ branches/1.4/wctdm24xxp/wctdm24xxp.h Fri Jul 20 13:54:20 2007
@@ -29,7 +29,8 @@
 #define MOD_TYPE_FXO		2
 #define MOD_TYPE_FXSINIT	3	
 #define MOD_TYPE_VPM		4
-#define MOD_TYPE_VPM150M	5
+#define MOD_TYPE_QRV		5
+#define MOD_TYPE_VPM150M	6
 
 #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 */
@@ -61,6 +62,7 @@
 
 #define USER_COMMANDS 8
 #define ISR_COMMANDS  2
+#define	QRV_DEBOUNCETIME 20
 
 #define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS)
 
@@ -154,6 +156,19 @@
 	int cards;
 	int cardflag;		/* Bit-map of present cards */
  	int altcs[NUM_CARDS + NUM_EC];
+	char qrvhook[NUM_CARDS];
+	unsigned short qrvdebtime[NUM_CARDS];
+	int radmode[NUM_CARDS];
+#define	RADMODE_INVERTCOR 1
+#define	RADMODE_IGNORECOR 2
+#define	RADMODE_EXTTONE 4
+#define	RADMODE_EXTINVERT 8
+#define	RADMODE_IGNORECT 16
+#define	RADMODE_PREEMP	32
+#define	RADMODE_DEEMP 64
+	unsigned short debouncetime[NUM_CARDS];
+	signed short rxgain[NUM_CARDS];
+	signed short txgain[NUM_CARDS];
 	spinlock_t reglock;
 	wait_queue_head_t regq;
 	/* FXO Stuff */
@@ -186,6 +201,7 @@
 	int modtype[NUM_CARDS + NUM_EC];
 	/* Set hook */
 	int sethook[NUM_CARDS + NUM_EC];
+ 	int dacssrc[NUM_CARDS];
  	int type;
 
 #ifdef VPM_SUPPORT

Modified: branches/1.4/zaptel-base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/zaptel-base.c?view=diff&rev=2762&r1=2761&r2=2762
==============================================================================
--- branches/1.4/zaptel-base.c (original)
+++ branches/1.4/zaptel-base.c Fri Jul 20 13:54:20 2007
@@ -1049,12 +1049,13 @@
 	memset(chan->conflast1, 0, sizeof(chan->conflast1));
 	memset(chan->conflast2, 0, sizeof(chan->conflast2));
 
+	if (chan->span && chan->span->dacs && oldconf)
+		chan->span->dacs(chan, NULL);
+
+	spin_unlock_irqrestore(&chan->lock, flags);
+
 	if (chan->span && chan->span->echocan)
 		chan->span->echocan(chan, 0);
-	if (chan->span && chan->span->dacs && oldconf)
-		chan->span->dacs(chan, NULL);
-
-	spin_unlock_irqrestore(&chan->lock, flags);
 
 	if (rxgain)
 		kfree(rxgain);
@@ -2279,9 +2280,11 @@
 		chan->ringcadence[0] = chan->starttime;
 		chan->ringcadence[1] = ZT_RINGOFFTIME;
 	}
+
+	spin_unlock_irqrestore(&chan->lock, flags);
+
 	if (chan->span && chan->span->echocan)
 		chan->span->echocan(chan, 0);
-	spin_unlock_irqrestore(&chan->lock, flags);
 
 	if (rxgain)
 		kfree(rxgain);
@@ -4283,9 +4286,10 @@
 			chan->txgain = defgain;
 			chan->gainalloc = 0;
 			/* Disable any native echo cancellation as well */
+			spin_unlock_irqrestore(&chan->lock, flags);
+
 			if (chan->span && chan->span->echocan)
 				chan->span->echocan(chan, 0);
-			spin_unlock_irqrestore(&chan->lock, flags);
 
 			if (rxgain)
 				kfree(rxgain);
@@ -4389,10 +4393,13 @@
 			tec = chan->ec;
 			chan->ec = NULL;
 			/* Attempt hardware native echo can */
+			spin_unlock_irqrestore(&chan->lock, flags);
+
 			if (chan->span && chan->span->echocan)
 				ret = chan->span->echocan(chan, j);
 			else
 				ret = -ENOTTY;
+
 			if (ret) {
 				/* Use built-in echo can */
 				if ((j == 32) ||
@@ -4405,7 +4412,6 @@
 				} else {
 					j = deftaps;
 				}
-				spin_unlock_irqrestore(&chan->lock, flags);
 				ec = echo_can_create(j, 0);
 				if (!ec)
 					return -ENOMEM;
@@ -4417,8 +4423,8 @@
 				chan->echotimer = 0;
 				echo_can_disable_detector_init(&chan->txecdis);
 				echo_can_disable_detector_init(&chan->rxecdis);
-			}
-			spin_unlock_irqrestore(&chan->lock, flags);
+				spin_unlock_irqrestore(&chan->lock, flags);
+			}
 			if (tec)
 				echo_can_free(tec);
 		} else {
@@ -4429,10 +4435,10 @@
 			chan->echostate = ECHO_STATE_IDLE;
 			chan->echolastupdate = 0;
 			chan->echotimer = 0;
+			spin_unlock_irqrestore(&chan->lock, flags);
 			/* Attempt hardware native echo can */
 			if (chan->span && chan->span->echocan)
 				chan->span->echocan(chan, 0);
-			spin_unlock_irqrestore(&chan->lock, flags);
 			if (tec)
 				echo_can_free(tec);
 		}




More information about the svn-commits mailing list