summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
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 /drivers/dahdi/dahdi-base.c
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
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c168
1 files changed, 135 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;