summaryrefslogtreecommitdiff
path: root/zaptel-base.c
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-19 04:04:16 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-12-19 04:04:16 +0000
commit4a8f1fb6fa4e4ad06f171c30d129dfeef6d07867 (patch)
tree9489f3307b1958505c482cccf5c5a06fe7da6fdf /zaptel-base.c
parente68e5ec9adb20f793ad0319b181cfdeea336826d (diff)
add ability to provide parameters to echo cancelers on a per-channel basis, and remove the three versions of the 'Mark' echo canceler (later replaced by KB1 and then by MG2)
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3524 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'zaptel-base.c')
-rw-r--r--zaptel-base.c166
1 files changed, 104 insertions, 62 deletions
diff --git a/zaptel-base.c b/zaptel-base.c
index 309b813..e200d12 100644
--- a/zaptel-base.c
+++ b/zaptel-base.c
@@ -419,18 +419,12 @@ static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX];
#include "sec.h"
#elif defined(ECHO_CAN_STEVE2)
#include "sec-2.h"
-#elif defined(ECHO_CAN_MARK)
-#include "mec.h"
-#elif defined(ECHO_CAN_MARK2)
-#include "mec2.h"
#elif defined(ECHO_CAN_KB1)
#include "kb1ec.h"
#elif defined(ECHO_CAN_MG2)
#include "mg2ec.h"
#elif defined(ECHO_CAN_JP1)
#include "jpah.h"
-#else
-#include "mec3.h"
#endif
static inline void rotate_sums(void)
@@ -4308,6 +4302,95 @@ static void do_ppp_calls(unsigned long data)
}
#endif
+#define MAX_ECHOCANPARAMS 8
+
+static int ioctl_echocancel(struct zt_chan *chan, struct zt_echocanparams *ecp, void *data)
+{
+ struct echo_can_state *ec, *tec;
+ struct zt_echocanparam params[MAX_ECHOCANPARAMS];
+ int ret;
+ unsigned long flags;
+
+ if (ecp->param_count > MAX_ECHOCANPARAMS)
+ return -E2BIG;
+
+ if (ecp->tap_length == 0) {
+ /* disable mode, don't need to inspect params */
+ spin_lock_irqsave(&chan->lock, flags);
+ tec = chan->ec;
+ chan->echocancel = 0;
+ chan->ec = NULL;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
+ if (tec)
+ echo_can_free(tec);
+
+ 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;
+
+ /* enable mode, need the params */
+
+ if (copy_from_user(params, (struct zt_echocanparam *) data, sizeof(params[0]) * ecp->param_count))
+ return -EFAULT;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ tec = chan->ec;
+ chan->ec = NULL;
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ ret = -ENOTTY;
+
+ /* 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 && chan->span->echocan_with_params)
+ ret = chan->span->echocan_with_params(chan, ecp, params);
+
+ if (ret == -ENOTTY) {
+ switch (ecp->tap_length) {
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ case 1024:
+ break;
+ default:
+ ecp->tap_length = deftaps;
+ }
+
+ if ((ret = echo_can_create(ecp, params, &ec))) {
+ if (tec)
+ echo_can_free(tec);
+ return ret;
+ }
+
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->echocancel = ecp->tap_length;
+ chan->ec = 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);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ }
+
+ if (tec)
+ echo_can_free(tec);
+
+ return 0;
+}
+
static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
{
struct zt_chan *chan = chans[unit];
@@ -4317,6 +4400,7 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
int oldconf;
void *rxgain=NULL;
struct echo_can_state *ec, *tec;
+ struct zt_echocanparams ecp;
if (!chan)
return -ENOSYS;
@@ -4481,62 +4565,20 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
case ZT_ECHOCANCEL:
if (!(chan->flags & ZT_FLAG_AUDIO))
return -EINVAL;
- get_user(j, (int *)data);
- if (j) {
- spin_lock_irqsave(&chan->lock, flags);
- /* If we had an old echo can, zap it now */
- tec = chan->ec;
- chan->ec = NULL;
- /* Attempt hardware native echo can */
- spin_unlock_irqrestore(&chan->lock, flags);
-
- if (chan->span && chan->span->echocan)
- ret = chan->span->echocan(chan, j);
- else
- ret = -ENOTTY;
-
- if (ret) {
- /* Use built-in echo can */
- if ((j == 32) ||
- (j == 64) ||
- (j == 128) ||
- (j == 256) ||
- (j == 512) ||
- (j == 1024)) {
- /* Okay */
- } else {
- j = deftaps;
- }
- ec = echo_can_create(j, 0);
- if (!ec)
- return -ENOMEM;
- spin_lock_irqsave(&chan->lock, flags);
- chan->echocancel = j;
- chan->ec = 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);
- spin_unlock_irqrestore(&chan->lock, flags);
- }
- if (tec)
- echo_can_free(tec);
- } else {
- spin_lock_irqsave(&chan->lock, flags);
- tec = chan->ec;
- chan->echocancel = 0;
- chan->ec = NULL;
- chan->echostate = ECHO_STATE_IDLE;
- chan->echolastupdate = 0;
- chan->echotimer = 0;
- spin_unlock_irqrestore(&chan->lock, flags);
- /* Attempt hardware native echo can */
- if (chan->span && chan->span->echocan)
- chan->span->echocan(chan, 0);
- if (tec)
- echo_can_free(tec);
- }
+ if (copy_from_user(&ecp, (struct zt_echocanparams *) data, sizeof(ecp)))
+ return -EFAULT;
+ data += sizeof(ecp);
+ if ((ret = ioctl_echocancel(chan, &ecp, (void *) data)))
+ return ret;
+ break;
+ case ZT_ECHOCANCEL_V1:
+ if (!(chan->flags & ZT_FLAG_AUDIO))
+ return -EINVAL;
+ get_user(j, (int *) data);
+ ecp.tap_length = j;
+ ecp.param_count = 0;
+ if ((ret = ioctl_echocancel(chan, &ecp, (void *) data)))
+ return ret;
break;
case ZT_ECHOTRAIN:
get_user(j, (int *)data); /* get pre-training time from user */