[dahdi-commits] kpfleming: branch linux/kpfleming/modular_ec r4423 - in /linux/team/kpfleming...

SVN commits to the DAHDI project dahdi-commits at lists.digium.com
Thu Jun 19 18:02:38 CDT 2008


Author: kpfleming
Date: Thu Jun 19 18:02:37 2008
New Revision: 4423

URL: http://svn.digium.com/view/dahdi?view=rev&rev=4423
Log:
it is now possible to attach (and detach) a modular echo canceler to a channel... tomorrow i will teach dahdi_cfg how to actually do it!

Modified:
    linux/team/kpfleming/modular_ec/drivers/dahdi/dahdi-base.c
    linux/team/kpfleming/modular_ec/include/dahdi/kernel.h

Modified: linux/team/kpfleming/modular_ec/drivers/dahdi/dahdi-base.c
URL: http://svn.digium.com/view/dahdi/linux/team/kpfleming/modular_ec/drivers/dahdi/dahdi-base.c?view=diff&rev=4423&r1=4422&r2=4423
==============================================================================
--- linux/team/kpfleming/modular_ec/drivers/dahdi/dahdi-base.c (original)
+++ linux/team/kpfleming/modular_ec/drivers/dahdi/dahdi-base.c Thu Jun 19 18:02:37 2008
@@ -61,6 +61,8 @@
 #endif
 
 #include <asm/atomic.h>
+
+#define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args)
 
 #ifndef CONFIG_OLD_HDLC_API
 #define NEW_HDLC_INTERFACE
@@ -978,11 +980,67 @@
 	return ret;
 }
 
+static const struct dahdi_echocan *find_echocan(const char *name)
+{
+	struct echocan *cur;
+	char name_upper[strlen(name) + 1];
+	char *c;
+	const char *d;
+	char modname_buf[128] = "dahdi_echocan_";
+	unsigned int tried_once = 0;
+
+	for (c = name_upper, d = name; *d; c++, d++) {
+		*c = toupper(*d);
+	}
+
+	*c = '\0';
+
+retry:
+	read_lock(&echocan_list_lock);
+
+	list_for_each_entry(cur, &echocan_list, list) {
+		if (!strcmp(name_upper, cur->ec->name)) {
+			if (try_module_get(cur->owner)) {
+				read_unlock(&echocan_list_lock);
+				return cur->ec;
+			} else {
+				read_unlock(&echocan_list_lock);
+				return NULL;
+			}
+		}
+	}
+
+	read_unlock(&echocan_list_lock);
+
+	if (tried_once) {
+		return NULL;
+	}
+
+	/* couldn't find it, let's try to load it */
+
+	for (c = &modname_buf[strlen(modname_buf)], d = name; *d; c++, d++) {
+		*c = tolower(*d);
+	}
+
+	request_module(modname_buf);
+
+	tried_once = 1;
+
+	/* and try one more time */
+	goto retry;
+}
+
+static void release_echocan(const struct dahdi_echocan *ec)
+{
+	module_put(ec->owner);
+}
+
 static void close_channel(struct dahdi_chan *chan)
 {
 	unsigned long flags;
 	void *rxgain = NULL;
-	struct echo_can_state *ec = NULL;
+	struct echo_can_state *ec_state;
+	const struct dahdi_echocan *ec_current;
 	int oldconf;
 	short *readchunkpreec;
 #ifdef CONFIG_DAHDI_PPP
@@ -997,8 +1055,10 @@
 	ppp = chan->ppp;
 	chan->ppp = NULL;
 #endif
-	ec = chan->ec_state;
+	ec_state = chan->ec_state;
 	chan->ec_state = NULL;
+	ec_current = chan->ec_current;
+	chan->ec_current = NULL;
 	readchunkpreec = chan->readchunkpreec;
 	chan->readchunkpreec = NULL;
 	chan->curtone = NULL;
@@ -1055,8 +1115,10 @@
 	if (chan->span && chan->span->dacs && oldconf)
 		chan->span->dacs(chan, NULL);
 
-	if (ec)
-		chan->ec->echo_can_free(ec);
+	if (ec_state) {
+		ec_current->echo_can_free(ec_state);
+		release_echocan(ec_current);
+	}
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 
@@ -2151,7 +2213,9 @@
 	int res;
 	unsigned long flags;
 	void *rxgain=NULL;
-	struct echo_can_state *ec=NULL;
+	struct echo_can_state *ec_state;
+	const struct dahdi_echocan *ec_current;
+
 	if ((res = dahdi_reallocbufs(chan, DAHDI_DEFAULT_BLOCKSIZE, DAHDI_DEFAULT_NUM_BUFS)))
 		return res;
 
@@ -2160,9 +2224,10 @@
 	chan->rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
 	chan->txbufpolicy = DAHDI_POLICY_IMMEDIATE;
 
-	/* Free up the echo canceller if there is one */
-	ec = chan->ec_state;
+	ec_state = chan->ec_state;
 	chan->ec_state = NULL;
+	ec_current = chan->ec_current;
+	chan->ec_current = NULL;
 	chan->echocancel = 0;
 	chan->echostate = ECHO_STATE_IDLE;
 	chan->echolastupdate = 0;
@@ -2259,8 +2324,10 @@
 		chan->ringcadence[1] = DAHDI_RINGOFFTIME;
 	}
 
