[svn-commits] sruffell: linux/trunk r6529 - in /linux/trunk: drivers/dahdi/ drivers/dahdi/h...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Apr 29 13:24:09 CDT 2009


Author: sruffell
Date: Wed Apr 29 13:24:04 2009
New Revision: 6529

URL: http://svn.digium.com/svn-view/dahdi?view=rev&rev=6529
Log:
echocan: Improve interface for echo cancelers.

Echo cancelers are now able to report if they are able to automatically disable
their NLP portions in the presence of tones in the audio stream.   Also, the
interface is changed to allow user space to just disable the NLP portion of the
echo canceler.  These changes improve fax and modem handling in DAHDI.

This commit merges in the changes on
http://svn.digium.com/svn/dahdi/linux/team/kpfleming/echocan_work

Patch by: kpfleming

Also contains improvements to CED tone detection.
(closes issue #13286)
Reported by: viniciusfontes

Modified:
    linux/trunk/drivers/dahdi/adt_lec.c
    linux/trunk/drivers/dahdi/dahdi-base.c
    linux/trunk/drivers/dahdi/dahdi_echocan_jpah.c
    linux/trunk/drivers/dahdi/dahdi_echocan_kb1.c
    linux/trunk/drivers/dahdi/dahdi_echocan_mg2.c
    linux/trunk/drivers/dahdi/dahdi_echocan_oslec.c
    linux/trunk/drivers/dahdi/dahdi_echocan_sec.c
    linux/trunk/drivers/dahdi/dahdi_echocan_sec2.c
    linux/trunk/drivers/dahdi/ecdis.h
    linux/trunk/drivers/dahdi/hpec/dahdi_echocan_hpec.c
    linux/trunk/drivers/dahdi/hpec/hpec.h
    linux/trunk/drivers/dahdi/voicebus/GpakCust.c
    linux/trunk/drivers/dahdi/voicebus/GpakCust.h
    linux/trunk/drivers/dahdi/wcb4xxp/base.c
    linux/trunk/drivers/dahdi/wcb4xxp/wcb4xxp.h
    linux/trunk/drivers/dahdi/wct4xxp/base.c
    linux/trunk/drivers/dahdi/wctdm24xxp/base.c
    linux/trunk/drivers/dahdi/wctdm24xxp/wctdm24xxp.h
    linux/trunk/drivers/dahdi/wcte12xp/base.c
    linux/trunk/drivers/dahdi/wcte12xp/wcte12xp.h
    linux/trunk/include/dahdi/dahdi_config.h
    linux/trunk/include/dahdi/kernel.h
    linux/trunk/include/dahdi/user.h

Modified: linux/trunk/drivers/dahdi/adt_lec.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/adt_lec.c?view=diff&rev=6529&r1=6528&r2=6529
==============================================================================
--- linux/trunk/drivers/dahdi/adt_lec.c (original)
+++ linux/trunk/drivers/dahdi/adt_lec.c Wed Apr 29 13:24:04 2009
@@ -39,6 +39,8 @@
 	unsigned int x;
 	char *c;
 
+	params->tap_length = ecp->tap_length;
+
 	for (x = 0; x < ecp->param_count; x++) {
 		for (c = p[x].name; *c; c++)
 			*c = tolower(*c);

Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=6529&r1=6528&r2=6529
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Wed Apr 29 13:24:04 2009
@@ -47,21 +47,11 @@
 #include <linux/moduleparam.h>
 #include <linux/list.h>
 
+#include <linux/ppp_defs.h>
+
 #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
-#endif
-
-#define __ECHO_STATE_MUTE			(1 << 8)
-#define ECHO_STATE_IDLE				(0)
-#define ECHO_STATE_PRETRAINING		(1 | (__ECHO_STATE_MUTE))
-#define ECHO_STATE_STARTTRAINING	(2 | (__ECHO_STATE_MUTE))
-#define ECHO_STATE_AWAITINGECHO		(3 | (__ECHO_STATE_MUTE))
-#define ECHO_STATE_TRAINING			(4 | (__ECHO_STATE_MUTE))
-#define ECHO_STATE_ACTIVE			(5)
 
 /* #define BUF_MUNGE */
 
@@ -71,16 +61,18 @@
 #include <dahdi/kernel.h>
 #include "ecdis.h"
 
-#ifdef CONFIG_DAHDI_NET
-#include <linux/netdevice.h>
-#endif /* CONFIG_DAHDI_NET */
-
-#include <linux/ppp_defs.h>
+#ifndef CONFIG_OLD_HDLC_API
+#define NEW_HDLC_INTERFACE
+#endif
 
 #ifdef CONFIG_DAHDI_PPP
 #include <linux/netdevice.h>
 #include <linux/if.h>
 #include <linux/if_ppp.h>
+#endif
+
+#ifdef CONFIG_DAHDI_NET
+#include <linux/netdevice.h>
 #endif
 
 #include "hpec/hpec_user.h"
@@ -143,8 +135,8 @@
 EXPORT_SYMBOL(dahdi_register_chardev);
 EXPORT_SYMBOL(dahdi_unregister_chardev);
 
-EXPORT_SYMBOL(dahdi_register_echocan);
-EXPORT_SYMBOL(dahdi_unregister_echocan);
+EXPORT_SYMBOL(dahdi_register_echocan_factory);
+EXPORT_SYMBOL(dahdi_unregister_echocan_factory);
 
 EXPORT_SYMBOL(dahdi_set_hpec_ioctl);
 
@@ -378,62 +370,62 @@
 #define NUM_SIGS	10
 
 #ifdef DEFINE_RWLOCK
-static DEFINE_RWLOCK(echocan_list_lock);
+static DEFINE_RWLOCK(ecfactory_list_lock);
 #else
-static rwlock_t echocan_list_lock = RW_LOCK_UNLOCKED;
-#endif
-
-static LIST_HEAD(echocan_list);
-
-struct echocan {
-	const struct dahdi_echocan *ec;
+static rwlock_t ecfactory_list_lock = __RW_LOCK_UNLOCKED();
+#endif
+
+static LIST_HEAD(ecfactory_list);
+
+struct ecfactory {
+	const struct dahdi_echocan_factory *ec;
 	struct module *owner;
 	struct list_head list;
 };
 
-int dahdi_register_echocan(const struct dahdi_echocan *ec)
-{
-	struct echocan *cur;
-
-	write_lock(&echocan_list_lock);
+int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec)
+{
+	struct ecfactory *cur;
+
+	write_lock(&ecfactory_list_lock);
 
 	/* make sure it isn't already registered */
-	list_for_each_entry(cur, &echocan_list, list) {
+	list_for_each_entry(cur, &ecfactory_list, list) {
 		if (cur->ec == ec) {
-			write_unlock(&echocan_list_lock);
+			write_unlock(&ecfactory_list_lock);
 			return -EPERM;
 		}
 	}
 
 	if (!(cur = kzalloc(sizeof(*cur), GFP_KERNEL))) {
-		write_unlock(&echocan_list_lock);
+		write_unlock(&ecfactory_list_lock);
 		return -ENOMEM;
 	}
 
 	cur->ec = ec;
 	INIT_LIST_HEAD(&cur->list);
 
-	list_add_tail(&cur->list, &echocan_list);
-
-	write_unlock(&echocan_list_lock);
+	list_add_tail(&cur->list, &ecfactory_list);
+
+	write_unlock(&ecfactory_list_lock);
 
 	return 0;
 }
 
-void dahdi_unregister_echocan(const struct dahdi_echocan *ec)
-{
-	struct echocan *cur, *next;
-
-	write_lock(&echocan_list_lock);
-
-	list_for_each_entry_safe(cur, next, &echocan_list, list) {
+void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec)
+{
+	struct ecfactory *cur, *next;
+
+	write_lock(&ecfactory_list_lock);
+
+	list_for_each_entry_safe(cur, next, &ecfactory_list, list) {
 		if (cur->ec == ec) {
 			list_del(&cur->list);
 			break;
 		}
 	}
 
-	write_unlock(&echocan_list_lock);
+	write_unlock(&ecfactory_list_lock);
 }
 
 static inline void rotate_sums(void)
@@ -663,8 +655,12 @@
 				chan->chan_alarms);
 
 		if (chan->ec_factory)
-			len += snprintf(page+len, count-len, " (EC: %s) ",
+			len += snprintf(page+len, count-len, "(SWEC: %s) ",
 					chan->ec_factory->name);
+
+		if (chan->ec_state)
+			len += snprintf(page+len, count-len, "(EC: %s) ",
+					chan->ec_state->ops->name);
 
 		len += snprintf(page+len, count-len, "\n");
 
@@ -1080,28 +1076,9 @@
 }
 
 
-static inline int hw_echocancel_off(struct dahdi_chan *chan)
-{
-	int ret = 0;
-
-	if (!chan->span)
-		return -ENODEV;
-
-	if (chan->span->echocan) {
-		ret = chan->span->echocan(chan, 0);
-	} else if (chan->span->echocan_with_params) {
-		struct dahdi_echocanparams ecp = {
-			.tap_length = 0,
-		};
-		ret = chan->span->echocan_with_params(chan, &ecp, NULL);
-	}
-
-	return ret;
-}
-
-static const struct dahdi_echocan *find_echocan(const char *name)
-{
-	struct echocan *cur;
+static const struct dahdi_echocan_factory *find_echocan(const char *name)
+{
+	struct ecfactory *cur;
 	char name_upper[strlen(name) + 1];
 	char *c;
 	const char *d;
@@ -1115,26 +1092,26 @@
 	*c = '\0';
 
 retry:
-	read_lock(&echocan_list_lock);
-
-	list_for_each_entry(cur, &echocan_list, list) {
+	read_lock(&ecfactory_list_lock);
+
+	list_for_each_entry(cur, &ecfactory_list, list) {
 		if (!strcmp(name_upper, cur->ec->name)) {
 #ifdef USE_ECHOCAN_REFCOUNT
 			if (try_module_get(cur->owner)) {
-				read_unlock(&echocan_list_lock);
+				read_unlock(&ecfactory_list_lock);
 				return cur->ec;
 			} else {
-				read_unlock(&echocan_list_lock);
+				read_unlock(&ecfactory_list_lock);
 				return NULL;
 			}
 #else
-			read_unlock(&echocan_list_lock);
+			read_unlock(&ecfactory_list_lock);
 			return cur->ec;
 #endif
 		}
 	}
 
-	read_unlock(&echocan_list_lock);
+	read_unlock(&ecfactory_list_lock);
 
 	if (tried_once) {
 		return NULL;
@@ -1154,10 +1131,11 @@
 	goto retry;
 }
 
-static void release_echocan(const struct dahdi_echocan *ec)
+static void release_echocan(const struct dahdi_echocan_factory *ec)
 {
 #ifdef USE_ECHOCAN_REFCOUNT
-	module_put(ec->owner);
+	if (ec)
+		module_put(ec->owner);
 #endif
 }
 
@@ -1173,8 +1151,8 @@
 {
 	unsigned long flags;
 	void *rxgain = NULL;
-	struct echo_can_state *ec_state;
-	const struct dahdi_echocan *ec_current;
+	struct dahdi_echocan_state *ec_state;
+	const struct dahdi_echocan_factory *ec_current;
 	int oldconf;
 	short *readchunkpreec;
 #ifdef CONFIG_DAHDI_PPP
@@ -1252,13 +1230,11 @@
 		chan->span->dacs(chan, NULL);
 
 	if (ec_state) {
-		ec_current->echo_can_free(ec_state);
+		ec_state->ops->echocan_free(chan, ec_state);
 		release_echocan(ec_current);
 	}
 
 	spin_unlock_irqrestore(&chan->lock, flags);
-
-	hw_echocancel_off(chan);
 
 	if (rxgain)
 		kfree(rxgain);
@@ -2449,8 +2425,8 @@
 	int res;
 	unsigned long flags;
 	void *rxgain=NULL;
-	struct echo_can_state *ec_state;
-	const struct dahdi_echocan *ec_current;
+	struct dahdi_echocan_state *ec_state;
+	const struct dahdi_echocan_factory *ec_current;
 
 	if ((res = dahdi_reallocbufs(chan, DAHDI_DEFAULT_BLOCKSIZE, DAHDI_DEFAULT_NUM_BUFS)))
 		return res;
@@ -2464,10 +2440,6 @@
 	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;
 
 	chan->txdisable = 0;
 	chan->rxdisable = 0;
@@ -2562,15 +2534,13 @@
 	}
 
 	if (ec_state) {
-		ec_current->echo_can_free(ec_state);
+		ec_state->ops->echocan_free(chan, ec_state);
 		release_echocan(ec_current);
 	}
 
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	set_tone_zone(chan, -1);
-
-	hw_echocancel_off(chan);
 
 	if (rxgain)
 		kfree(rxgain);
@@ -3437,7 +3407,6 @@
 	struct dahdi_chan *chan;
 	unsigned long flags;
 	unsigned char *txgain, *rxgain;
-	struct dahdi_chan *mychan;
 	int i,j;
 	int return_master = 0;
 	size_t size_to_copy;
@@ -3678,7 +3647,14 @@
 		break;
 	case DAHDI_CHANDIAG_V1: /* Intentional drop through. */
 	case DAHDI_CHANDIAG:
-		get_user(j, (int *)data); /* get channel number from user */
+	{
+		/* there really is no need to initialize this structure because when it is used it has
+		 * already been completely overwritten, but apparently the compiler cannot figure that
+		 * out and warns about uninitialized usage... so initialize it.
+		 */
+		struct dahdi_echocan_state ec_state = { .ops = NULL, };
+
+		get_user(j, (int *) data); /* get channel number from user */
 		/* make sure its a valid channel number */
 		if ((j < 1) || (j >= maxchans))
 			return -EINVAL;
@@ -3686,54 +3662,52 @@
 		if (!chans[j])
 			return -EINVAL;
 
-		if (!(mychan = kmalloc(sizeof(*mychan), GFP_KERNEL)))
+		chan = kmalloc(sizeof(*chan), GFP_KERNEL);
+		if (!chan)
 			return -ENOMEM;
 
 		/* lock channel */
 		spin_lock_irqsave(&chans[j]->lock, flags);
 		/* make static copy of channel */
-		memcpy(mychan, chans[j], sizeof(*mychan));
+		*chan = *chans[j];
+		if (chan->ec_state) {
+			ec_state = *chan->ec_state;
+		}
 		/* release it. */
 		spin_unlock_irqrestore(&chans[j]->lock, flags);
 
 		module_printk(KERN_INFO, "Dump of DAHDI Channel %d (%s,%d,%d):\n\n",j,
-			mychan->name,mychan->channo,mychan->chanpos);
-		module_printk(KERN_INFO, "flags: %x hex, writechunk: %08lx, readchunk: %08lx\n",
-			(unsigned int) mychan->flags, (long) mychan->writechunk, (long) mychan->readchunk);
-		module_printk(KERN_INFO, "rxgain: %08lx, txgain: %08lx, gainalloc: %d\n",
-			(long) mychan->rxgain, (long)mychan->txgain, mychan->gainalloc);
-		module_printk(KERN_INFO, "span: %08lx, sig: %x hex, sigcap: %x hex\n",
-			(long)mychan->span, mychan->sig, mychan->sigcap);
+			      chan->name, chan->channo, chan->chanpos);
+		module_printk(KERN_INFO, "flags: %x hex, writechunk: %p, readchunk: %p\n",
+			      (unsigned int) chan->flags, chan->writechunk, chan->readchunk);
+		module_printk(KERN_INFO, "rxgain: %p, txgain: %p, gainalloc: %d\n",
+			      chan->rxgain, chan->txgain, chan->gainalloc);
+		module_printk(KERN_INFO, "span: %p, sig: %x hex, sigcap: %x hex\n",
+			      chan->span, chan->sig, chan->sigcap);
 		module_printk(KERN_INFO, "inreadbuf: %d, outreadbuf: %d, inwritebuf: %d, outwritebuf: %d\n",
-			mychan->inreadbuf, mychan->outreadbuf, mychan->inwritebuf, mychan->outwritebuf);
+			      chan->inreadbuf, chan->outreadbuf, chan->inwritebuf, chan->outwritebuf);
 		module_printk(KERN_INFO, "blocksize: %d, numbufs: %d, txbufpolicy: %d, txbufpolicy: %d\n",
-			mychan->blocksize, mychan->numbufs, mychan->txbufpolicy, mychan->rxbufpolicy);
+			      chan->blocksize, chan->numbufs, chan->txbufpolicy, chan->rxbufpolicy);
 		module_printk(KERN_INFO, "txdisable: %d, rxdisable: %d, iomask: %d\n",
-			mychan->txdisable, mychan->rxdisable, mychan->iomask);
-		module_printk(KERN_INFO, "curzone: %08lx, tonezone: %d, curtone: %08lx, tonep: %d\n",
-			(long) mychan->curzone, mychan->tonezone, (long) mychan->curtone, mychan->tonep);
+			      chan->txdisable, chan->rxdisable, chan->iomask);
+		module_printk(KERN_INFO, "curzone: %p, tonezone: %d, curtone: %p, tonep: %d\n",
+			      chan->curzone, chan->tonezone, chan->curtone, chan->tonep);
 		module_printk(KERN_INFO, "digitmode: %d, txdialbuf: %s, dialing: %d, aftdialtimer: %d, cadpos. %d\n",
-			mychan->digitmode, mychan->txdialbuf, mychan->dialing,
-				mychan->afterdialingtimer, mychan->cadencepos);
+			      chan->digitmode, chan->txdialbuf, chan->dialing,
+			      chan->afterdialingtimer, chan->cadencepos);
 		module_printk(KERN_INFO, "confna: %d, confn: %d, confmode: %d, confmute: %d\n",
-			mychan->confna, mychan->_confn, mychan->confmode, mychan->confmute);
-		module_printk(KERN_INFO, "ec: %08lx, echocancel: %d, deflaw: %d, xlaw: %08lx\n",
-			(long) mychan->ec_state, mychan->echocancel, mychan->deflaw, (long) mychan->xlaw);
-		module_printk(KERN_INFO, "echostate: %02x, echotimer: %d, echolastupdate: %d\n",
-			(int) mychan->echostate, mychan->echotimer, mychan->echolastupdate);
+			      chan->confna, chan->_confn, chan->confmode, chan->confmute);
+		module_printk(KERN_INFO, "ec: %p, deflaw: %d, xlaw: %p\n",
+			      chan->ec_state, chan->deflaw, chan->xlaw);
+		if (chan->ec_state) {
+			module_printk(KERN_INFO, "echostate: %02x, echotimer: %d, echolastupdate: %d\n",
+				      ec_state.status.mode, ec_state.status.pretrain_timer, ec_state.status.last_train_tap);
+		}
 		module_printk(KERN_INFO, "itimer: %d, otimer: %d, ringdebtimer: %d\n\n",
-			mychan->itimer, mychan->otimer, mychan->ringdebtimer);
-#if 0
-		if (mychan->ec_state) {
-			int x;
-			/* Dump the echo canceller parameters */
-			for (x=0;x<mychan->ec_state->taps;x++) {
-				module_printk(KERN_INFO, "tap %d: %d\n", x, mychan->ec_state->fir_taps[x]);
-			}
-		}
-#endif
-		kfree(mychan);
-		break;
+			      chan->itimer, chan->otimer, chan->ringdebtimer);
+		kfree(chan);
+		break;
+	}
 	default:
 		return -ENOTTY;
 	}
