[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