-	if (ec)
-		chan->ec->echo_can_free(ec);
+	if (ec_state) {
+		ec_current->echo_can_free(ec_state);
+		release_echocan(ec_current);
+	}
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 
@@ -3476,61 +3543,6 @@
 #endif
 }
 
-static const struct dahdi_echocan *find_echocan(const char *name)
-{
-	struct echocan *cur;
-	char name_upper[strlen(name) + 1];
-	char *c;
-	const char *d;
-	char modname_buf[128] = "dahdi_echocan_";
-	unsigned int tried_once = 0;
-
-	for (c = name_upper, d = name; *d; c++, d++) {
-		*c = toupper(*d);
-	}
-
-	*c = '\0';
-
-retry:
-	read_lock(&echocan_list_lock);
-
-	list_for_each_entry(cur, &echocan_list, list) {
-		if (!strcmp(name_upper, cur->ec->name)) {
-			if (try_module_get(cur->owner)) {
-				read_unlock(&echocan_list_lock);
-				return cur->ec;
-			} else {
-				read_unlock(&echocan_list_lock);
-				return NULL;
-			}
-		}
-	}
-
-	read_unlock(&echocan_list_lock);
-
-	if (tried_once) {
-		return NULL;
-	}
-
-	/* couldn't find it, let's try to load it */
-
-	for (c = &modname_buf[strlen(modname_buf)], d = name; *d; c++, d++) {
-		*c = tolower(*d);
-	}
-
-	request_module(modname_buf);
-
-	tried_once = 1;
-
-	/* and try one more time */
-	goto retry;
-}
-
-static void release_echocan(const struct dahdi_echocan *ec)
-{
-	module_put(ec->owner);
-}
-
 static int dahdi_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
 {
 	/* I/O CTL's for control interface */
@@ -3598,7 +3610,6 @@
 	case DAHDI_CHANCONFIG:
 	{
 		struct dahdi_chanconfig ch;
-		struct dahdi_echocan *new_ec, *old_ec;
 
 		if (copy_from_user(&ch, (struct dahdi_chanconfig *)data, sizeof(ch)))
 			return -EFAULT;
@@ -4557,7 +4568,8 @@
 
 static int ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, void *data)
 {
-	struct echo_can_state *ec = NULL, *tec;
+	struct echo_can_state *ec = NULL, *ec_state;
+	const struct dahdi_echocan *ec_current;
 	struct dahdi_echocanparam *params;
 	int ret;
 	unsigned long flags;
@@ -4568,15 +4580,19 @@
 	if (ecp->tap_length == 0) {
 		/* disable mode, don't need to inspect params */
 		spin_lock_irqsave(&chan->lock, flags);
-		tec = chan->ec_state;
+		ec_state = chan->ec_state;
 		chan->ec_state = NULL;
+		ec_current = chan->ec_current;
+		chan->ec_current = NULL;
 		chan->echocancel = 0;
 		chan->echostate = ECHO_STATE_IDLE;
 		chan->echolastupdate = 0;
 		chan->echotimer = 0;
-		if (tec)
-			chan->ec->echo_can_free(tec);
 		spin_unlock_irqrestore(&chan->lock, flags);
+		if (ec_state) {
+			ec_current->echo_can_free(ec_state);
+			release_echocan(ec_current);
+		}
 		hw_echocancel_off(chan);
 
 		return 0;
@@ -4601,11 +4617,15 @@
 	}
 	
 	spin_lock_irqsave(&chan->lock, flags);
-	tec = chan->ec_state;
+	ec_state = chan->ec_state;
 	chan->ec_state = NULL;
-	if (tec)
-		chan->ec->echo_can_free(tec);
+	ec_current = chan->ec_current;
+	chan->ec_current = NULL;
 	spin_unlock_irqrestore(&chan->lock, flags);
+	if (ec_state) {
+		ec_current->echo_can_free(ec_state);
+		release_echocan(ec_current);
+	}
 	
 	ret = -ENODEV;
 	
@@ -4619,6 +4639,8 @@
 	}
 	
 	if (ret == -ENODEV) {
+		const struct dahdi_echocan *ec_current;
+
 		switch (ecp->tap_length) {
 		case 32:
 		case 64:
@@ -4631,11 +4653,26 @@
 			ecp->tap_length = deftaps;
 		}
 		
-		if ((ret = chan->ec->echo_can_create(ecp, params, &ec)))
+		/* try to get another reference to the module providing
+		   this channel's echo canceler */
+		if (!try_module_get(chan->ec_factory->owner)) {
+			module_printk(KERN_ERR, "Cannot get a reference to the '%s' echo canceler\n", chan->ec_factory->name);
 			goto exit_with_free;
+		}
+
+		/* got the reference, copy the pointer and use it for making
+		   an echo canceler instance if possible */
+		ec_current = chan->ec_current;
+
+		if ((ret = ec_current->echo_can_create(ecp, params, &ec))) {
+			release_echocan(ec_current);
+
+			goto exit_with_free;
+		}
 		
 		spin_lock_irqsave(&chan->lock, flags);
 		chan->echocancel = ecp->tap_length;
+		chan->ec_current = ec_current;
 		chan->ec_state = ec;
 		chan->echostate = ECHO_STATE_IDLE;
 		chan->echolastupdate = 0;
@@ -4647,6 +4684,7 @@
 
 exit_with_free:
 	kfree(params);
+
 	return ret;
 }
 
@@ -4658,7 +4696,6 @@
 	int ret;
 	int oldconf;
 	void *rxgain=NULL;
-	struct echo_can_state *ec;
 
 	if (!chan)
 		return -ENOSYS;
@@ -4696,6 +4733,9 @@
 			/* Coming out of audio mode, also clear all 
 			   conferencing and gain related info as well
 			   as echo canceller */
+			struct echo_can_state *ec_state;
+			const struct dahdi_echocan *ec_current;
+
 			spin_lock_irqsave(&chan->lock, flags);
 			chan->flags &= ~DAHDI_FLAG_AUDIO;
 			/* save old conf number, if any */
@@ -4710,8 +4750,10 @@
 			memset(chan->conflast, 0, sizeof(chan->conflast));
 			memset(chan->conflast1, 0, sizeof(chan->conflast1));
 			memset(chan->conflast2, 0, sizeof(chan->conflast2));
-			ec = chan->ec_state;
+			ec_state = chan->ec_state;
 			chan->ec_state = NULL;
+			ec_current = chan->ec_current;
+			chan->ec_current = NULL;
 			/* release conference resource, if any to release */
 			reset_conf(chan);
 			if (chan->gainalloc && chan->rxgain)
@@ -4722,9 +4764,12 @@
 			chan->rxgain = defgain;
 			chan->txgain = defgain;
 			chan->gainalloc = 0;
-			if (ec)
-				chan->ec->echo_can_free(ec);
 			spin_unlock_irqrestore(&chan->lock, flags);
+
+			if (ec_state) {
+				ec_current->echo_can_free(ec_state);
+				release_echocan(ec_current);
+			}
 
 			/* Disable any native echo cancellation as well */
 			hw_echocancel_off(chan);
@@ -4820,6 +4865,38 @@
 			fasthdlc_init(&chan->txhdlc);
 		}
 		break;