@@ -3851,7 +3825,7 @@
 	case DAHDI_ATTACH_ECHOCAN:
 	{
 		struct dahdi_attach_echocan ae;
-		const struct dahdi_echocan *new = NULL, *old;
+		const struct dahdi_echocan_factory *new = NULL, *old;
 
 		if (copy_from_user(&ae, (struct dahdi_attach_echocan *) data, sizeof(ae))) {
 			return -EFAULT;
@@ -4172,19 +4146,19 @@
 	case DAHDI_GETVERSION:
 	{
 		struct dahdi_versioninfo vi;
-		struct echocan *cur;
+		struct ecfactory *cur;
 		size_t space = sizeof(vi.echo_canceller) - 1;
 
 		memset(&vi, 0, sizeof(vi));
 		dahdi_copy_string(vi.version, DAHDI_VERSION, sizeof(vi.version));
-		read_lock(&echocan_list_lock);
-		list_for_each_entry(cur, &echocan_list, list) {
+		read_lock(&ecfactory_list_lock);
+		list_for_each_entry(cur, &ecfactory_list, list) {
 			strncat(vi.echo_canceller + strlen(vi.echo_canceller), cur->ec->name, space);
 			space -= strlen(cur->ec->name);
 			if (space < 1) {
 				break;
 			}
-			if (cur->list.next && (cur->list.next != &echocan_list)) {
+			if (cur->list.next && (cur->list.next != &ecfactory_list)) {
 				strncat(vi.echo_canceller + strlen(vi.echo_canceller), ", ", space);
 				space -= 2;
 				if (space < 1) {
@@ -4192,7 +4166,7 @@
 				}
 			}
 		}
-		read_unlock(&echocan_list_lock);
+		read_unlock(&ecfactory_list_lock);
 		if (copy_to_user((struct dahdi_versioninfo *) data, &vi, sizeof(vi)))
 			return -EFAULT;
 		break;
@@ -4854,8 +4828,8 @@
 
 static int ioctl_echocancel(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, void *data)
 {
-	struct echo_can_state *ec = NULL, *ec_state;
-	const struct dahdi_echocan *ec_current;
+	struct dahdi_echocan_state *ec = NULL, *ec_state;
+	const struct dahdi_echocan_factory *ec_current;
 	struct dahdi_echocanparam *params;
 	int ret;
 	unsigned long flags;
@@ -4870,25 +4844,14 @@
 		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;
 		spin_unlock_irqrestore(&chan->lock, flags);
 		if (ec_state) {
-			ec_current->echo_can_free(ec_state);
+			ec_state->ops->echocan_free(chan, ec_state);
 			release_echocan(ec_current);
 		}
-		hw_echocancel_off(chan);
 
 		return 0;
 	}
-
-	/* if parameters were supplied and this channel's span provides an echocan,
-	   but not one that takes params, then we must punt here and return an error */
-	if (ecp->param_count && chan->span && chan->span->echocan &&
-	    !chan->span->echocan_with_params)
-		return -EINVAL;
 
 	params = kmalloc(sizeof(params[0]) * DAHDI_MAX_ECHOCANPARAMS, GFP_KERNEL);
 
@@ -4902,6 +4865,7 @@
 		goto exit_with_free;
 	}
 
+	/* free any echocan that may be on the channel already */
 	spin_lock_irqsave(&chan->lock, flags);
 	ec_state = chan->ec_state;
 	chan->ec_state = NULL;
@@ -4909,34 +4873,31 @@
 	chan->ec_current = NULL;
 	spin_unlock_irqrestore(&chan->lock, flags);
 	if (ec_state) {
-		ec_current->echo_can_free(ec_state);
+		ec_state->ops->echocan_free(chan, ec_state);
 		release_echocan(ec_current);
 	}
 
+	switch (ecp->tap_length) {
+	case 32:
+	case 64:
+	case 128:
+	case 256:
+	case 512:
+	case 1024:
+		break;
+	default:
+		ecp->tap_length = deftaps;
+	}
+
 	ret = -ENODEV;
+	ec_current = NULL;
 
 	/* attempt to use the span's echo canceler; fall back to built-in
 	   if it fails (but not if an error occurs) */
-	if (chan->span) {
-		if (chan->span->echocan_with_params)
-			ret = chan->span->echocan_with_params(chan, ecp, params);
-		else if (chan->span->echocan)
-			ret = chan->span->echocan(chan, ecp->tap_length);
-	}
+	if (chan->span && chan->span->echocan_create)
+		ret = chan->span->echocan_create(chan, ecp, params, &ec);
 
 	if ((ret == -ENODEV) && chan->ec_factory) {
-		switch (ecp->tap_length) {
-		case 32:
-		case 64:
-		case 128:
-		case 256:
-		case 512:
-		case 1024:
-			break;
-		default:
-			ecp->tap_length = deftaps;
-		}
-
 #ifdef USE_ECHOCAN_REFCOUNT
 		/* try to get another reference to the module providing
 		   this channel's echo canceler */
@@ -4950,21 +4911,32 @@
 		   an echo canceler instance if possible */
 		ec_current = chan->ec_factory;
 
-		if ((ret = ec_current->echo_can_create(ecp, params, &ec))) {
+		ret = ec_current->echocan_create(chan, ecp, params, &ec);
+		if (ret) {
 			release_echocan(ec_current);
 
 			goto exit_with_free;
 		}
-
+		if (!ec) {
+			module_printk(KERN_ERR, "%s failed to allocate an " \
+				      "dahdi_echocan_state instance.\n",
+				      ec_current->name);
+			ret = -EFAULT;
+			goto exit_with_free;
+		}
+	}
+
+	if (ec) {
 		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;
-		chan->echotimer = 0;
-		echo_can_disable_detector_init(&chan->txecdis);
-		echo_can_disable_detector_init(&chan->rxecdis);
+		ec->status.mode = ECHO_MODE_ACTIVE;
+		if (!ec->features.CED_tx_detect) {
+			echo_can_disable_detector_init(&chan->ec_state->txecdis);
+		}
+		if (!ec->features.CED_rx_detect) {
+			echo_can_disable_detector_init(&chan->ec_state->rxecdis);
+		}
 		spin_unlock_irqrestore(&chan->lock, flags);
 	}
 
@@ -4972,6 +4944,56 @@
 	kfree(params);
 
 	return ret;
+}
+
+static void set_echocan_fax_mode(struct dahdi_chan *chan, unsigned int channo, const char *reason, unsigned int enable)
+{
+	if (enable) {
+		if (!chan->ec_state)
+			module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for channel %d with no echo canceller\n", reason, channo);
+		else if (chan->ec_state->status.mode == ECHO_MODE_FAX)
+			module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller already in FAX mode on channel %d\n", reason, channo);
+		else if (chan->ec_state->status.mode != ECHO_MODE_ACTIVE)
+			module_printk(KERN_NOTICE, "Ignoring FAX mode request because of %s for echo canceller not in active mode on channel %d\n", reason, channo);
+		else if (chan->ec_state->features.NLP_automatic) {
+			/* for echocans that automatically do the right thing, just
+			 * mark it as being in FAX mode without making any
+			 * changes, as none are necessary.
+			*/
+			chan->ec_state->status.mode = ECHO_MODE_FAX;
+		} else if (chan->ec_state->features.NLP_toggle) {
+			module_printk(KERN_NOTICE, "Disabled echo canceller NLP because of %s on channel %d\n", reason, channo);
+			dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED);
+			chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 0);
+			chan->ec_state->status.mode = ECHO_MODE_FAX;
+		} else {
+			module_printk(KERN_NOTICE, "Idled echo canceller because of %s on channel %d\n", reason, channo);
+			chan->ec_state->status.mode = ECHO_MODE_IDLE;
+		}
+	} else {
+		if (!chan->ec_state)
+			module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for channel %d with no echo canceller\n", reason, channo);
+		else if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE)
+			module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller already in voice mode on channel %d\n", reason, channo);
+		else if ((chan->ec_state->status.mode != ECHO_MODE_FAX) &&
+			 (chan->ec_state->status.mode != ECHO_MODE_IDLE))
+			module_printk(KERN_NOTICE, "Ignoring voice mode request because of %s for echo canceller not in FAX or idle mode on channel %d\n", reason, channo);
+		else if (chan->ec_state->features.NLP_automatic) {
+			/* for echocans that automatically do the right thing, just
+			 * mark it as being in active mode without making any
+			 * changes, as none are necessary.
+			*/
+			chan->ec_state->status.mode = ECHO_MODE_ACTIVE;
+		} else if (chan->ec_state->features.NLP_toggle) {
+			module_printk(KERN_NOTICE, "Enabled echo canceller NLP because of %s on channel %d\n", reason, channo);
+			dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED);
+			chan->ec_state->ops->echocan_NLP_toggle(chan->ec_state, 1);
+			chan->ec_state->status.mode = ECHO_MODE_ACTIVE;
+		} else {
+			module_printk(KERN_NOTICE, "Activated echo canceller because of %s on channel %d\n", reason, channo);
+			chan->ec_state->status.mode = ECHO_MODE_ACTIVE;
+		}
+	}
 }
 
 static int dahdi_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
