[zaptel-commits] trunk r1108 - in /trunk: pciradio.c wctdm24xxp.c zaptel.h ztcfg.c

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Wed Jun 7 20:13:27 MST 2006


Author: jdixon
Date: Wed Jun  7 22:13:26 2006
New Revision: 1108

URL: http://svn.digium.com/view/zaptel?rev=1108&view=rev
Log:
Added support for QRV radio daughterboard (in wctdm24xxp) and fixed compile
warning in pciradio.

Modified:
    trunk/pciradio.c
    trunk/wctdm24xxp.c
    trunk/zaptel.h
    trunk/ztcfg.c

Modified: trunk/pciradio.c
URL: http://svn.digium.com/view/zaptel/trunk/pciradio.c?rev=1108&r1=1107&r2=1108&view=diff
==============================================================================
--- trunk/pciradio.c (original)
+++ trunk/pciradio.c Wed Jun  7 22:13:26 2006
@@ -541,6 +541,7 @@
 	if ((rad->encdec.lastcmd + 2) > jiffies) return;
 	if (__pciradio_getcreg(rad,0xc) & 1) return;
 	n = 0;
+	byte2 = 0;
 	switch(rad->encdec.state)
 	{
 	    case 0:

Modified: trunk/wctdm24xxp.c
URL: http://svn.digium.com/view/zaptel/trunk/wctdm24xxp.c?rev=1108&r1=1107&r2=1108&view=diff
==============================================================================
--- trunk/wctdm24xxp.c (original)
+++ trunk/wctdm24xxp.c Wed Jun  7 22:13:26 2006
@@ -2,9 +2,11 @@
  * Wilcard TDM2400P TDM FXS/FXO Interface Driver for Zapata Telephony interface
  *
  * Written by Mark Spencer <markster at digium.com>
+ * Copyright (C) 2005,2006, Digium, Inc.
+ * All rights reserved.
  *
- * Copyright (C) 2005, 2006, Digium, Inc.
- *
+ * 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
@@ -22,6 +24,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/kernel.h>
 #include <linux/errno.h>
@@ -263,6 +272,7 @@
 #define MOD_TYPE_FXO		2
 #define MOD_TYPE_FXSINIT	3	
 #define MOD_TYPE_VPM		4
+#define MOD_TYPE_QRV		5
 
 #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 */
@@ -279,6 +289,7 @@
 
 #define USER_COMMANDS 8
 #define ISR_COMMANDS  2
+#define	QRV_DEBOUNCETIME 20
 
 #define MAX_COMMANDS (USER_COMMANDS + ISR_COMMANDS)
 
@@ -326,6 +337,19 @@
 	unsigned char ctlreg;
 	int cards;
 	int cardflag;		/* Bit-map of present cards */
+	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 */
@@ -454,6 +478,11 @@
 	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;
+	}
 	/* Skip audio */
 	writechunk += 24;
 	spin_lock_irqsave(&wc->reglock, flags);
@@ -477,6 +506,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) {
@@ -522,6 +553,22 @@
 		writechunk[CMD_BYTE(card, 1)] = (curcmd >> 8) & 0xff;
 		writechunk[CMD_BYTE(card, 2)] = curcmd & 0xff;
 #endif
+	} else if (wc->modtype[card] == MOD_TYPE_QRV) {
+
+		writechunk[CMD_BYTE(card, 0)] = 0x00;
+		if (!curcmd)
+		{
+			writechunk[CMD_BYTE(card, 1)] = 0x00;
+			writechunk[CMD_BYTE(card, 2)] = 0x00;
+		}
+		else
+		{
+			if (curcmd & __CMD_WR)
+				writechunk[CMD_BYTE(card, 1)] = 0x40 | ((curcmd >> 8) & 0x3f);
+			else
+				writechunk[CMD_BYTE(card, 1)] = 0xc0 | ((curcmd >> 8) & 0x3f);
+			writechunk[CMD_BYTE(card, 2)] = curcmd & 0xff;
+		}
 	} else if (wc->modtype[card] == MOD_TYPE_NONE) {
 		writechunk[CMD_BYTE(card, 0)] = 0x00;
 		writechunk[CMD_BYTE(card, 1)] = 0x00;
@@ -545,6 +592,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);
@@ -588,6 +640,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 */
@@ -603,6 +657,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 */
@@ -686,6 +742,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);
@@ -717,6 +779,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);
@@ -1082,6 +1150,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)
@@ -1311,6 +1433,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) {
@@ -1342,6 +1465,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);
 			}
 		}
 	}