+	case DAHDI_ATTACH_ECHOCAN:
+	{
+		struct dahdi_attach_echocan ae;
+		const struct dahdi_echocan *new = NULL, *old;
+
+		if (!(chan->flags & DAHDI_FLAG_AUDIO)) {
+			return -EINVAL;
+		}
+
+		if (copy_from_user(&ae, (struct dahdi_attach_echocan *) data, sizeof(ae))) {
+			return -EFAULT;
+		}
+
+		VALID_CHANNEL(ae.chan);
+
+		if (ae.echocan[0]) {
+			if (!(new = find_echocan(ae.echocan))) {
+				return -EINVAL;
+			}
+		}
+
+		spin_lock_irqsave(&chan->lock, flags);
+		old = chan->ec_factory;
+		chan->ec_factory = new;
+		spin_unlock_irqrestore(&chan->lock, flags);
+
+		if (old) {
+			release_echocan(old);
+		}
+
+		break;
+	}
 	case DAHDI_ECHOCANCEL_PARAMS:
 	{
 		struct dahdi_echocanparams ecp;
@@ -5378,8 +5455,10 @@
 				ms->echostate = ECHO_STATE_IDLE;
 				ms->echolastupdate = 0;
 				ms->echotimer = 0;
-				ms->ec->echo_can_free(ms->ec_state);
+				ms->ec_current->echo_can_free(ms->ec_state);
 				ms->ec_state = NULL;
+				release_echocan(ms->ec_current);
+				ms->ec_current = NULL;
 				__qevent(ss, DAHDI_EVENT_EC_DISABLED);
 				break;
 			}