@@ -5020,8 +5042,8 @@
 			/* 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;
+			struct dahdi_echocan_state *ec_state;
+			const struct dahdi_echocan_factory *ec_current;
 
 			spin_lock_irqsave(&chan->lock, flags);
 			chan->flags &= ~DAHDI_FLAG_AUDIO;
@@ -5054,12 +5076,9 @@
 			spin_unlock_irqrestore(&chan->lock, flags);
 
 			if (ec_state) {
-				ec_current->echo_can_free(ec_state);
+				ec_state->ops->echocan_free(chan, ec_state);
 				release_echocan(ec_current);
 			}
-
-			/* Disable any native echo cancellation as well */
-			hw_echocancel_off(chan);
 
 			if (rxgain)
 				kfree(rxgain);
@@ -5074,8 +5093,8 @@
 			if (!chan->ppp) {
 				chan->ppp = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL);
 				if (chan->ppp) {
-					struct echo_can_state *tec;
-					const struct dahdi_echocan *ec_current;
+					struct dahdi_echocan_state *tec;
+					const struct dahdi_echocan_factory *ec_current;
 
 					chan->ppp->private = chan;
 					chan->ppp->ops = &ztppp_ops;
@@ -5100,10 +5119,6 @@
 					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;
 					/* Make sure there's no gain */
 					if (chan->gainalloc)
 						kfree(chan->rxgain);
@@ -5112,10 +5127,9 @@
 					chan->gainalloc = 0;
 					chan->flags &= ~DAHDI_FLAG_AUDIO;
 					chan->flags |= (DAHDI_FLAG_PPP | DAHDI_FLAG_HDLC | DAHDI_FLAG_FCS);
-					hw_echocancel_off(chan);
 
 					if (tec) {
-						ec_current->echo_can_free(tec);
+						tec->ops->echocan_free(chan, tec);
 						release_echocan(ec_current);
 					}
 				} else
