summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wct4xxp
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2009-04-29 18:24:04 +0000
committerShaun Ruffell <sruffell@digium.com>2009-04-29 18:24:04 +0000
commit5f94a3b91de2c3835d6852d59cab9f6876177156 (patch)
tree4c25956b6ecdcd5b902ac80b40237bc3e938be44 /drivers/dahdi/wct4xxp
parent4a192a3e8f16ed6143377b5726e1fb53b446f5e9 (diff)
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 git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@6529 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/wct4xxp')
-rw-r--r--drivers/dahdi/wct4xxp/base.c117
1 files changed, 96 insertions, 21 deletions
diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index 28ba8ee..3bfd9cc 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -283,6 +283,7 @@ struct t4_span {
struct work_struct swork;
#endif
struct dahdi_chan *chans[32]; /* Individual channels */
+ struct dahdi_echocan_state *ec[32]; /* Echocan state for each channel */
};
struct t4 {
@@ -345,12 +346,38 @@ struct t4 {
#define T4_VPM_PRESENT (1 << 28)
-
#ifdef VPM_SUPPORT
static void t4_vpm400_init(struct t4 *wc);
static void t4_vpm450_init(struct t4 *wc);
static void t4_vpm_set_dtmf_threshold(struct t4 *wc, unsigned int threshold);
+
+static int echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
+ struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec);
+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
+
+static const struct dahdi_echocan_features vpm400m_ec_features = {
+ .NLP_automatic = 1,
+ .CED_tx_detect = 1,
+ .CED_rx_detect = 1,
+};
+
+static const struct dahdi_echocan_features vpm450m_ec_features = {
+ .NLP_automatic = 1,
+ .CED_tx_detect = 1,
+ .CED_rx_detect = 1,
+};
+
+static const struct dahdi_echocan_ops vpm400m_ec_ops = {
+ .name = "VPM400M",
+ .echocan_free = echocan_free,
+};
+
+static const struct dahdi_echocan_ops vpm450m_ec_ops = {
+ .name = "VPM450M",
+ .echocan_free = echocan_free,
+};
#endif
+
static void __set_clear(struct t4 *wc, int span);
static int t4_startup(struct dahdi_span *span);
static int t4_shutdown(struct dahdi_span *span);
@@ -1089,43 +1116,84 @@ static int t4_vpm_unit(int span, int channel)
return unit;
}
-static int t4_echocan(struct dahdi_chan *chan, int eclen)
+static int echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
+ struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec)
{
struct t4 *wc = chan->pvt;
+ struct t4_span *tspan = chan->span->pvt;
int channel;
- int unit;
-
+ const struct dahdi_echocan_ops *ops;
+ const struct dahdi_echocan_features *features;
+
if (!wc->vpm)
return -ENODEV;
if (chan->span->offset >= vpmspans)
return -ENODEV;
- if (wc->t1e1)
- channel = chan->chanpos;
- else
- channel = chan->chanpos + 4;
+ if (wc->vpm450m) {
+ ops = &vpm450m_ec_ops;
+ features = &vpm450m_ec_features;
+ } else {
+ ops = &vpm400m_ec_ops;
+ features = &vpm400m_ec_features;
+ }
+
+ if (ecp->param_count > 0) {
+ printk(KERN_WARNING "%s echo canceller does not support parameters; failing request\n", ops->name);
+ return -EINVAL;
+ }
+
+ *ec = tspan->ec[chan->chanpos - 1];
+ (*ec)->ops = ops;
+ (*ec)->features = *features;
+
+ channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4;
+
if (wc->vpm450m) {
channel = channel << 2;
channel |= chan->span->offset;
- if(debug & DEBUG_ECHOCAN)
+ if (debug & DEBUG_ECHOCAN)
printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n",
- wc->num, chan->chanpos, chan->span->offset, channel, eclen);
- vpm450m_setec(wc->vpm450m, channel, eclen);
-// Mark msleep(10);
-// msleep(100); // longer test
+ wc->num, chan->chanpos, chan->span->offset, channel, ecp->tap_length);
+ vpm450m_setec(wc->vpm450m, channel, ecp->tap_length);
} else {
- unit = t4_vpm_unit(chan->span->offset, channel);
- if(debug & DEBUG_ECHOCAN)
+ int unit = t4_vpm_unit(chan->span->offset, channel);
+
+ if (debug & DEBUG_ECHOCAN)
printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n",
- wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
- if (eclen)
- t4_vpm_out(wc,unit,channel,0x3e);
- else
- t4_vpm_out(wc,unit,channel,0x01);
+ wc->num, chan->chanpos, chan->span->offset, unit, channel, ecp->tap_length);
+ t4_vpm_out(wc, unit, channel, 0x3e);
}
+
return 0;
}
+
+static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec)
+{
+ struct t4 *wc = chan->pvt;
+ int channel;
+
+ memset(ec, 0, sizeof(*ec));
+
+ channel = wc->t1e1 ? chan->chanpos : chan->chanpos + 4;
+
+ if (wc->vpm450m) {
+ channel = channel << 2;
+ channel |= chan->span->offset;
+ if (debug & DEBUG_ECHOCAN)
+ printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, Span is %d, offset is %d length 0\n",
+ wc->num, chan->chanpos, chan->span->offset, channel);
+ vpm450m_setec(wc->vpm450m, channel, 0);
+ } else {
+ int unit = t4_vpm_unit(chan->span->offset, channel);
+
+ if (debug & DEBUG_ECHOCAN)
+ printk(KERN_DEBUG "echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length 0\n",
+ wc->num, chan->chanpos, chan->span->offset, unit, channel);
+ t4_vpm_out(wc, unit, channel, 0x01);
+ }
+}
#endif
static int t4_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long data)
@@ -1593,7 +1661,7 @@ static void init_spans(struct t4 *wc)
ts->span.hdlc_hard_xmit = t4_hdlc_hard_xmit;
if (gen2) {
#ifdef VPM_SUPPORT
- ts->span.echocan = t4_echocan;
+ ts->span.echocan_create = echocan_create;
#endif
ts->span.dacs = t4_dacs;
}
@@ -3494,6 +3562,8 @@ static void free_wc(struct t4 *wc)
if (wc->tspans[x]->chans[y]) {
kfree(wc->tspans[x]->chans[y]);
}
+ if (wc->tspans[x]->ec[y])
+ kfree(wc->tspans[x]->ec[y]);
}
kfree(wc->tspans[x]);
}
@@ -3630,6 +3700,11 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i
return -ENOMEM;
}
memset(wc->tspans[x]->chans[f], 0, sizeof(*wc->tspans[x]->chans[f]));
+ if (!(wc->tspans[x]->ec[f] = kmalloc(sizeof(*wc->tspans[x]->ec[f]), GFP_KERNEL))) {
+ free_wc(wc);
+ return -ENOMEM;
+ }
+ memset(wc->tspans[x]->ec[f], 0, sizeof(*wc->tspans[x]->ec[f]));
}
#ifdef ENABLE_WORKQUEUES