@@ -6204,7 +6283,7 @@
 					ss->echostate = ECHO_STATE_TRAINING;
 				}
 				if (ss->echostate == ECHO_STATE_TRAINING) {
-					if (ss->ec->echo_can_traintap(ss->ec_state, ss->echolastupdate++, rxlin)) {
+					if (ss->ec_current->echo_can_traintap(ss->ec_state, ss->echolastupdate++, rxlin)) {
 #if 0
 						printk("Finished training (%d taps trained)!\n", ss->echolastupdate);
 #endif						
@@ -6220,7 +6299,7 @@
 				rxlins[x] = DAHDI_XLAW(rxchunk[x], ss);
 				txlins[x] = DAHDI_XLAW(txchunk[x], ss);
 			}
-			ss->ec->echo_can_array_update(ss->ec_state, rxlins, txlins);
+			ss->ec_current->echo_can_array_update(ss->ec_state, rxlins, txlins);
 			for (x = 0; x < DAHDI_CHUNKSIZE; x++)
 				rxchunk[x] = DAHDI_LIN2X((int) rxlins[x], ss);
 		}
@@ -6240,7 +6319,7 @@
 {
 	int x;
 	for (x = 0; x < span->channels; x++) {
-		if (span->chans[x].ec)
+		if (span->chans[x].ec_current)
 			__dahdi_ec_chunk(&span->chans[x], span->chans[x].readchunk, span->chans[x].writechunk);
 	}
 }
@@ -6324,8 +6403,10 @@
 				ms->echostate = ECHO_STATE_IDLE;
 				ms->echolastupdate = 0;
 				ms->echotimer = 0;
-				ms->ec->echo_can_free(ms->ec_state);
+				ms->ec_current->echo_can_free(ms->ec_state);
 				ms->ec_state = NULL;
+				release_echocan(ms->ec_current);
+				ms->ec_current = NULL;
 				break;
 			}
 		}

Modified: linux/team/kpfleming/modular_ec/include/dahdi/kernel.h
URL: http://svn.digium.com/view/dahdi/linux/team/kpfleming/modular_ec/include/dahdi/kernel.h?view=diff&rev=4423&r1=4422&r2=4423
==============================================================================
--- linux/team/kpfleming/modular_ec/include/dahdi/kernel.h (original)
+++ linux/team/kpfleming/modular_ec/include/dahdi/kernel.h Thu Jun 19 18:02:37 2008
@@ -259,7 +259,6 @@
 int	idlebits;	/* Idle bits (if this is a CAS channel) or
 			   channel to monitor (if this is DACS channel) */
 char	netdev_name[16];/* name for the hdlc network device*/
-char	echocan[16];	/* echo canceler to use on this channel */
 } DAHDI_CHANCONFIG;
 
 typedef struct dahdi_sfconfig
@@ -329,11 +328,16 @@
 	char echo_canceller[80];
 };
 
-struct dahdi_hwgain{
+struct dahdi_hwgain {
 	__s32 newgain;	/* desired gain in dB but x10.  -3.5dB would be -35 */
 	__u32 tx:1;	/* 0=rx; 1=tx */
 };
 
+struct dahdi_attach_echocan {
+	int	chan;		/* Channel we're applying this to */
+	char	echocan[16];	/* Name of echo canceler to attach to this channel
+				   (leave empty to have no echocan attached */
+};
 
 /* ioctl definitions */
 #define DAHDI_CODE	0xDA
@@ -644,6 +648,13 @@
  * transmitted back on the interface)
  */
 #define DAHDI_LOOPBACK _IOW(DAHDI_CODE, 58, int)
+
+/*
+  Attach the desired echo canceler module (or none) to a channel in an
+  audio-supporting mode, so that when the channel needs an echo canceler
+  that module will be used to supply one.
+ */
+#define DAHDI_ATTACH_ECHOCAN _IOW(DAHDI_CODE, 59, struct dahdi_attach_echocan)
 
 
 /*
@@ -1349,7 +1360,13 @@
 
 	/* Is echo cancellation enabled or disabled */
 	int		echocancel;
-	struct dahdi_echocan *ec;
+	/* The echo canceler module that should be used to create an
+	   instance when this channel needs one */
+	const struct dahdi_echocan *ec_factory;
+	/* The echo canceler module that owns the instance currently
+	   on this channel, if one is present */
+	const struct dahdi_echocan *ec_current;
+	/* The private state data of the echo canceler instance in use */
 	struct echo_can_state *ec_state;
 	echo_can_disable_detector_state_t txecdis;
 	echo_can_disable_detector_state_t rxecdis;




More information about the dahdi-commits mailing list