@@ -1751,6 +1876,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);
@@ -1840,6 +1967,8 @@
 	unsigned char r19;
 	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;
@@ -2035,6 +2164,137 @@
 	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)
 {
@@ -2044,6 +2304,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 */
@@ -2107,6 +2371,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++)
@@ -2174,12 +2442,150 @@
 			wc->dtmfmutemask &= ~(1 << (chan->chanpos - 1));
 		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;
@@ -2207,6 +2613,7 @@
 {
 	struct wctdm *wc = chan->pvt;
 	int x;
+	signed char reg;
 	wc->usecount--;
 #ifndef LINUX26
 	MOD_DEC_USE_COUNT;
@@ -2216,6 +2623,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) 
@@ -2226,8 +2650,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:
@@ -2433,6 +2875,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;
 		}
 	}
 }
@@ -2732,7 +3176,7 @@
 			if (debug) {
 				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 {
@@ -2744,7 +3188,7 @@
                                 if (debug) {
                                         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 {
@@ -2753,6 +3197,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 {
 				printk("Port %d: Not installed\n", x + 1);
 				wc->modtype[x] = MOD_TYPE_NONE;
@@ -2955,6 +3402,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;

Modified: trunk/zaptel.h
URL: http://svn.digium.com/view/zaptel/trunk/zaptel.h?rev=1108&r1=1107&r2=1108&view=diff
==============================================================================
--- trunk/zaptel.h (original)
+++ trunk/zaptel.h Wed Jun  7 22:13:26 2006
@@ -1601,5 +1601,12 @@
 
 #define	ZT_RADPAR_REMCOMMAND 17	/* Remote conrtol write data block & do cmd */
 
+#define	ZT_RADPAR_DEEMP 18 /* Audio De-empahsis (on or off) */ 
+
+#define	ZT_RADPAR_PREEMP 19 /* Audio Pre-empahsis (on or off) */ 
+
+#define	ZT_RADPAR_RXGAIN 20 /* Audio (In to system) Rx Gain */ 
+
+#define	ZT_RADPAR_TXGAIN 21 /* Audio (Out from system) Tx Gain */ 
 
 #endif /* _LINUX_ZAPTEL_H */

Modified: trunk/ztcfg.c
URL: http://svn.digium.com/view/zaptel/trunk/ztcfg.c?rev=1108&r1=1107&r2=1108&view=diff
==============================================================================
--- trunk/ztcfg.c (original)
+++ trunk/ztcfg.c Wed Jun  7 22:13:26 2006
@@ -56,6 +56,7 @@
 
 int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
 int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
+int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
 
 int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
 
@@ -177,6 +178,10 @@
 	debouncetime = 0;
 	invertcor = 0;
 	exttone = 0;
+	txgain = 0;
+	rxgain = 0;
+	deemp = 0;
+	preemp = 0;
 }
 
 static int error(char *fmt, ...)
@@ -783,6 +788,86 @@
 	return 0;
 }
 
+int tx_gain(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+	}
+
+	txgain = val;
+	return 0;
+}
+
+int rx_gain(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+	}
+
+	rxgain = val;
+	return 0;
+}
+
+int de_emp(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'de-emp' (should be <value>)\n");
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+	}
+
+	deemp = val;
+	return 0;
+}
+
+int pre_emp(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'pre_emp' (should be <value>)\n");
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+	}
+
+	preemp = val;
+	return 0;
+}
+
 int invert_cor(char *keyword, char *args)
 {
 	static char *realargs[10];
@@ -934,54 +1019,56 @@
 		if (chans[x]) {
 			p.radpar = ZT_RADPAR_NUMTONES;
 			if (ind_ioctl(x,fd,ZT_RADIO_GETPARAM,&p) == -1)
-				error("Cannot get number of tones for channel %d\n",x);
-			n = p.data;
-			p.radpar = ZT_RADPAR_INITTONE;
-			if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-				error("Cannot init tones for channel %d\n",x);
-			if (!rxtones[0]) for(i = 1; i <= n; i++)
+				n = 0; else n = p.data;
+			if (n)
 			{
-				if (rxtones[i])
+				p.radpar = ZT_RADPAR_INITTONE;
+				if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+					error("Cannot init tones for channel %d\n",x);
+				if (!rxtones[0]) for(i = 1; i <= n; i++)
 				{
-					p.radpar = ZT_RADPAR_RXTONE;
-					p.index = i;
-					p.data = rxtones[i];
-					if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-						error("Cannot set rxtone on channel %d\n",x);
-				}
-				if (rxtags[i])
-				{
-					p.radpar = ZT_RADPAR_RXTONECLASS;
-					p.index = i;
-					p.data = rxtags[i];
-					if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-						error("Cannot set rxtag on channel %d\n",x);
-				}
-				if (txtones[i])
+					if (rxtones[i])
+					{
+						p.radpar = ZT_RADPAR_RXTONE;
+						p.index = i;
+						p.data = rxtones[i];
+						if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set rxtone on channel %d\n",x);
+					}
+					if (rxtags[i])
+					{
+						p.radpar = ZT_RADPAR_RXTONECLASS;
+						p.index = i;
+						p.data = rxtags[i];
+						if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set rxtag on channel %d\n",x);
+					}
+					if (txtones[i])
+					{
+						p.radpar = ZT_RADPAR_TXTONE;
+						p.index = i;
+						p.data = txtones[i];
+						if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set txtone on channel %d\n",x);
+					}
+				} else { /* if we may have DCS receive */
+					if (rxtones[0])
+					{
+						p.radpar = ZT_RADPAR_RXTONE;
+						p.index = 0;
+						p.data = rxtones[0];
+						if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set DCS rxtone on channel %d\n",x);
+					}
+				}
+				if (txtones[0])
 				{
 					p.radpar = ZT_RADPAR_TXTONE;
-					p.index = i;
-					p.data = txtones[i];
+					p.index = 0;
+					p.data = txtones[0];
 					if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-						error("Cannot set txtone on channel %d\n",x);
-				}
-			} else { /* if we may have DCS receive */
-				if (rxtones[0])
-				{
-					p.radpar = ZT_RADPAR_RXTONE;
-					p.index = 0;
-					p.data = rxtones[0];
-					if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-						error("Cannot set DCS rxtone on channel %d\n",x);
-				}
-			}
-			if (txtones[0])
-			{
-				p.radpar = ZT_RADPAR_TXTONE;
-				p.index = 0;
-				p.data = txtones[0];
-				if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-					error("Cannot set default txtone on channel %d\n",x);
+						error("Cannot set default txtone on channel %d\n",x);
+				}
 			}
 			if (debouncetime)
 			{
@@ -997,20 +1084,24 @@
 				if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
 					error("Cannot set bursttime on channel %d\n",x);
 			}