@@ -5201,21 +5215,31 @@
 		j <<= 3;
 		if (chan->ec_state) {
 			/* Start pretraining stage */
-			chan->echostate = ECHO_STATE_PRETRAINING;
-			chan->echotimer = j;
+			spin_lock_irqsave(&chan->lock, flags);
+			chan->ec_state->status.mode = ECHO_MODE_PRETRAINING;
+			chan->ec_state->status.pretrain_timer = j;
+			spin_unlock_irqrestore(&chan->lock, flags);
 		} else
 			return -EINVAL;
+		break;
+	case DAHDI_ECHOCANCEL_FAX_MODE:
+		if (!chan->ec_state) {
+			return -EINVAL;
+		} else {
+			get_user(j, (int *) data);
+			spin_lock_irqsave(&chan->lock, flags);
+			set_echocan_fax_mode(chan, chan->channo, "ioctl", j ? 1 : 0);
+			spin_unlock_irqrestore(&chan->lock, flags);
+		}
 		break;
 	case DAHDI_SETTXBITS:
 		if (chan->sig != DAHDI_SIG_CAS)
 			return -EINVAL;
 		get_user(j,(int *)data);
 		dahdi_cas_setbits(chan, j);
-		rv = 0;
 		break;
 	case DAHDI_GETRXBITS:
 		put_user(chan->rxsig, (int *)data);
