From a1281f4eafa7eb5b869d2935803b5dd198d5997c Mon Sep 17 00:00:00 2001 From: russell Date: Wed, 15 Jun 2005 21:31:22 +0000 Subject: more stuff for 2nd gen support git-svn-id: http://svn.digium.com/svn/zaptel/branches/v1-0@677 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- zaptel.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- zaptel.h | 35 ++++++++++++- 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;xgotgs = 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' @@ -589,6 +597,12 @@ char dialstr[ZT_MAX_DTMF_BUF]; #define ZT_SIGFREEZE _IOW (ZT_CODE, 54, int) #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. */ -- cgit v1.2.3