summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrussell <russell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-06-15 21:31:22 +0000
committerrussell <russell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2005-06-15 21:31:22 +0000
commita1281f4eafa7eb5b869d2935803b5dd198d5997c (patch)
tree9092fbfaa15a050fcc68a27bb12f2d160d746ff0
parent318dfc80dfede13577ef7f076b9ccdd3193744a8 (diff)
more stuff for 2nd gen support
git-svn-id: http://svn.digium.com/svn/zaptel/branches/v1-0@677 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xzaptel.c173
-rwxr-xr-xzaptel.h35
2 files changed, 177 insertions, 31 deletions
diff --git a/zaptel.c b/zaptel.c
index c07bbd4..cc900dd 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -140,6 +140,7 @@ EXPORT_SYMBOL(zt_hooksig);
EXPORT_SYMBOL(zt_alarm_notify);
EXPORT_SYMBOL(zt_set_dynamic_ioctl);
EXPORT_SYMBOL(zt_ec_chunk);
+EXPORT_SYMBOL(zt_ec_span);
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_entries[ZT_MAX_SPANS];
@@ -278,6 +279,8 @@ of the next sample chunk's data (next time around the world).
#include "digits.h"
+static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit);
+
#if defined(CONFIG_ZAPTEL_MMX) || defined(ECHO_CAN_FP)
/* XXX kernel_fpu_begin() is NOT exported properly (in 2.4), so we have to make
a local version. Somebody fix this! XXX */
@@ -956,6 +959,11 @@ static void close_channel(struct zt_chan *chan)
memset(chan->conflast1, 0, sizeof(chan->conflast1));
memset(chan->conflast2, 0, sizeof(chan->conflast2));
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
+ if (chan->span && chan->span->dacs && oldconf)
+ chan->span->dacs(chan, NULL);
+
spin_unlock_irqrestore(&chan->lock, flags);
if (rxgain)
@@ -1266,7 +1274,9 @@ static void zt_net_close(hdlc_device *hdlc)
#ifdef LINUX26
hdlc_close(dev);
#else
+#ifndef CONFIG_OLD_HDLC_API
hdlc_close(hdlc);
+#endif
#endif
#ifndef LINUX26
MOD_DEC_USE_COUNT;
@@ -1559,8 +1569,11 @@ static void zt_chan_unreg(struct zt_chan *chan)
(chans[x]->confmode == ZT_CONF_DIGITALMON))) {
/* Take them out of conference with us */
/* release conference resource if any */
- if (chans[x]->confna)
+ if (chans[x]->confna) {
zt_check_conf(chans[x]->confna);
+ if (chans[x]->span && chans[x]->span->dacs)
+ chans[x]->span->dacs(chans[x], NULL);
+ }
chans[x]->confna = 0;
chans[x]->_confn = 0;
chans[x]->confmode = 0;
@@ -1872,8 +1885,10 @@ who cares what the sig bits are as long as they are stable */
return;
}
if (chan->span->hooksig) {
- chan->txhooksig = txsig;
- chan->span->hooksig(chan, txsig);
+ if (chan->txhooksig != txsig) {
+ chan->txhooksig = txsig;
+ chan->span->hooksig(chan, txsig);
+ }
chan->otimer = timeout * 8; /* Otimer is timer in samples */
return;
} else {
@@ -1933,8 +1948,13 @@ static int zt_hangup(struct zt_chan *chan)
zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
} else {
/* Let the driver hang up the line if it wants to */
- if (chan->span->sethook)
- res = chan->span->sethook(chan, ZT_ONHOOK);
+ if (chan->span->sethook) {
+ if (chan->txhooksig != ZT_ONHOOK) {
+ chan->txhooksig = ZT_ONHOOK;
+ res = chan->span->sethook(chan, ZT_ONHOOK);
+ } else
+ res = 0;
+ }
}
/* if not registered yet, just return here */
if (!(chan->flags & ZT_FLAG_REGISTERED)) return res;
@@ -2037,6 +2057,8 @@ static int initialize_channel(struct zt_chan *chan)
if ((chan->sig & __ZT_SIG_DACS) != __ZT_SIG_DACS) {
chan->confna = 0;
chan->confmode = 0;
+ if (chan->span && chan->span->dacs)
+ chan->span->dacs(chan, NULL);
}
chan->_confn = 0;
memset(chan->conflast, 0, sizeof(chan->conflast));
@@ -2074,6 +2096,8 @@ static int initialize_channel(struct zt_chan *chan)
chan->ringcadence[0] = chan->starttime;
chan->ringcadence[1] = ZT_RINGOFFTIME;
}
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
spin_unlock_irqrestore(&chan->lock, flags);
if (rxgain)
@@ -2691,6 +2715,7 @@ static int zt_timer_ioctl(struct inode *node, struct file *file, unsigned int cm
}
return 0;
}
+
static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit)
{
union {
@@ -2993,9 +3018,15 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct zt_chan *newmaster;
struct zt_dialparams tdp;
struct zt_maintinfo maint;
+ struct zt_indirect_data ind;
unsigned long flags;
int rv;
switch(cmd) {
+ case ZT_INDIRECT:
+ if (copy_from_user(&ind, (struct zt_indirect_data *)data, sizeof(ind)))
+ return -EFAULT;
+ VALID_CHANNEL(ind.chan);
+ return zt_chan_ioctl(inode, file, ind.op, (unsigned long) ind.data, ind.chan);
case ZT_SPANCONFIG:
if (copy_from_user(&lc, (struct zt_lineconfig *)data, sizeof(lc)))
return -EFAULT;
@@ -3127,7 +3158,14 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* Setup conference properly */
chans[ch.chan]->confmode = ZT_CONF_DIGITALMON;
chans[ch.chan]->confna = ch.idlebits;
- }
+ if (chans[ch.chan]->span &&
+ chans[ch.chan]->span->dacs &&
+ chans[ch.idlebits] &&
+ chans[ch.chan]->span &&
+ (chans[ch.chan]->span->dacs == chans[ch.idlebits]->span->dacs))
+ chans[ch.chan]->span->dacs(chans[ch.chan], chans[ch.idlebits]);
+ } else if (chans[ch.chan]->span && chans[ch.chan]->span->dacs)
+ chans[ch.chan]->span->dacs(chans[ch.chan], NULL);
chans[ch.chan]->master = newmaster;
/* Note new slave if we are not our own master */
if (newmaster != chans[ch.chan]) {
@@ -3178,7 +3216,7 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
chans[ch.chan]->hdlcnetdev->netdev.close = zt_net_close;
chans[ch.chan]->hdlcnetdev->netdev.set_mode = NULL;
chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
-#endif
+#endif /* NEW_HDLC_INTERFACE */
chans[ch.chan]->hdlcnetdev->netdev.netdev.irq = chans[ch.chan]->span->irq;
chans[ch.chan]->hdlcnetdev->netdev.netdev.tx_queue_len = 50;
res = register_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
@@ -3647,6 +3685,14 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
chans[i]->_confn = 0; /* Clear confn */
zt_check_conf(j);
zt_check_conf(stack.conf.confno);
+ if (chans[i]->span && chans[i]->span->dacs) {
+ if ((stack.conf.confmode == ZT_CONF_DIGITALMON) && chans[stack.conf.confno]->span &&
+ (chans[stack.conf.confno]->span->dacs == chans[i]->span->dacs)) {
+ chans[i]->span->dacs(chans[i], chans[stack.conf.confno]);
+ } else {
+ chans[i]->span->dacs(chans[i], NULL);
+ }
+ }
/* k will be non-zero if in a real conf */
k = stack.conf.confmode & (ZT_CONF_CONF | ZT_CONF_CONFANN | ZT_CONF_CONFMON | ZT_CONF_CONFANNMON | ZT_CONF_REALANDPSEUDO);
/* if we are going onto a conf */
@@ -3909,6 +3955,8 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
/* initialize conference variables */
chan->_confn = 0;
chan->confna = 0;
+ if (chan->span && chan->span->dacs)
+ chan->span->dacs(chan, NULL);
chan->confmode = 0;
chan->confmute = 0;
memset(chan->conflast, 0, sizeof(chan->conflast));
@@ -3926,6 +3974,9 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
chan->rxgain = defgain;
chan->txgain = defgain;
chan->gainalloc = 0;
+ /* Disable any native echo cancellation as well */
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
spin_unlock_irqrestore(&chan->lock, flags);
if (rxgain)
@@ -3977,6 +4028,8 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
chan->gainalloc = 0;
chan->flags &= ~ZT_FLAG_AUDIO;
chan->flags |= (ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
if (tec)
echo_can_free(tec);
} else
@@ -4023,27 +4076,38 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
return -EINVAL;
get_user(j, (int *)data);
if (j) {
- if ((j == 32) ||
- (j == 64) ||
- (j == 128) ||
- (j == 256)) {
- /* Okay */
- } else {
- j = deftaps;
- }
- ec = echo_can_create(j, 0);
- if (!ec)
- return -ENOMEM;
spin_lock_irqsave(&chan->lock, flags);
/* If we had an old echo can, zap it now */
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);
+ chan->ec = NULL;
+ /* Attempt hardware native echo can */
+ 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)) {
+ /* Okay */
+ } else {
+ j = deftaps;
+ }
+ spin_unlock_irqrestore(&chan->lock, flags);
+ 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);
@@ -4055,6 +4119,9 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
chan->echostate = ECHO_STATE_IDLE;
chan->echolastupdate = 0;
chan->echotimer = 0;
+ /* Attempt hardware native echo can */
+ if (chan->span && chan->span->echocan)
+ chan->span->echocan(chan, 0);
spin_unlock_irqrestore(&chan->lock, flags);
if (tec)
echo_can_free(tec);
@@ -4173,9 +4240,12 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
default:
return -EINVAL;
}
- } else if (chan->span->sethook)
- chan->span->sethook(chan, j);
- else
+ } else if (chan->span->sethook) {
+ if (chan->txhooksig != j) {
+ chan->txhooksig = j;
+ chan->span->sethook(chan, j);
+ }
+ } else
return -ENOSYS;
break;
#ifdef CONFIG_ZAPATA_PPP
@@ -4589,6 +4659,8 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
/* Do nuffin */
break;
case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
/* Add monitored channel */
if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
ACSS(getlin, chans[ms->confna]->getlin);
@@ -4599,6 +4671,8 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
/* Add monitored channel */
if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
ACSS(getlin, chans[ms->confna]->putlin);
@@ -4610,6 +4684,8 @@ static inline void __zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char
txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */
+ /* if a pseudo-channel, ignore */
+ if (ms->flags & ZT_FLAG_PSEUDO) break;
ACSS(getlin, chans[ms->confna]->putlin);
ACSS(getlin, chans[ms->confna]->getlin);
for (x=0;x<ZT_CHUNKSIZE;x++)
@@ -4894,6 +4970,15 @@ static inline void rbs_itimer_expire(struct zt_chan *chan)
__qevent(chan,ZT_EVENT_ONHOOK);
chan->gotgs = 0;
break;
+#ifdef EMFLASH
+ case ZT_SIG_EM:
+ case ZT_SIG_EM_E1:
+ if (chan->rxhooksig == ZT_RXSIG_ONHOOK) {
+ __qevent(chan,ZT_EVENT_ONHOOK);
+ break;
+ }
+ /* intentionally fall thru */
+#endif
default: /* otherwise, its definitely off hook */
__qevent(chan,ZT_EVENT_RINGOFFHOOK);
break;
@@ -5050,6 +5135,14 @@ static void __zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
switch(rxsig) {
case ZT_RXSIG_OFFHOOK: /* went off hook */
/* The interface is going off hook */
+#ifdef EMFLASH
+ if (chan->itimer)
+ {
+ __qevent(chan,ZT_EVENT_WINKFLASH);
+ chan->itimerset = chan->itimer = 0;
+ break;
+ }
+#endif
/* set wink timer */
chan->itimerset = chan->itimer = chan->rxwinktime * 8;
break;
@@ -5058,10 +5151,18 @@ static void __zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
Check for WINK, etc */
if (chan->itimer)
__qevent(chan,ZT_EVENT_WINKFLASH);
+#ifdef EMFLASH
+ else {
+ chan->itimerset = chan->itimer = chan->rxflashtime * 8;
+ chan->gotgs = 0;
+ break;
+ }
+#else
else {
__qevent(chan,ZT_EVENT_ONHOOK);
chan->gotgs = 0;
}
+#endif
chan->itimerset = chan->itimer = 0;
break;
default:
@@ -5211,7 +5312,7 @@ void zt_rbsbits(struct zt_chan *chan, int cursig)
spin_unlock_irqrestore(&chan->lock, flags);
}
-void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
+static inline void __zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
{
short rxlin, txlin;
int x;
@@ -5262,6 +5363,20 @@ void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char
spin_unlock_irqrestore(&ss->lock, flags);
}
+void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
+{
+ __zt_ec_chunk(ss, rxchunk, txchunk);
+}
+
+void zt_ec_span(struct zt_span *span)
+{
+ int x;
+ for (x = 0; x < span->channels; x++) {
+ if (span->chans[x].ec)
+ __zt_ec_chunk(&span->chans[x], span->chans[x].readchunk, span->chans[x].writechunk);
+ }
+}
+
/* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */
/* modifies buffer pointed to by 'amp' with notched-out values */
static inline int sf_detect (sf_detect_state_t *s,
diff --git a/zaptel.h b/zaptel.h
index 14dd69f..8146b63 100755
--- a/zaptel.h
+++ b/zaptel.h
@@ -304,6 +304,14 @@ char dialstr[ZT_MAX_DTMF_BUF];
} ZT_DIAL_OPERATION;
+typedef struct zt_indirect_data
+{
+int chan;
+int op;
+void *data;
+} ZT_INDIRECT_DATA;
+
+
/* ioctl definitions */
#define ZT_CODE 'J'
@@ -590,6 +598,12 @@ char dialstr[ZT_MAX_DTMF_BUF];
#define ZT_GETSIGFREEZE _IOR (ZT_CODE, 55, int)
/*
+ * Do a channel IOCTL from the /dev/zap/ctl interface
+ */
+#define ZT_INDIRECT _IOWR (ZT_CODE, 56, struct zt_indirect_data)
+
+
+/*
* 60-80 are reserved for private drivers
* 80-85 are reserved for dynamic span stuff
*/
@@ -604,6 +618,12 @@ char dialstr[ZT_MAX_DTMF_BUF];
*/
#define ZT_DYNAMIC_DESTROY _IOW (ZT_CODE, 81, struct zt_dynamic_span)
+/*
+ * Enable tone detection -- implemented by low level driver
+ */
+#define ZT_TONEDETECT _IOW (ZT_CODE, 91, int)
+
+
/*
* Startup or Shutdown a span
*/
@@ -630,6 +650,9 @@ char dialstr[ZT_MAX_DTMF_BUF];
#define ZT_MAX_CADENCE 16
+#define ZT_TONEDETECT_ON (1 << 0) /* Detect tones */
+#define ZT_TONEDETECT_MUTE (1 << 1) /* Mute audio in received channel */
+
struct zt_ring_cadence {
int ringcadence [ZT_MAX_CADENCE];
};
@@ -778,7 +801,8 @@ struct zt_tone_def { /* Structure for zone programming */
#define ZT_EVENT_POLARITY 17
#define ZT_EVENT_PULSEDIGIT (1 << 16) /* This is OR'd with the digit received */
-#define ZT_EVENT_DTMFDIGIT (1 << 17) /* Ditto for DTMF */
+#define ZT_EVENT_DTMFDOWN (1 << 17) /* Ditto for DTMF key down event */
+#define ZT_EVENT_DTMFUP (1 << 18) /* Ditto for DTMF key up event */
/* Flag Value for IOMUX, read avail */
#define ZT_IOMUX_READ 1
@@ -849,7 +873,7 @@ struct zt_tone_def { /* Structure for zone programming */
#define ZT_DEFAULT_PULSEAFTERTIME 750 /* 750ms between dial pulse digits */
#define ZT_MINPULSETIME (15 * 8) /* 15 ms minimum */
-#define ZT_MAXPULSETIME (150 * 8) /* 150 ms maximum */
+#define ZT_MAXPULSETIME (200 * 8) /* 200 ms maximum */
#define ZT_PULSETIMEOUT ((ZT_MAXPULSETIME / 8) + 50)
#define ZT_RINGTRAILER (50 * 8) /* Don't consider a ring "over" until it's been gone at least this
@@ -1228,6 +1252,9 @@ struct zt_span {
/* Opt: IOCTL */
int (*ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long data);
+ /* Opt: Native echo cancellation */
+ int (*echocan)(struct zt_chan *chan, int ecval);
+
/* Okay, now we get to the signalling. You have several options: */
/* Option 1: If you're a T1 like interface, you can just provide a
@@ -1247,6 +1274,9 @@ struct zt_span {
/* Option 3: If you can't use sig bits, you can write a function
which handles the individual hook states */
int (*sethook)(struct zt_chan *chan, int hookstate);
+
+ /* Opt: Dacs the contents of chan2 into chan1 if possible */
+ int (*dacs)(struct zt_chan *chan1, struct zt_chan *chan2);
/* Used by zaptel only -- no user servicable parts inside */
int spanno; /* Span number for zaptel */
@@ -1350,6 +1380,7 @@ extern struct zt_tone *zt_dtmf_tone(char digit, int mf);
not be doing so. rxchunk is modified in-place */
extern void zt_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk);
+extern void zt_ec_span(struct zt_span *span);
/* Don't use these directly -- they're not guaranteed to
be there. */