summaryrefslogtreecommitdiff
path: root/zaptel.c
diff options
context:
space:
mode:
Diffstat (limited to 'zaptel.c')
-rwxr-xr-xzaptel.c87
1 files changed, 80 insertions, 7 deletions
diff --git a/zaptel.c b/zaptel.c
index b5589d1..2e8589d 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -52,6 +52,14 @@
#include <linux/if_ppp.h>
#endif
+#define __ECHO_STATE_MUTE (1 << 8)
+#define ECHO_STATE_IDLE (0)
+#define ECHO_STATE_PRETRAINING (1 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_STARTTRAINING (2 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_AWAITINGECHO (3 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_TRAINING (4 | (__ECHO_STATE_MUTE))
+#define ECHO_STATE_ACTIVE (5)
+
/* #define BUF_MUNGE */
/* Grab fasthdlc with tables */
@@ -1791,6 +1799,9 @@ static int initialize_channel(struct zt_chan *chan)
ec = chan->ec;
chan->ec = NULL;
chan->echocancel = 0;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
chan->txdisable = 0;
chan->rxdisable = 0;
@@ -2613,6 +2624,8 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
mychan.confna, mychan._confn, mychan.confmode, mychan.confmute);
printk("ec: %08x, echocancel: %d, deflaw: %d, xlaw: %08x\n",
(int) mychan.ec, mychan.echocancel, mychan.deflaw, (int) mychan.xlaw);
+ printk("echostate: %02x, echotimer: %d, echolastupdate: %d\n",
+ (int) mychan.echostate, mychan.echotimer, mychan.echolastupdate);
printk("itimer: %d, otimer: %d, ringdebtimer: %d\n\n",
mychan.itimer,mychan.otimer,mychan.ringdebtimer);
#if 0
@@ -3551,6 +3564,9 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
tec = chan->ec;
chan->ec = NULL;
chan->echocancel = 0;
+ chan->echostate = ECHO_STATE_IDLE;
+ chan->echolastupdate = 0;
+ chan->echotimer = 0;
/* Make sure there's no gain */
if (chan->gainalloc)
kfree(chan->rxgain);
@@ -3621,6 +3637,9 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
tec = chan->ec;
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);
@@ -3631,11 +3650,26 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
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 (tec)
echo_can_free(tec);
}
break;
+ case ZT_ECHOTRAIN:
+ get_user(j, (int *)data); /* get pre-training time from user */
+ if ((j < 0) || (j >= ZT_MAX_PRETRAINING))
+ return -EINVAL;
+ j <<= 3;
+ if (chan->ec) {
+ /* Start pretraining stage */
+ chan->echostate = ECHO_STATE_PRETRAINING;
+ chan->echotimer = j;
+ } else
+ return -EINVAL;
+ break;
case ZT_SETTXBITS:
if (chan->sig != ZT_SIG_CAS)
return -EINVAL;
@@ -4112,6 +4146,9 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
if (echo_can_disable_detector_update(&ms->txecdis, getlin[x])) {
printk("zaptel Disabled echo canceller because of tone (tx) on channel %d\n", ss->channo);
ms->echocancel = 0;
+ ms->echostate = ECHO_STATE_IDLE;
+ ms->echolastupdate = 0;
+ ms->echotimer = 0;
kfree(ms->ec);
ms->ec = NULL;
break;
@@ -4244,9 +4281,14 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
break;
}
}
- if (ms->confmute) {
+ if (ms->confmute || (ms->echostate & __ECHO_STATE_MUTE)) {
txb[0] = ZT_LIN2X(0, ms);
memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
+ if (ms->echostate == ECHO_STATE_STARTTRAINING) {
+ /* Transmit impulse now */
+ txb[0] = ZT_LIN2X(16384, ms);
+ ms->echostate = ECHO_STATE_AWAITINGECHO;
+ }
}
/* save value from last chunk */
memcpy(ms->getlin_lastchunk, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
@@ -4405,7 +4447,7 @@ out in the later versions, and is put back now. */
memset(txb, ZT_LIN2X(0, ms), bytes); /* Lastly we use silence on telephony channels */
bytes = 0;
}
- }
+ }
}
static inline void rbs_itimer_expire(struct zt_chan *chan)
@@ -4705,7 +4747,7 @@ void zt_rbsbits(struct zt_chan *chan, int cursig)
void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
{
- short rxlin;
+ short rxlin, txlin;
int x;
long flags;
spin_lock_irqsave(&ss->lock, flags);
@@ -4714,10 +4756,38 @@ void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char
#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
zt_kernel_fpu_begin();
#endif
- for (x=0;x<ZT_CHUNKSIZE;x++) {
- rxlin = ZT_XLAW(rxchunk[x], ss);
- rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin);
- rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
+ if (ss->echostate & __ECHO_STATE_MUTE) {
+ /* Special stuff for training the echo can */
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], ss);
+ txlin = ZT_XLAW(txchunk[x], ss);
+ if (ss->echostate == ECHO_STATE_PRETRAINING) {
+ if (--ss->echotimer <= 0) {
+ ss->echotimer = 0;
+ ss->echostate = ECHO_STATE_STARTTRAINING;
+ }
+ }
+ if ((ss->echostate == ECHO_STATE_AWAITINGECHO) && (txlin > 8000)) {
+ ss->echolastupdate = 0;
+ ss->echostate = ECHO_STATE_TRAINING;
+ }
+ if (ss->echostate == ECHO_STATE_TRAINING) {
+ if (echo_can_traintap(ss->ec, ss->echolastupdate++, rxlin)) {
+#if 0
+ printk("Finished training (%d taps trained)!\n", ss->echolastupdate);
+#endif
+ ss->echostate = ECHO_STATE_ACTIVE;
+ }
+ }
+ rxlin = 0;
+ rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
+ }
+ } else {
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxlin = ZT_XLAW(rxchunk[x], ss);
+ rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin);
+ rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
+ }
}
#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
kernel_fpu_end();
@@ -4801,6 +4871,9 @@ static inline void __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char
if (echo_can_disable_detector_update(&ms->rxecdis, putlin[x])) {
printk("zaptel Disabled echo canceller because of tone (rx) on channel %d\n", ss->channo);
ms->echocancel = 0;
+ ms->echostate = ECHO_STATE_IDLE;
+ ms->echolastupdate = 0;
+ ms->echotimer = 0;
kfree(ms->ec);
ms->ec = NULL;
break;