-		rv = 0;
 		break;
 	case DAHDI_LOOPBACK:
 		get_user(j, (int *)data);
@@ -5225,7 +5249,6 @@
 		else
 			chan->flags &= ~DAHDI_FLAG_LOOPED;
 		spin_unlock_irqrestore(&chan->lock, flags);
-		rv = 0;
 		break;
 	case DAHDI_HOOK:
 		get_user(j,(int *)data);
@@ -5286,7 +5309,6 @@
 				rv = schluffen(&chan->txstateq);
 				if (rv) return rv;
 #endif
-				rv = 0;
 				break;
 			case DAHDI_WINK:
 				spin_lock_irqsave(&chan->lock, flags);
@@ -5466,13 +5488,6 @@
 		span->deflaw = DAHDI_LAW_MULAW;
 	}
 
-	if (span->echocan && span->echocan_with_params) {
-		module_printk(KERN_NOTICE, "Span %s implements both echocan "
-				"and echocan_with_params functions, preserving only "
-				"echocan_with_params, please fix driver!\n", span->name);
-		span->echocan = NULL;
-	}
-
 	for (x = 0; x < span->channels; x++) {
 		span->chans[x]->span = span;
 		dahdi_chan_reg(span->chans[x]);
@@ -5741,26 +5756,17 @@
 	/* Okay, now we've got something to transmit */
 	for (x=0;x<DAHDI_CHUNKSIZE;x++)
 		getlin[x] = DAHDI_XLAW(txb[x], ms);
-#ifndef NO_ECHOCAN_DISABLE
-	if (ms->ec_state) {
-		for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-			/* Check for echo cancel disabling tone */
-			if (echo_can_disable_detector_update(&ms->txecdis, getlin[x])) {
-				module_printk(KERN_NOTICE, "Disabled echo canceller because of tone (tx) on channel %d\n", ss->channo);
-				ms->echocancel = 0;
-				ms->echostate = ECHO_STATE_IDLE;
-				ms->echolastupdate = 0;
-				ms->echotimer = 0;
-				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);
+
+	if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_tx_detect) {
+		for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
+			if (echo_can_disable_detector_update(&ms->ec_state->txecdis, getlin[x])) {
+				set_echocan_fax_mode(ms, ss->channo, "CED tx detected", 1);
+				dahdi_qevent_nolock(ms, DAHDI_EVENT_TX_CED_DETECTED);
 				break;
 			}
 		}
 	}
