summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-06-02 20:01:44 +0000
committerShaun Ruffell <sruffell@digium.com>2011-06-02 20:01:44 +0000
commit914882bb844f05c3e1e7bd23b570abc55838a6df (patch)
tree75e2db46168eab4f8c9c845ad195799c16a73f71
parenta5321ae535ea720597e83c23eea34f46c0dc8b26 (diff)
dahdi: Provide notification when preechocan buffer is created and destroyed.
Not quite ideal, but this seems to be the most straightforward way to know when someone is trying to monitor the preec stream on a channel. This callback allows the board driver providing the span an opportunity to setup the hardware preecho monitoring as needed. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9942 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/dahdi-base.c168
-rw-r--r--include/dahdi/kernel.h6
2 files changed, 141 insertions, 33 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index a6290f9..2680b71 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -1343,6 +1343,75 @@ static inline bool is_gain_allocated(const struct dahdi_chan *chan)
return (chan->rxgain && (chan->rxgain != defgain));
}
+static const char *hwec_def_name = "HWEC";
+static const char *hwec_get_name(const struct dahdi_chan *chan)
+{
+ if (chan && chan->span && chan->span->ops->echocan_name)
+ return chan->span->ops->echocan_name(chan);
+ else
+ return hwec_def_name;
+}
+
+static int hwec_echocan_create(struct dahdi_chan *chan,
+ struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p,
+ struct dahdi_echocan_state **ec)
+{
+ if (chan->span && chan->span->ops->echocan_create)
+ return chan->span->ops->echocan_create(chan, ecp, p, ec);
+ else
+ return -ENODEV;
+}
+
+static const struct dahdi_echocan_factory hwec_factory = {
+ .get_name = hwec_get_name,
+ .owner = THIS_MODULE,
+ .echocan_create = hwec_echocan_create,
+};
+
+/**
+ * dahdi_enable_hw_preechocan - Let the board driver enable hwpreec if possible.
+ * @chan: The channel to monitor.
+ *
+ * Returns 0 on success, if there is a software echocanceler attached on
+ * the channel, or the span does not have an enable_hw_preechocan callback.
+ * Otherwise an error code.
+ *
+ */
+static int dahdi_enable_hw_preechocan(struct dahdi_chan *chan)
+{
+ int res;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->ec_factory != &hwec_factory)
+ res = -ENODEV;
+ else
+ res = 0;
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (-ENODEV == res)
+ return 0;
+
+ if (chan->span->ops->enable_hw_preechocan)
+ return chan->span->ops->enable_hw_preechocan(chan);
+ else
+ return 0;
+}
+
+/**
+ * dahdi_disable_hw_preechocan - Disable any hardware pre echocan monitoring.
+ * @chan: The channel to stop monitoring.
+ *
+ * Give the board driver the option to free any resources needed to monitor
+ * the preechocan stream.
+ *
+ */
+static void dahdi_disable_hw_preechocan(struct dahdi_chan *chan)
+{
+ if (chan->span->ops->disable_hw_preechocan)
+ chan->span->ops->disable_hw_preechocan(chan);
+}
+
/*
* close_channel - close the channel, resetting any channel variables
* @chan: the dahdi_chan to close
@@ -1366,6 +1435,23 @@ static void close_channel(struct dahdi_chan *chan)
might_sleep();
+ if (chan->conf_chan &&
+ ((DAHDI_CONF_MONITOR_RX_PREECHO == chan->confmode) ||
+ (DAHDI_CONF_MONITOR_TX_PREECHO == chan->confmode) ||
+ (DAHDI_CONF_MONITORBOTH_PREECHO == chan->confmode))) {
+ void *readchunkpreec;
+
+ spin_lock_irqsave(&chan->conf_chan->lock, flags);
+ readchunkpreec = chan->conf_chan->readchunkpreec;
+ chan->conf_chan->readchunkpreec = NULL;
+ spin_unlock_irqrestore(&chan->conf_chan->lock, flags);
+
+ if (readchunkpreec) {
+ dahdi_disable_hw_preechocan(chan->conf_chan);
+ kfree(readchunkpreec);
+ }
+ }
+
/* XXX Buffers should be send out before reallocation!!! XXX */
if (!(chan->flags & DAHDI_FLAG_NOSTDTXRX))
dahdi_reallocbufs(chan, 0, 0);
@@ -1443,8 +1529,11 @@ static void close_channel(struct dahdi_chan *chan)
if (rxgain)
kfree(rxgain);
- if (readchunkpreec)
+
+ if (readchunkpreec) {
+ dahdi_disable_hw_preechocan(chan);
kfree(readchunkpreec);
+ }
#ifdef CONFIG_DAHDI_PPP
if (ppp) {
@@ -5108,6 +5197,7 @@ static int dahdi_ioctl_setconf(struct file *file, unsigned long data)
unsigned long flags;
unsigned int confmode;
int oldconf;
+ enum {NONE, ENABLE_HWPREEC, DISABLE_HWPREEC} preec = NONE;
if (copy_from_user(&conf, (void __user *)data, sizeof(conf)))
return -EFAULT;
@@ -5184,21 +5274,50 @@ static int dahdi_ioctl_setconf(struct file *file, unsigned long data)
chan->_confn = dahdi_get_conf_alias(conf.confno);
}
+ spin_unlock(&chan->lock);
+
if (conf_chan) {
if ((confmode == DAHDI_CONF_MONITOR_RX_PREECHO) ||
(confmode == DAHDI_CONF_MONITOR_TX_PREECHO) ||
(confmode == DAHDI_CONF_MONITORBOTH_PREECHO)) {
- void *temp = kmalloc(sizeof(*chan->readchunkpreec) *
- DAHDI_CHUNKSIZE, GFP_ATOMIC);
- conf_chan->readchunkpreec = temp;
+ if (!conf_chan->readchunkpreec) {
+ void *temp = kmalloc(sizeof(short) *
+ DAHDI_CHUNKSIZE, GFP_ATOMIC);
+ if (temp) {
+ preec = ENABLE_HWPREEC;
+
+ spin_lock(&conf_chan->lock);
+ conf_chan->readchunkpreec = temp;
+ spin_unlock(&conf_chan->lock);
+ }
+ }
} else {
+ preec = DISABLE_HWPREEC;
+
+ spin_lock(&conf_chan->lock);
kfree(conf_chan->readchunkpreec);
conf_chan->readchunkpreec = NULL;
+ spin_unlock(&conf_chan->lock);
}
}
- spin_unlock(&chan->lock);
spin_unlock_irqrestore(&chan_lock, flags);
+
+ if (ENABLE_HWPREEC == preec) {
+ int res = dahdi_enable_hw_preechocan(conf_chan);
+ if (res) {
+ spin_lock_irqsave(&chan_lock, flags);
+ spin_lock(&conf_chan->lock);
+ kfree(conf_chan->readchunkpreec);
+ conf_chan->readchunkpreec = NULL;
+ spin_unlock(&conf_chan->lock);
+ spin_unlock_irqrestore(&chan_lock, flags);
+ }
+ return res;
+ } else if (DISABLE_HWPREEC == preec) {
+ dahdi_disable_hw_preechocan(conf_chan);
+ }
+
dahdi_check_conf(oldconf);
if (copy_to_user((void __user *)data, &conf, sizeof(conf)))
return -EFAULT;
@@ -6497,6 +6616,13 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
if (!span || !span->ops || !span->ops->owner)
return -EINVAL;
+ if (span->ops->enable_hw_preechocan ||
+ span->ops->disable_hw_preechocan) {
+ if ((NULL == span->ops->enable_hw_preechocan) ||
+ (NULL == span->ops->disable_hw_preechocan))
+ return -EINVAL;
+ }
+
if (!span->deflaw) {
module_printk(KERN_NOTICE, "Span %s didn't specify default law. "
"Assuming mulaw, please fix driver!\n", span->name);
@@ -7750,6 +7876,8 @@ void __dahdi_ec_chunk(struct dahdi_chan *ss, u8 *rxchunk,
short rxlin;
int x;
+ spin_lock(&ss->lock);
+
if (ss->readchunkpreec) {
/* Save a copy of the audio before the echo can has its way with it */
for (x = 0; x < DAHDI_CHUNKSIZE; x++)
@@ -7811,6 +7939,8 @@ void __dahdi_ec_chunk(struct dahdi_chan *ss, u8 *rxchunk,
dahdi_kernel_fpu_end();
#endif
}
+
+ spin_unlock(&ss->lock);
}
EXPORT_SYMBOL(__dahdi_ec_chunk);
@@ -7829,10 +7959,7 @@ void _dahdi_ec_span(struct dahdi_span *span)
struct dahdi_chan *const chan = span->chans[x];
if (!chan->ec_current)
continue;
-
- spin_lock(&chan->lock);
_dahdi_ec_chunk(chan, chan->readchunk, chan->writechunk);
- spin_unlock(&chan->lock);
}
}
EXPORT_SYMBOL(_dahdi_ec_span);
@@ -9372,31 +9499,6 @@ static void __exit watchdog_cleanup(void)
#endif
-static const char *hwec_def_name = "HWEC";
-static const char *hwec_get_name(const struct dahdi_chan *chan)
-{
- if (chan && chan->span && chan->span->ops->echocan_name)
- return chan->span->ops->echocan_name(chan);
- else
- return hwec_def_name;
-}
-
-static int hwec_echocan_create(struct dahdi_chan *chan,
- struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p,
- struct dahdi_echocan_state **ec)
-{
- if (chan->span && chan->span->ops->echocan_create)
- return chan->span->ops->echocan_create(chan, ecp, p, ec);
- else
- return -ENODEV;
-}
-
-static const struct dahdi_echocan_factory hwec_factory = {
- .get_name = hwec_get_name,
- .owner = THIS_MODULE,
- .echocan_create = hwec_echocan_create,
-};
-
static int __init dahdi_init(void)
{
int res = 0;
diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
index 41196e4..97e1231 100644
--- a/include/dahdi/kernel.h
+++ b/include/dahdi/kernel.h
@@ -864,6 +864,12 @@ struct dahdi_span_ops {
int (*audio_notify)(struct dahdi_chan *chan, int yes);
#endif
+ /*! Opt: Enable preechocan stream from inline HW echocanceler. */
+ int (*enable_hw_preechocan)(struct dahdi_chan *chan);
+
+ /*! Opt: Disable preechocan stream from inline HW echocanceler. */
+ void (*disable_hw_preechocan)(struct dahdi_chan *chan);
+
/*! Opt: Dacs the contents of chan2 into chan1 if possible */
int (*dacs)(struct dahdi_chan *chan1, struct dahdi_chan *chan2);