-			if (invertcor)
-			{
-				p.radpar = ZT_RADPAR_INVERTCOR;
-				p.data = invertcor;
-				if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-					error("Cannot set invertcor on channel %d\n",x);
-			}
-			if (exttone)
-			{
-				p.radpar = ZT_RADPAR_EXTRXTONE;
-				p.data = exttone;
-				if (ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p) == -1)
-					error("Cannot set exttone on channel %d\n",x);
-			}
+			p.radpar = ZT_RADPAR_DEEMP;
+			p.data = deemp;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+			p.radpar = ZT_RADPAR_PREEMP;
+			p.data = preemp;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+			p.radpar = ZT_RADPAR_TXGAIN;
+			p.data = txgain;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+			p.radpar = ZT_RADPAR_RXGAIN;
+			p.data = rxgain;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+			p.radpar = ZT_RADPAR_INVERTCOR;
+			p.data = invertcor;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
+			p.radpar = ZT_RADPAR_EXTRXTONE;
+			p.data = exttone;
+			ind_ioctl(x,fd,ZT_RADIO_SETPARAM,&p);
 			if (corthresh)
 			{
 				p.radpar = ZT_RADPAR_CORTHRESH;
@@ -1120,6 +1211,10 @@
 	{ "exttone", ext_tone },
 	{ "invertcor", invert_cor },
 	{ "corthresh", cor_thresh },
+	{ "rxgain", rx_gain },
+	{ "txgain", tx_gain },
+	{ "deemp", de_emp },
+	{ "preemp", pre_emp },
 	{ "channel", rad_chanconfig },
 	{ "channels", rad_chanconfig },
 };



More information about the zaptel-commits mailing list