-#endif
+
 	if ((!ms->confmute && !ms->dialing) || (ms->flags & DAHDI_FLAG_PSEUDO)) {
 		/* Handle conferencing on non-clear channel and non-HDLC channels */
 		switch(ms->confmode & DAHDI_CONF_MODE_MASK) {
@@ -5945,13 +5951,13 @@
 			break;
 		}
 	}
-	if (ms->confmute || (ms->echostate & __ECHO_STATE_MUTE)) {
+	if (ms->confmute || (ms->ec_state && (ms->ec_state->status.mode) & __ECHO_MODE_MUTE)) {
 		txb[0] = DAHDI_LIN2X(0, ms);
 		memset(txb + 1, txb[0], DAHDI_CHUNKSIZE - 1);
-		if (ms->echostate == ECHO_STATE_STARTTRAINING) {
+		if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_STARTTRAINING)) {
 			/* Transmit impulse now */
 			txb[0] = DAHDI_LIN2X(16384, ms);
-			ms->echostate = ECHO_STATE_AWAITINGECHO;
+			ms->ec_state->status.mode = ECHO_MODE_AWAITINGECHO;
 		}
 	}
 	/* save value from last chunk */
@@ -6545,6 +6551,47 @@
 	spin_unlock_irqrestore(&chan->lock, flags);
 }
 
+static void process_echocan_events(struct dahdi_chan *chan)
+{
+	union dahdi_echocan_events events = chan->ec_state->events;
+
+	if (events.CED_tx_detected) {
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CED_DETECTED);
+		if (chan->ec_state) {
+			if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE)
+				set_echocan_fax_mode(chan, chan->channo, "CED tx detected", 1);
+			else
+				module_printk(KERN_NOTICE, "Detected CED tone (tx) on channel %d\n", chan->channo);
+		}
+	}
+
+	if (events.CED_rx_detected) {
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CED_DETECTED);
+		if (chan->ec_state) {
+			if (chan->ec_state->status.mode == ECHO_MODE_ACTIVE)
+				set_echocan_fax_mode(chan, chan->channo, "CED rx detected", 1);
+			else
+				module_printk(KERN_NOTICE, "Detected CED tone (rx) on channel %d\n", chan->channo);
+		}
+	}
+
+	if (events.CNG_tx_detected)
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_TX_CNG_DETECTED);
+
+	if (events.CNG_rx_detected)
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_RX_CNG_DETECTED);
+
+	if (events.NLP_auto_disabled) {
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_DISABLED);
+		chan->ec_state->status.mode = ECHO_MODE_FAX;
+	}
+
+	if (events.NLP_auto_enabled) {
+		dahdi_qevent_nolock(chan, DAHDI_EVENT_EC_NLP_ENABLED);
+		chan->ec_state->status.mode = ECHO_MODE_ACTIVE;
+	}
+}
+
 static inline void __dahdi_ec_chunk(struct dahdi_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
 {
 	short rxlin, txlin;
@@ -6565,41 +6612,52 @@
 #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP)
 		dahdi_kernel_fpu_begin();
 #endif
-		if (ss->echostate & __ECHO_STATE_MUTE) {
+		if (ss->ec_state->status.mode & __ECHO_MODE_MUTE) {
 			/* Special stuff for training the echo can */
 			for (x=0;x<DAHDI_CHUNKSIZE;x++) {
 				rxlin = DAHDI_XLAW(rxchunk[x], ss);
 				txlin = DAHDI_XLAW(txchunk[x], ss);
-				if (ss->echostate == ECHO_STATE_PRETRAINING) {
-					if (--ss->echotimer <= 0) {
-						ss->echotimer = 0;
-						ss->echostate = ECHO_STATE_STARTTRAINING;
+				if (ss->ec_state->status.mode == ECHO_MODE_PRETRAINING) {
+					if (--ss->ec_state->status.pretrain_timer <= 0) {
+						ss->ec_state->status.pretrain_timer = 0;
+						ss->ec_state->status.mode = ECHO_MODE_STARTTRAINING;
 					}
 				}
-				if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
-					ss->echolastupdate = 0;
-					ss->echostate = ECHO_STATE_TRAINING;
+				if ((ss->ec_state->status.mode == ECHO_MODE_AWAITINGECHO) && (txlin > 8000)) {
+					ss->ec_state->status.last_train_tap = 0;
+					ss->ec_state->status.mode = ECHO_MODE_TRAINING;
 				}
-				if (ss->echostate == ECHO_STATE_TRAINING) {
-					if (ss->ec_current->echo_can_traintap(ss->ec_state, ss->echolastupdate++, rxlin)) {
+				if (ss->ec_state->status.mode == ECHO_MODE_TRAINING) {
+					if (ss->ec_state->ops->echocan_traintap(ss->ec_state, ss->ec_state->status.last_train_tap++, rxlin)) {
 #if 0
-						module_printk(KERN_NOTICE, "Finished training (%d taps trained)!\n", ss->echolastupdate);
-#endif
-						ss->echostate = ECHO_STATE_ACTIVE;
+						module_printk(KERN_NOTICE, "Finished training (%d taps trained)!\n", ss->ec_state->status.last_train_tap);
+#endif
+						ss->ec_state->status.mode = ECHO_MODE_ACTIVE;
 					}
 				}
 				rxlin = 0;
 				rxchunk[x] = DAHDI_LIN2X((int)rxlin, ss);
 			}
-		} else {
-			short rxlins[DAHDI_CHUNKSIZE], txlins[DAHDI_CHUNKSIZE];
-			for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
-				rxlins[x] = DAHDI_XLAW(rxchunk[x], ss);
-				txlins[x] = DAHDI_XLAW(txchunk[x], ss);
-			}
-			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);
+		} else if (ss->ec_state->status.mode != ECHO_MODE_IDLE) {
+			ss->ec_state->events.all = 0;
+
+			if (ss->ec_state->ops->echocan_process) {
+				short rxlins[DAHDI_CHUNKSIZE], txlins[DAHDI_CHUNKSIZE];
+
+				for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
+					rxlins[x] = DAHDI_XLAW(rxchunk[x], ss);
+					txlins[x] = DAHDI_XLAW(txchunk[x], ss);
+				}
+				ss->ec_state->ops->echocan_process(ss->ec_state, rxlins, txlins, DAHDI_CHUNKSIZE);
+
+				for (x = 0; x < DAHDI_CHUNKSIZE; x++)
+					rxchunk[x] = DAHDI_LIN2X((int) rxlins[x], ss);
+			} else if (ss->ec_state->ops->echocan_events)
+				ss->ec_state->ops->echocan_events(ss->ec_state);
+
+			if (ss->ec_state->events.all)
+				process_echocan_events(ss);
+
 		}
 #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP)
 		kernel_fpu_end();
@@ -6692,24 +6750,16 @@
 		putlin[x] = DAHDI_XLAW(rxb[x], ms);
 	}
 
-#ifndef NO_ECHOCAN_DISABLE
-	if (ms->ec_state) {
-		for (x=0;x<DAHDI_CHUNKSIZE;x++) {
-			if (echo_can_disable_detector_update(&ms->rxecdis, putlin[x])) {
-				module_printk(KERN_NOTICE, "Disabled echo canceller because of tone (rx) on channel %d\n", ss->channo);
-				ms->echocancel = 0;
-				ms->echostate = ECHO_STATE_IDLE;
-				ms->echolastupdate = 0;
-				ms->echotimer = 0;
-				ms->ec_current->echo_can_free(ms->ec_state);
-				ms->ec_state = NULL;
-				release_echocan(ms->ec_current);
-				ms->ec_current = NULL;
+	if (ms->ec_state && (ms->ec_state->status.mode == ECHO_MODE_ACTIVE) && !ms->ec_state->features.CED_rx_detect) {
+		for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
+			if (echo_can_disable_detector_update(&ms->ec_state->rxecdis, putlin[x])) {
+				set_echocan_fax_mode(ms, ss->channo, "CED rx detected", 1);
+				dahdi_qevent_nolock(ms, DAHDI_EVENT_RX_CED_DETECTED);
 				break;
 			}
 		}
 	}
-#endif
+
 	/* if doing rx tone decoding */
 	if (ms->rxp1 && ms->rxp2 && ms->rxp3)
 	{

Modified: linux/trunk/drivers/dahdi/dahdi_echocan_jpah.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/dahdi_echocan_jpah.c?view=diff&rev=6529&r1=6528&r2=6529
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_echocan_jpah.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_echocan_jpah.c Wed Apr 29 13:24:04 2009
@@ -40,84 +40,98 @@
 #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args)
 #define debug_printk(level, fmt, args...) if (debug >= level) printk("%s (%s): " fmt, THIS_MODULE->name, __FUNCTION__, ## args)
 
-struct echo_can_state {
+static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
+			   struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec);
+static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
+static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size);
+static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val);
+
+static const struct dahdi_echocan_factory my_factory = {
+	.name = "JPAH",
+	.owner = THIS_MODULE,
+	.echocan_create = echo_can_create,
+};
+
+static const struct dahdi_echocan_ops my_ops = {
+	.name = "JPAH",
+	.echocan_free = echo_can_free,
+	.echocan_process = echo_can_process,
+	.echocan_traintap = echo_can_traintap,
+};
+
+struct ec_pvt {
+	struct dahdi_echocan_state dahdi;
 	int blah;
 };
 
-static int echo_can_create(struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p,
-			   struct echo_can_state **ec)
+#define dahdi_to_pvt(a) container_of(a, struct ec_pvt, dahdi)
+
+static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
+			   struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec)
 {
-	unsigned int x;
-	char *c;
+	struct ec_pvt *pvt;
 
-	if ((*ec = kmalloc(sizeof(**ec), GFP_KERNEL))) {
-		memset(ec, 0, sizeof(**ec));
-	}
-
-	for (x = 0; x < ecp->param_count; x++) {
-		for (c = p[x].name; *c; c++)
-			*c = tolower(*c);
-		printk(KERN_WARNING "Unknown parameter supplied to JPAH echo canceler: '%s'\n", p[x].name);
-		kfree(*ec);
-
+	if (ecp->param_count > 0) {
+		printk(KERN_WARNING "JPAH does not support parameters; failing request\n");
 		return -EINVAL;
 	}
 
+	pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
+	if (!pvt)
+		return -ENOMEM;
+
+	pvt->dahdi.ops = &my_ops;
+
+	*ec = &pvt->dahdi;
 	return 0;
 }
 
-static void echo_can_free(struct echo_can_state *ec)
+static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec)
 {
-	kfree(ec);
+	struct ec_pvt *pvt = dahdi_to_pvt(ec);
+
+	kfree(pvt);
 }
 
-static void echo_can_update(struct echo_can_state *ec, short *isig, short *iref)
+static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size)
 {
-	unsigned int x;
+	struct ec_pvt *pvt = dahdi_to_pvt(ec);
+	u32 x;
 
-	for (x = 0; x < DAHDI_CHUNKSIZE; x++) {
-		if (ec->blah < 2) {
-			ec->blah++;
+	for (x = 0; x < size; x++) {
+		if (pvt->blah < 2) {
+			pvt->blah++;
 
 			*isig++ = 0;
 		} else {
-			ec->blah = 0;
+			pvt->blah = 0;
 			
 			isig++;
 		}
 	}
 }
 
-static int echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val)
 {
 	return 0;
 }
 
-static const struct dahdi_echocan me = {
-	.name = "JPAH",
-	.owner = THIS_MODULE,
-	.echo_can_create = echo_can_create,
-	.echo_can_free = echo_can_free,
-	.echo_can_array_update = echo_can_update,
-	.echo_can_traintap = echo_can_traintap,
-};
-
 static int __init mod_init(void)
 {
-	if (dahdi_register_echocan(&me)) {
+	if (dahdi_register_echocan_factory(&my_factory)) {
 		module_printk(KERN_ERR, "could not register with DAHDI core\n");
 
 		return -EPERM;
 	}
 
-	module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", me.name);
+	module_printk(KERN_NOTICE, "Registered echo canceler '%s'\n", my_factory.name);
 
 	return 0;
 }
 
 static void __exit mod_exit(void)
 {
-	dahdi_unregister_echocan(&me);
+	dahdi_unregister_echocan_factory(&my_factory);
 }
 
 module_param(debug, int, S_IRUGO | S_IWUSR);

Modified: linux/trunk/drivers/dahdi/dahdi_echocan_kb1.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/dahdi_echocan_kb1.c?view=diff&rev=6529&r1=6528&r2=6529
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_echocan_kb1.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_echocan_kb1.c Wed Apr 29 13:24:04 2009
@@ -142,8 +142,33 @@
 	short *buf_d;			
 } echo_can_cb_s;
 
-/* Echo canceller definition */
-struct echo_can_state {
+static int echo_can_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
+			   struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec);
+static void echo_can_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
+static void echo_can_process(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size);
+static int echo_can_traintap(struct dahdi_echocan_state *ec, int pos, short val);
+static void echocan_NLP_toggle(struct dahdi_echocan_state *ec, unsigned int enable);
+
+static const struct dahdi_echocan_factory my_factory = {
+	.name = "KB1",
+	.owner = THIS_MODULE,
+	.echocan_create = echo_can_create,
+};
+
+static const struct dahdi_echocan_features my_features = {

[... 3972 lines stripped ...]



More information about the svn-commits mailing list