summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-06-20 14:42:35 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-06-20 14:42:35 +0000
commit29ebfe8a9da5898e9e884c41cb5091b50e29a741 (patch)
treea806b60bb8faee1dec35dad055af880036d6f406
parentfbe94a62186b12f2c3afec02a183ec4587597499 (diff)
Version 0.2.0 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@87 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xzaptel.c1782
1 files changed, 1125 insertions, 657 deletions
diff --git a/zaptel.c b/zaptel.c
index 1712a22..2b228a8 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -45,9 +45,12 @@
#endif /* CONFIG_ZAPATA_NET */
#include <linux/ppp_defs.h>
#ifdef CONFIG_ZAPATA_PPP
+#include <linux/if.h>
#include <linux/if_ppp.h>
#endif
+/* #define BUF_MUNGE */
+
/* Grab fasthdlc with tables */
#define FAST_HDLC_NEED_TABLES
#include "fasthdlc.h"
@@ -58,6 +61,12 @@
#include <linux/zaptel.h>
#endif
+/* Get helper arithmetic */
+#include "arith.h"
+#ifdef CONFIG_ZAPTEL_MMX
+#include <asm/i387.h>
+#endif
+
#define hdlc_to_ztchan(h) (((struct zt_hdlc *)(h))->chan)
/* macro-oni for determining a unit (channel) number */
@@ -80,7 +89,14 @@ EXPORT_SYMBOL(zt_dtmf_tone);
EXPORT_SYMBOL(zt_register);
EXPORT_SYMBOL(zt_unregister);
EXPORT_SYMBOL(__zt_mulaw);
+EXPORT_SYMBOL(__zt_alaw);
+#ifdef CONFIG_CALC_XLAW
+EXPORT_SYMBOL(__zt_lineartoulaw);
+EXPORT_SYMBOL(__zt_lineartoalaw);
+#else
EXPORT_SYMBOL(__zt_lin2mu);
+EXPORT_SYMBOL(__zt_lin2a);
+#endif
EXPORT_SYMBOL(zt_lboname);
EXPORT_SYMBOL(zt_transmit);
EXPORT_SYMBOL(zt_receive);
@@ -89,6 +105,7 @@ EXPORT_SYMBOL(zt_qevent);
EXPORT_SYMBOL(zt_hooksig);
EXPORT_SYMBOL(zt_alarm_notify);
EXPORT_SYMBOL(zt_set_dynamic_ioctl);
+EXPORT_SYMBOL(zt_ec_chunk);
/* Here are a couple important little additions for devfs */
#ifdef CONFIG_DEVFS_FS
@@ -151,6 +168,10 @@ typedef short sumtype[ZT_MAX_CHUNKSIZE];
static sumtype sums[(ZT_MAX_CONF + 1) * 3];
+/* Translate conference aliases into actual conferences
+ and vice-versa */
+static short confalias[ZT_MAX_CONF + 1];
+static short confrev[ZT_MAX_CONF + 1];
static sumtype *conf_sums_next;
static sumtype *conf_sums;
@@ -204,22 +225,37 @@ of the next sample chunk's data (next time around the world).
*/
-static inline void rotate_sums(void)
-{
- /* Rotate where we sum and so forth */
- static int pos = 0;
- conf_sums_prev = sums + (ZT_MAX_CONF + 1) * pos;
- conf_sums = sums + (ZT_MAX_CONF + 1) * ((pos + 1) % 3);
- conf_sums_next = sums + (ZT_MAX_CONF + 1) * ((pos + 2) % 3);
- pos = (pos + 1) % 3;
- memset(conf_sums_next, 0,(ZT_MAX_CONF + 1) * sizeof(sumtype));
-}
-
#define DIGIT_MODE_DTMF 0
#define DIGIT_MODE_MFV1 1
#include "digits.h"
-
+
+#ifdef CONFIG_ZAPTEL_MMX
+/* XXX kernel_fpu_begin() is NOT exported properly, so we have to make
+ a local version. Somebody fix this! XXX */
+
+static inline void __save_init_fpu( struct task_struct *tsk )
+{
+ if ( cpu_has_fxsr ) {
+ asm volatile( "fxsave %0 ; fnclex"
+ : "=m" (tsk->thread.i387.fxsave) );
+ } else {
+ asm volatile( "fnsave %0 ; fwait"
+ : "=m" (tsk->thread.i387.fsave) );
+ }
+ tsk->flags &= ~PF_USEDFPU;
+}
+
+static inline void zt_kernel_fpu_begin(void)
+{
+ struct task_struct *tsk = current;
+ if (tsk->flags & PF_USEDFPU) {
+ __save_init_fpu(tsk);
+ return;
+ }
+ clts();
+}
+#endif
struct zt_zone {
char name[40]; /* Informational, only */
@@ -236,18 +272,21 @@ static struct zt_chan *chans[ZT_MAX_CHANNELS];
static int maxspans = 0;
static int maxchans = 0;
+static int maxconfs = 0;
+static int maxlinks = 0;
static int default_zone = DEFAULT_TONE_ZONE;
short __zt_mulaw[256];
-u_char __zt_lin2mu[16384];
-
short __zt_alaw[256];
-u_char __zt_lin2a[16384];
-u_char defgain[256];
+#ifndef CONFIG_CALC_XLAW
+u_char __zt_lin2mu[16384];
+u_char __zt_lin2a[16384];
+#endif
+static u_char defgain[256];
static rwlock_t zone_lock = RW_LOCK_UNLOCKED;
static rwlock_t chan_lock = RW_LOCK_UNLOCKED;
@@ -256,6 +295,18 @@ static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX];
#define NUM_SIGS 8
+
+static inline void rotate_sums(void)
+{
+ /* Rotate where we sum and so forth */
+ static int pos = 0;
+ conf_sums_prev = sums + (ZT_MAX_CONF + 1) * pos;
+ conf_sums = sums + (ZT_MAX_CONF + 1) * ((pos + 1) % 3);
+ conf_sums_next = sums + (ZT_MAX_CONF + 1) * ((pos + 2) % 3);
+ pos = (pos + 1) % 3;
+ memset(conf_sums_next, 0, maxconfs * sizeof(sumtype));
+}
+
/* return quiescent (idle) signalling states, for the various signalling types */
static int zt_q_sig(struct zt_chan *chan)
{
@@ -275,28 +326,103 @@ static unsigned int in_sig[NUM_SIGS][2] = {
/* if RBS does not apply, return error */
if (!(chan->span->flags & ZT_FLAG_RBS) ||
!chan->span->rbsbits) return(-1);
+ if (chan->sig == ZT_SIG_CAS) {
+ static int printed = 0;
+ if (printed < 10) {
+ printed++;
+ }
+ return chan->idlebits;
+ }
for (x=0;x<NUM_SIGS;x++) {
if (in_sig[x][0] == chan->sig) return(in_sig[x][1]);
} return(-1); /* not found -- error */
}
+static int zt_first_empty_alias(void)
+{
+ /* Find the first conference which has no alias pointing to it */
+ int x;
+ for (x=1;x<ZT_MAX_CONF;x++) {
+ if (!confrev[x])
+ return x;
+ }
+ return -1;
+}
+
+static void recalc_maxconfs(void)
+{
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (confrev[x]) {
+ maxconfs = x+1;
+ return;
+ }
+ }
+ maxconfs = 0;
+}
+
+static void recalc_maxlinks(void)
+{
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (conf_links[x].src || conf_links[x].dst) {
+ maxlinks = x+1;
+ return;
+ }
+ }
+ maxlinks = 0;
+}
+
static int zt_first_empty_conference(void)
{
- /* Find first conference to which no one is subscribed */
- int x,y, inuse;
- for (y=ZT_MAX_CONF;y>0;y--) {
- inuse=0;
- for (x=1;x<ZT_MAX_CHANNELS;x++)
- if (chans[x] && (chans[x]->confn == y)) {
- inuse++;
- break;
- }
- if (!inuse)
- return y;
+ /* Find the first conference which has no alias */
+ int x;
+ for (x=ZT_MAX_CONF-1;x>0;x--) {
+ if (!confalias[x])
+ return x;
}
return -1;
}
+static int zt_get_conf_alias(int x)
+{
+ int a;
+ if (confalias[x]) {
+ return confalias[x];
+ }
+
+ /* Allocate an alias */
+ a = zt_first_empty_alias();
+ confalias[x] = a;
+ confrev[a] = x;
+
+ /* Highest conference may have changed */
+ recalc_maxconfs();
+ return a;
+}
+
+static void zt_check_conf(int x)
+{
+ int y;
+
+ /* return if no valid conf number */
+ if (x <= 0) return;
+ /* Return if there is no alias */
+ if (!confalias[x])
+ return;
+ for (y=0;y<maxchans;y++) {
+ if (chans[y] && (chans[y]->confna == x) && (chans[y]->confmode & (ZT_CONF_CONF | ZT_CONF_CONFANN | ZT_CONF_CONFMON | ZT_CONF_CONFANNMON | ZT_CONF_REALANDPSEUDO)))
+ return;
+ }
+ /* If we get here, nobody is in the conference anymore. Clear it out
+ both forward and reverse */
+ confrev[confalias[x]] = 0;
+ confalias[x] = 0;
+
+ /* Highest conference may have changed */
+ recalc_maxconfs();
+}
+
/* enqueue an event on a channel */
static void qevent(struct zt_chan *chan, int event)
{
@@ -424,6 +550,121 @@ static int zt_reallocbufs(struct zt_chan *ss, int j, int numbufs)
static int zt_hangup(struct zt_chan *chan);
static void zt_set_law(struct zt_chan *chan, int law);
+/* Pull a ZT_CHUNKSIZE piece off the queue. Returns
+ 0 on success or -1 on failure. If failed, provides
+ silence */
+static int buf_pull(struct confq *q, u_char *data, struct zt_chan *c, char *label)
+{
+ int oldoutbuf = q->outbuf;
+ /* Ain't nuffin to read */
+ if (q->outbuf < 0) {
+ if (data)
+ memset(data, ZT_LIN2X(0,c), ZT_CHUNKSIZE);
+ return -1;
+ }
+ if (data)
+ memcpy(data, q->buf[q->outbuf], ZT_CHUNKSIZE);
+ q->outbuf = (q->outbuf + 1) % ZT_CB_SIZE;
+
+ /* Won't be nuffin next time */
+ if (q->outbuf == q->inbuf) {
+ q->outbuf = -1;
+ }
+
+ /* If they thought there was no space then
+ there is now where we just read */
+ if (q->inbuf < 0)
+ q->inbuf = oldoutbuf;
+ return 0;
+}
+
+/* Returns a place to put stuff, or NULL if there is
+ no room */
+
+static u_char *buf_pushpeek(struct confq *q)
+{
+ if (q->inbuf < 0)
+ return NULL;
+ return q->buf[q->inbuf];
+}
+
+static u_char *buf_peek(struct confq *q)
+{
+ if (q->outbuf < 0)
+ return NULL;
+ return q->buf[q->outbuf];
+}
+
+#ifdef BUF_MUNGE
+static u_char *buf_cpush(struct confq *q)
+{
+ int pos;
+ /* If we have no space, return where the
+ last space that we *did* have was */
+ if (q->inbuf > -1)
+ return NULL;
+ pos = q->outbuf - 1;
+ if (pos < 0)
+ pos += ZT_CB_SIZE;
+ return q->buf[pos];
+}
+
+static void buf_munge(struct zt_chan *chan, u_char *old, u_char *new)
+{
+ /* Run a weighted average of the old and new, in order to
+ mask a missing sample */
+ int x;
+ int val;
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ val = x * ZT_XLAW(new[x], chan) + (ZT_CHUNKSIZE - x - 1) * ZT_XLAW(old[x], chan);
+ val = val / (ZT_CHUNKSIZE - 1);
+ old[x] = ZT_LIN2X(val, chan);
+ }
+}
+#endif
+/* Push something onto the queue, or assume what
+ is there is valid if data is NULL */
+static int buf_push(struct confq *q, u_char *data, char *label)
+{
+ int oldinbuf = q->inbuf;
+ if (q->inbuf < 0) {
+ return -1;
+ }
+ if (data)
+ /* Copy in the data */
+ memcpy(q->buf[q->inbuf], data, ZT_CHUNKSIZE);
+
+ /* Advance the inbuf pointer */
+ q->inbuf = (q->inbuf + 1) % ZT_CB_SIZE;
+
+ if (q->inbuf == q->outbuf) {
+ /* No space anymore... */
+ q->inbuf = -1;
+ }
+ /* If they don't think data is ready, let
+ them know it is now */
+ if (q->outbuf < 0) {
+ q->outbuf = oldinbuf;
+ }
+ return 0;
+}
+
+static void reset_conf(struct zt_chan *chan)
+{
+ int x;
+ /* Empty out buffers and reset to initialization */
+ for (x=0;x<ZT_CB_SIZE;x++)
+ chan->confin.buf[x] = chan->confin.buffer + ZT_CHUNKSIZE * x;
+ chan->confin.inbuf = 0;
+ chan->confin.outbuf = -1;
+
+ for (x=0;x<ZT_CB_SIZE;x++)
+ chan->confout.buf[x] = chan->confout.buffer + ZT_CHUNKSIZE * x;
+ chan->confout.inbuf = 0;
+ chan->confout.outbuf = -1;
+}
+
+
static void close_channel(struct zt_chan *chan)
{
unsigned int flags;
@@ -457,11 +698,15 @@ static void close_channel(struct zt_chan *chan)
chan->afterdialingtimer = 0;
/* initialize IO MUX mask */
chan->iomask = 0;
+ /* release conference resource if any */
+ if (chan->confna) zt_check_conf(chan->confna);
/* initialize conference variables */
- chan->confn = 0;
+ chan->_confn = 0;
+ chan->confna = 0;
chan->confmode = 0;
chan->confmute = 0;
chan->gotgs = 0;
+ reset_conf(chan);
if (chan->gainalloc && chan->rxgain)
rxgain = chan->rxgain;
@@ -572,6 +817,7 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
if (tone_zones[zone]) {
chan->curzone = tone_zones[zone];
chan->tonezone = zone;
+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
} else {
res = -ENODATA;
}
@@ -591,10 +837,18 @@ static void zt_set_law(struct zt_chan *chan, int law)
}
if (law == ZT_LAW_ALAW) {
chan->xlaw = __zt_alaw;
+#ifdef CONFIG_CALC_XLAW
+ chan->lineartoxlaw = __zt_lineartoalaw;
+#else
chan->lin2x = __zt_lin2a;
+#endif
} else {
chan->xlaw = __zt_mulaw;
+#ifdef CONFIG_CALC_XLAW
+ chan->lineartoxlaw = __zt_lineartoulaw;
+#else
chan->lin2x = __zt_lin2mu;
+#endif
}
}
@@ -945,12 +1199,16 @@ static void zt_chan_unreg(struct zt_chan *chan)
if (chans[x]->master == chan) {
chans[x]->master = chans[x];
}
- if ((chans[x]->confn == chan->channo) &&
+ if ((chans[x]->confna == chan->channo) &&
(chans[x]->confmode >= ZT_CONF_MONITOR) &&
(chans[x]->confmode <= ZT_CONF_MONITORBOTH)) {
/* Take them out of conference with us */
- chans[x]->confn = -1;
- chans[x]->confmode = ZT_CONF_NORMAL;
+ /* release conference resource if any */
+ if (chans[x]->confna)
+ zt_check_conf(chans[x]->confna);
+ chans[x]->confna = 0;
+ chans[x]->_confn = 0;
+ chans[x]->confmode = 0;
}
}
chan->channo = -1;
@@ -992,7 +1250,7 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u
/* There seems to be a max stack size, so we have
to do this in smaller pieces */
short lindata[512];
- int left = amnt;
+ int left = amnt >> 1; /* amnt is in bytes */
int pos = 0;
int pass;
while(left) {
@@ -1084,7 +1342,7 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
/* There seems to be a max stack size, so we have
to do this in smaller pieces */
short lindata[512];
- int left = amnt;
+ int left = amnt >> 1; /* amnt is in bytes */
int pos = 0;
int pass;
while(left) {
@@ -1214,6 +1472,17 @@ who cares what the sig bits are as long as they are stable */
printk("zt_rbs: Don't know RBS signalling type %d on channel %s\n", chan->sig, chan->name);
}
+static int zt_cas_setbits(struct zt_chan *chan, int bits)
+{
+ if (chan->span->rbsbits) {
+ chan->txsig = bits;
+ chan->span->rbsbits(chan, bits);
+ } else {
+ printk("Huh? CAS setbits, but no RBS bits function\n");
+ }
+ return 0;
+}
+
static int zt_hangup(struct zt_chan *chan)
{
int res=0;
@@ -1225,8 +1494,10 @@ static int zt_hangup(struct zt_chan *chan)
return -EINVAL;
chan->kewlonhook = 0;
if (chan->span->flags & ZT_FLAG_RBS) {
- /* Do RBS signalling on the channel's behalf */
- if ((chan->sig == ZT_SIG_FXOKS) && (chan->txstate != ZT_TXSTATE_ONHOOK)) {
+ if (chan->sig == ZT_SIG_CAS) {
+ zt_cas_setbits(chan, chan->idlebits);
+ } else if ((chan->sig == ZT_SIG_FXOKS) && (chan->txstate != ZT_TXSTATE_ONHOOK)) {
+ /* Do RBS signalling on the channel's behalf */
zt_rbs_sethook(chan, ZT_TXSIG_KEWL, ZT_TXSTATE_KEWL, ZT_KEWLTIME);
} else
zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
@@ -1293,10 +1564,16 @@ static int initialize_channel(struct zt_chan *chan)
init_waitqueue_head(&chan->writebufq);
init_waitqueue_head(&chan->eventbufq);
init_waitqueue_head(&chan->txstateq);
+
+ /* Reset conferences */
+ reset_conf(chan);
/* I/O Mask, etc */
chan->iomask = 0;
- chan->confn = 0;
+ /* release conference resource if any */
+ if (chan->confna) zt_check_conf(chan->confna);
+ chan->confna = 0;
+ chan->_confn = 0;
chan->confmode = 0;
memset(chan->conflast, 0, sizeof(chan->conflast));
memset(chan->conflast1, 0, sizeof(chan->conflast1));
@@ -1323,7 +1600,15 @@ static int initialize_channel(struct zt_chan *chan)
chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC);
chan->flags &= ~ZT_FLAG_LINEAR;
-
+ if (chan->curzone) {
+ /* Take cadence from tone zone */
+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
+ } else {
+ /* Do a default */
+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence));
+ chan->ringcadence[0] = chan->starttime;
+ chan->ringcadence[1] = ZT_RINGOFFTIME;
+ }
spin_unlock_irqrestore(&chan->lock, flags);
if (rxgain)
@@ -1777,9 +2062,11 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
if (chan->span && chan->span->rbsbits && !(chan->sig & ZT_SIG_CLEAR)) {
param.rxbits = chan->rxsig;
param.txbits = chan->txsig;
+ param.idlebits = chan->idlebits;
} else {
param.rxbits = -1;
param.txbits = -1;
+ param.idlebits = 0;
}
if (chan->span && (chan->span->rbsbits || chan->span->hooksig) &&
!(chan->sig & ZT_SIG_CLEAR)) {
@@ -1826,6 +2113,9 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
chan->winktime = param.winktime;
chan->flashtime = param.flashtime;
chan->starttime = param.starttime;
+ /* Update ringtime if not using a tone zone */
+ if (!chan->curzone)
+ chan->ringcadence[0] = chan->starttime;
chan->rxwinktime = param.rxwinktime;
chan->rxflashtime = param.rxflashtime;
chan->debouncetime = param.debouncetime;
@@ -1926,6 +2216,35 @@ void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data))
zt_dynamic_ioctl = func;
}
+static void recalc_slaves(struct zt_chan *chan)
+{
+ int x;
+ struct zt_chan *last = chan;
+ /* Makes no sense if you don't have a span */
+ if (!chan->span)
+ return;
+
+#if 0
+ printk("Recalculating slaves on %s\n", chan->name);
+#endif
+
+ /* Link all slaves appropriately */
+ for (x=chan->chanpos;x<chan->span->channels;x++)
+ if (chan->span->chans[x].master == chan) {
+#if 0
+ printk("Channel %s, slave to %s, last is %s, its next will be %d\n",
+ chan->span->chans[x].name, chan->name, last->name, x);
+#endif
+ last->nextslave = x;
+ last = &chan->span->chans[x];
+ }
+ /* Terminate list */
+ last->nextslave = 0;
+#if 0
+ printk("Done Recalculating slaves on %s (last is %s)\n", chan->name, last->name);
+#endif
+}
+
static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
{
/* I/O CTL's for control interface */
@@ -2023,10 +2342,15 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype);
if (chans[ch.chan]->master) {
/* Clear the master channel */
- chans[ch.chan]->master->slavemask &= ~(1 << (chans[ch.chan]->chanpos - 1));
+ recalc_slaves(chans[ch.chan]->master);
+ chans[ch.chan]->nextslave = 0;
}
if (!res) {
chans[ch.chan]->sig = ch.sigtype;
+ if (chans[ch.chan]->sig == ZT_SIG_CAS)
+ chans[ch.chan]->idlebits = ch.idlebits;
+ else
+ chans[ch.chan]->idlebits = 0;
if ((ch.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
/* Set clear channel flag if appropriate */
chans[ch.chan]->flags &= ~ZT_FLAG_AUDIO;
@@ -2052,8 +2376,9 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
chans[ch.chan]->master = newmaster;
/* Note new slave if we are not our own master */
- if (newmaster != chans[ch.chan])
- chans[ch.chan]->master->slavemask |= (1 << (chans[ch.chan]->chanpos - 1));
+ if (newmaster != chans[ch.chan]) {
+ recalc_slaves(chans[ch.chan]->master);
+ }
}
#ifdef CONFIG_ZAPATA_NET
if (!res &&
@@ -2203,6 +2528,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
struct zt_dialoperation tdo;
struct zt_bufferinfo bi;
struct zt_confinfo conf;
+ struct zt_ring_cadence cad;
unsigned int flags;
int i, j, k, rv;
int ret, c;
@@ -2424,7 +2750,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
if ((i < 0) || (i > ZT_MAX_CONF) || (!chans[i])) return(-EINVAL);
if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
conf.chan = i; /* get channel number */
- conf.confno = chans[i]->confn; /* get conference number */
+ conf.confno = chans[i]->confna; /* get conference number */
conf.confmode = chans[i]->confmode; /* get conference mode */
copy_to_user((struct zt_confinfo *) data,&conf,sizeof(conf));
break;
@@ -2446,25 +2772,36 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
/* if taking off of any conf, must have 0 mode */
if ((!conf.confno) && conf.confmode) return(-EINVAL);
+ /* likewise if 0 mode must have no conf */
+ if ((!conf.confmode) && conf.confno) return (-EINVAL);
conf.chan = i; /* return with real channel # */
spin_lock_irqsave(&chan->lock, flags);
- if (conf.confno == -1) {
+ if (conf.confno == -1)
conf.confno = zt_first_empty_conference();
- if (conf.confno < 1) return -EBUSY;
- }
if ((conf.confno < 1) && (conf.confmode)) {
/* No more empty conferences */
spin_unlock_irqrestore(&chan->lock, flags);
return -EBUSY;
}
/* if changing confs, clear last added info */
- if (conf.confno != chans[i]->confn) {
+ if (conf.confno != chans[i]->confna) {
memset(chans[i]->conflast, 0, ZT_MAX_CHUNKSIZE);
memset(chans[i]->conflast1, 0, ZT_MAX_CHUNKSIZE);
memset(chans[i]->conflast2, 0, ZT_MAX_CHUNKSIZE);
}
- chans[i]->confn = conf.confno; /* set conference number */
+ j = chans[i]->confna; /* save old conference number */
+ chans[i]->confna = conf.confno; /* set conference number */
chans[i]->confmode = conf.confmode; /* set conference mode */
+ chans[i]->_confn = 0; /* Clear confn */
+ zt_check_conf(j);
+ zt_check_conf(conf.confno);
+ /* k will be non-zero if in a real conf */
+ k = conf.confmode & (ZT_CONF_CONF | ZT_CONF_CONFANN | ZT_CONF_CONFMON | ZT_CONF_CONFANNMON | ZT_CONF_REALANDPSEUDO);
+ /* if we are going onto a conf */
+ if (conf.confno && k) {
+ /* Get alias */
+ chans[i]->_confn = zt_get_conf_alias(conf.confno);
+ }
copy_to_user((struct zt_confinfo *) data,&conf,sizeof(conf));
spin_unlock_irqrestore(&chan->lock, flags);
break;
@@ -2482,6 +2819,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
{
/* clear all the links */
memset(conf_links,0,sizeof(conf_links));
+ recalc_maxlinks();
spin_unlock_irqrestore(&chan->lock, flags);
break;
}
@@ -2531,12 +2869,13 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
rv = -ENOENT;
}
}
+ recalc_maxlinks();
spin_unlock_irqrestore(&chan->lock, flags);
return(rv);
case ZT_CONFDIAG: /* output diagnostic info to console */
if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
get_user(j,(int *)data); /* get conf # */
- /* loop thru the interesting ones */
+ /* loop thru the interesting ones */
for(i = ((j) ? j : 1); i <= ((j) ? j : ZT_MAX_CONF); i++)
{
c = 0;
@@ -2545,7 +2884,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
/* skip if no pointer */
if (!chans[k]) continue;
/* skip if not in this conf */
- if (chans[k]->confn != i) continue;
+ if (chans[k]->confna != i) continue;
if (!c) printk("Conf #%d:\n",i);
c = 1;
printk("chan %d, mode %x\n",
@@ -2586,6 +2925,23 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
else
chan->flags &= ~ZT_FLAG_LINEAR;
break;
+ case ZT_SETCADENCE:
+ if (data) {
+ /* Use specific ring cadence */
+ if (copy_from_user(&cad, (struct zt_ring_cadence *)data, sizeof(cad)))
+ return -EIO;
+ memcpy(chan->ringcadence, &cad, sizeof(chan->ringcadence));
+ } else {
+ /* Reset to default */
+ if (chan->curzone) {
+ memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
+ } else {
+ memset(chan->ringcadence, 0, sizeof(chan->ringcadence));
+ chan->ringcadence[0] = chan->starttime;
+ chan->ringcadence[1] = ZT_RINGOFFTIME;
+ }
+ }
+ break;
default:
/* Check for common ioctl's and private ones */
rv = zt_common_ioctl(inode, file, cmd, data, unit);
@@ -2729,6 +3085,8 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
tec = chan->ec;
chan->echocancel = j;
chan->ec = ec;
+ 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);
@@ -2742,9 +3100,18 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
echo_can_free(tec);
}
break;
+ case ZT_SETTXBITS:
+ if (chan->sig != ZT_SIG_CAS)
+ return -EINVAL;
+ get_user(j,(int *)data);
+ zt_cas_setbits(chan, j);
+ rv = 0;
+ break;
case ZT_HOOK:
if (chan->flags & ZT_FLAG_CLEAR)
return -EINVAL;
+ if (chan->sig == ZT_SIG_CAS)
+ return -EINVAL;
get_user(j,(int *)data);
if (chan->span->flags & ZT_FLAG_RBS) {
switch (j) {
@@ -2772,12 +3139,8 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
}
if (chan->sig & __ZT_SIG_FXO) {
ret = 0;
- if (chan->curzone) {
- chan->cadencepos = 0;
- ret = chan->curzone->ringcadence[0];
- }
- if (!ret)
- ret = chan->starttime;
+ chan->cadencepos = 0;
+ ret = chan->ringcadence[0];
zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, ret);
} else
zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_START, chan->starttime);
@@ -3029,7 +3392,12 @@ int zt_unregister(struct zt_span *span)
#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
#define CLIP 32635
-static unsigned char __init linear2ulaw(short sample)
+#ifdef CONFIG_CALC_XLAW
+unsigned char
+#else
+static unsigned char __init
+#endif
+__zt_lineartoulaw(short sample)
{
static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
@@ -3069,7 +3437,12 @@ static unsigned char __init linear2ulaw(short sample)
#define AMI_MASK 0x55
-static inline uint8_t linear2alaw (short int linear)
+#ifdef CONFIG_CALC_XLAW
+unsigned char
+#else
+static inline unsigned char __init
+#endif
+__zt_lineartoalaw (short linear)
{
int mask;
int seg;
@@ -3103,7 +3476,7 @@ static inline uint8_t linear2alaw (short int linear)
}
/*- End of function --------------------------------------------------------*/
-static inline short int alaw2linear (uint8_t alaw)
+static inline short int __init alaw2linear (uint8_t alaw)
{
int i;
int seg;
@@ -3138,168 +3511,71 @@ static void __init zt_conv_init(void)
/* Default (0.0 db) gain table */
defgain[i] = i;
}
+#ifndef CONFIG_CALC_XLAW
/* set up the reverse (mu-law) conversion table */
for(i = -32768; i < 32768; i += 4)
{
- __zt_lin2mu[((unsigned short)(short)i) >> 2] = linear2ulaw(i);
- __zt_lin2a[((unsigned short)(short)i) >> 2] = linear2alaw(i);
+ __zt_lin2mu[((unsigned short)(short)i) >> 2] = __zt_lineartoulaw(i);
+ __zt_lin2a[((unsigned short)(short)i) >> 2] = __zt_lineartoalaw(i);
}
+#endif
}
-static inline unsigned char zt_getbuf_byte(struct zt_chan *ss, int pos)
+static inline void zt_process_getaudio_chunk(struct zt_chan *ss, unsigned char *txb)
{
/* We transmit data from our master channel */
struct zt_chan *ms = ss->master;
- /* ulaw-encoded transmit character */
- unsigned char txc;
- /* Buffer we're using */
- unsigned char *buf;
- /* Old buffer number */
- int oldbuf;
/* Linear representation */
- int getlin;
- /* and how about another int */
- int k;
+ short getlin[ZT_CHUNKSIZE], k[ZT_CHUNKSIZE];
+ int x;
- /* Let's pick something to transmit. First source to
- try is our write-out buffer. Always check it first because
- its our 'fast path' for whatever that's worth. */
- if ((ms->outwritebuf > -1) && !ms->txdisable) {
- buf= ms->writebuf[ms->outwritebuf];
- if (ms->flags & ZT_FLAG_HDLC) {
- /* If this is an HDLC channel we only send a byte of
- HDLC. */
- if (ms->txhdlc.bits < 8)
- /* Load a byte of data only if needed */
- fasthdlc_tx_load_nocheck(&ms->txhdlc, buf[ms->writeidx[ms->outwritebuf]++]);
- txc = fasthdlc_tx_run_nocheck(&ms->txhdlc);
- } else {
- txc = buf[ms->writeidx[ms->outwritebuf]++];
- }
- /* Check buffer status */
- if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
- /* We've reached the end of our buffer. Go to the next. */
- oldbuf = ms->outwritebuf;
- /* Clear out write index and such */
- ms->writeidx[oldbuf] = 0;
- ms->writen[oldbuf] = 0;
- ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs;
- if (ms->outwritebuf == ms->inwritebuf) {
- /* Whoopsies, we're run out of buffers. Mark ours
- as -1 and wait for the filler to notify us that
- there is something to write */
- ms->outwritebuf = -1;
- if (ms->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
- wake_up_interruptible(&ms->eventbufq);
- /* If we're only supposed to start when full, disable the transmitter */
- if (ms->txbufpolicy == ZT_POLICY_WHEN_FULL)
- ms->txdisable = 1;
- }
- if (ms->inwritebuf < 0) {
- /* The filler doesn't have a place to put data. Now
- that we're done with this buffer, notify them. */
- ms->inwritebuf = oldbuf;
- }
-/* In the very orignal driver, it was quite well known to me (Jim) that there
-was a possibility that a channel sleeping on a write block needed to
-be potentially woken up EVERY time a buffer was emptied, not just on the first
-one, because if only done on the first one there is a slight timing potential
-of missing the wakeup (between where it senses the (lack of) active condition
-(with interrupts disabled) and where it does the sleep (interrupts enabled)
-in the read or iomux call, etc). That is why the write and iomux calls start
-with an infinite loop that gets broken out of upon an active condition,
-otherwise keeps sleeping and looking. The part in this code got "optimized"
-out in the later versions, and is put back now. */
- if (!(ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) {
- wake_up_interruptible(&ms->writebufq);
- wake_up_interruptible(&ms->sel);
- if (ms->iomask & ZT_IOMUX_WRITE)
- wake_up_interruptible(&ms->eventbufq);
- }
- /* Transmit a flag if this is an HDLC channel */
- if (ms->flags & ZT_FLAG_HDLC)
- fasthdlc_tx_frame_nocheck(&ms->txhdlc);
-#ifdef CONFIG_ZAPATA_NET
- if (ms->flags & ZT_FLAG_NETDEV)
- netif_wake_queue(&ms->hdlcnetdev->netdev.netdev);
-#endif
-#ifdef CONFIG_ZAPATA_PPP
- if (ms->flags & ZT_FLAG_PPP) {
- ppp_output_wakeup(ms->ppp);
- }
-#endif
- }
- } else if (ms->curtone) {
- /* Pick our default value from the next sample of the current tone */
- getlin = zt_tone_nextsample(&ms->ts, ms->curtone);
- txc = ZT_LIN2X(getlin, ms);
- ms->tonep++;
- if (ms->tonep >= ms->curtone->tonesamples) {
- struct zt_tone *last;
- /* Go to the next sample of the tone */
- ms->tonep = 0;
- last = ms->curtone;
- ms->curtone = ms->curtone->next;
- if (!ms->curtone) {
- /* No more tones... Is this dtmf or mf? If so, go to the next digit */
- if (ms->dialing)
- do_dtmf(ms);
- } else {
- if (last != ms->curtone)
- zt_init_tone_state(&ms->ts, ms->curtone);
+ /* Okay, now we've got something to transmit */
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ getlin[x] = ZT_XLAW(txb[x], ms);
+ if (ms->ec) {
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ /* Check for echo cancel disabling tone */
+ if (echo_can_disable_detector_update(&ms->txecdis, getlin[x])) {
+ printk("Disabled echo canceller because of tone (tx)\n");
+ ms->echocancel = 0;
+ kfree(ms->ec);
+ ms->ec = NULL;
+ break;
}
}
- } else if (ms->flags & ZT_FLAG_HDLC) {
- /* Okay, if we're HDLC, then transmit a flag by default */
- if (ms->txhdlc.bits < 8)
- fasthdlc_tx_frame_nocheck(&ms->txhdlc);
- txc = fasthdlc_tx_run_nocheck(&ms->txhdlc);
- } else if (ms->flags & ZT_FLAG_CLEAR) {
- /* Clear channels should idle with 0xff for the sake
- of silly PRI's that care about idle B channels */
- txc = 0xff;
- } else txc = ZT_LIN2X(0, ms); /* Lastly we use silence on telephony channels */
-
- /* Okay, now we've got something to transmit */
- getlin = ZT_XLAW(txc, ms);
- if ((ms->flags & ZT_FLAG_AUDIO) && !ms->confmute && !ms->dialing) {
+ }
+ if (!ms->confmute && !ms->dialing) {
/* Handle conferencing on non-clear channel and non-HDLC channels */
switch(ms->confmode & ZT_CONF_MODE_MASK) {
case ZT_CONF_NORMAL:
/* Do nuffin */
- txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */
/* Add monitored channel */
- if (chans[ms->confn]->flags & ZT_FLAG_PSEUDO) {
- getlin += chans[ms->confn]->getlin[pos];
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(getlin, chans[ms->confna]->getlin);
} else {
- getlin += chans[ms->confn]->putlin[pos];
+ ACSS(getlin, chans[ms->confna]->putlin);
}
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = 32767;
- txc = ZT_LIN2X(getlin, ms);
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
/* Add monitored channel */
- if (chans[ms->confn]->flags & ZT_FLAG_PSEUDO) {
- getlin += chans[ms->confn]->putlin[pos];
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(getlin, chans[ms->confna]->putlin);
} else {
- getlin += chans[ms->confn]->getlin[pos];
+ ACSS(getlin, chans[ms->confna]->getlin);
}
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = 32767;
- txc = ZT_LIN2X(getlin, ms);
+
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */
- getlin += chans[ms->confn]->putlin[pos] +
- chans[ms->confn]->getlin[pos];
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = 32767;
- txc = ZT_LIN2X(getlin, ms);
+ ACSS(getlin, chans[ms->confna]->putlin);
+ ACSS(getlin, chans[ms->confna]->getlin);
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_REALANDPSEUDO:
/* This strange mode takes the transmit buffer and
@@ -3309,24 +3585,23 @@ out in the later versions, and is put back now. */
/* if to talk on conf */
if (ms->confmode & ZT_CONF_PSEUDO_TALKER) {
/* Store temp value */
- k = getlin;
+ memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short));
/* Add conf value */
- k += (int)conf_sums_next[ms->confn][pos];
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
+ ACSS(k, conf_sums_next[ms->_confn]);
/* save last one */
- ms->conflast2[pos] = ms->conflast1[pos];
+ memcpy(ms->conflast2, ms->conflast1, ZT_CHUNKSIZE * sizeof(short));
+ memcpy(ms->conflast1, k, ZT_CHUNKSIZE * sizeof(short));
/* get amount actually added */
- ms->conflast1[pos] = ((short)k) -
- conf_sums_next[ms->confn][pos];
+ SCSS(ms->conflast1, conf_sums_next[ms->_confn]);
/* Really add in new value */
- conf_sums_next[ms->confn][pos] += ms->conflast1[pos];
+ ACSS(conf_sums_next[ms->_confn], ms->conflast1);
} else {
- ms->conflast1[pos] = 0;
- ms->conflast2[pos] = 0;
+ memset(ms->conflast1, 0, ZT_CHUNKSIZE * sizeof(short));
+ memset(ms->conflast2, 0, ZT_CHUNKSIZE * sizeof(short));
}
- getlin = 0;
- txc = 0;
+ memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short));
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
/* fall through to normal conf mode */
case ZT_CONF_CONF: /* Normal conference mode */
if (ms->flags & ZT_FLAG_PSEUDO) /* if pseudo-channel */
@@ -3334,65 +3609,198 @@ out in the later versions, and is put back now. */
/* if to talk on conf */
if (ms->confmode & ZT_CONF_TALKER) {
/* Store temp value */
- k = getlin;
+ memcpy(k, getlin, ZT_CHUNKSIZE * sizeof(short));
/* Add conf value */
- k += (int)conf_sums[ms->confn][pos];
- if (k > 32767) k = 32767;
- if (k < -32767) k = -32767;
+ ACSS(k, conf_sums[ms->_confn]);
/* get amount actually added */
- ms->conflast[pos] = ((short)k) -
- conf_sums[ms->confn][pos];
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums[ms->_confn]);
/* Really add in new value */
- conf_sums[ms->confn][pos] += ms->conflast[pos];
- } else ms->conflast[pos] = 0;
- getlin = ms->getlin[pos];
- txc = 0;
+ ACSS(conf_sums[ms->_confn], ms->conflast);
+ } else memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ memcpy(getlin, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
break;
}
/* fall through */
case ZT_CONF_CONFMON: /* Conference monitor mode */
if (ms->confmode & ZT_CONF_LISTENER) {
/* Subtract out last sample written to conf */
- getlin -= ms->conflast[pos];
+ SCSS(getlin, ms->conflast);
/* Add in conference */
- getlin += conf_sums[ms->confn][pos];
+ ACSS(getlin, conf_sums[ms->_confn]);
}
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = 32767;
- txc = ZT_LIN2X(getlin, ms);
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
break;
case ZT_CONF_CONFANN:
case ZT_CONF_CONFANNMON:
/* First, add tx buffer to conf */
- getlin += conf_sums_next[ms->confn][pos];
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = -32767;
- conf_sums_next[ms->confn][pos] = (short)getlin;
+ ACSS(conf_sums_next[ms->_confn], getlin);
/* Start with silence */
- getlin = 0;
+ memset(getlin, 0, ZT_CHUNKSIZE * sizeof(short));
/* If a listener on the conf... */
if (ms->confmode & ZT_CONF_LISTENER) {
/* Subtract last value written */
- getlin -= ms->conflast[pos];
+ SCSS(getlin, ms->conflast);
/* Add in conf */
- getlin += conf_sums[ms->confn][pos];
+ ACSS(getlin, conf_sums[ms->_confn]);
}
- /* Clip */
- if (getlin > 32767) getlin = 32767;
- if (getlin < -32767) getlin = -32767;
- txc = ZT_LIN2X(getlin, ms);
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ZT_LIN2X(getlin[x], ms);
break;
}
}
- if (ms->confmute) txc = 0x7f;
+ if (ms->confmute) {
+ txb[0] = ZT_LIN2X(0, ms);
+ memset(txb + 1, txb[0], ZT_CHUNKSIZE - 1);
+ }
/* save value from last chunk */
- ms->getlin_lastchunk[pos] = ms->getlin[pos];
+ memcpy(ms->getlin_lastchunk, ms->getlin, ZT_CHUNKSIZE * sizeof(short));
/* save value from current */
- ms->getlin[pos] = getlin;
- /* This is what to send */
- return txc;
+ memcpy(ms->getlin, getlin, ZT_CHUNKSIZE * sizeof(short));
+ /* This is what to send (after having applied gain) */
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ txb[x] = ms->txgain[txb[x]];
+}
+
+static inline void zt_getbuf_chunk(struct zt_chan *ss, unsigned char *txb)
+{
+ /* We transmit data from our master channel */
+ struct zt_chan *ms = ss->master;
+ /* Buffer we're using */
+ unsigned char *buf;
+ /* Old buffer number */
+ int oldbuf;
+ /* Linear representation */
+ int getlin;
+ /* How many bytes we need to process */
+ int bytes = ZT_CHUNKSIZE, left;
+ int x;
+
+ /* Let's pick something to transmit. First source to
+ try is our write-out buffer. Always check it first because
+ its our 'fast path' for whatever that's worth. */
+ while(bytes) {
+ if ((ms->outwritebuf > -1) && !ms->txdisable) {
+ buf= ms->writebuf[ms->outwritebuf];
+ left = ms->writen[ms->outwritebuf] - ms->writeidx[ms->outwritebuf];
+ if (left > bytes)
+ left = bytes;
+ if (ms->flags & ZT_FLAG_HDLC) {
+ /* If this is an HDLC channel we only send a byte of
+ HDLC. */
+ for(x=0;x<left;x++) {
+ if (ms->txhdlc.bits < 8)
+ /* Load a byte of data only if needed */
+ fasthdlc_tx_load_nocheck(&ms->txhdlc, buf[ms->writeidx[ms->outwritebuf]++]);
+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ }
+ bytes -= left;
+ } else {
+ memcpy(txb, buf + ms->writeidx[ms->outwritebuf], left);
+ ms->writeidx[ms->outwritebuf]+=left;
+ txb += left;
+ bytes -= left;
+ }
+ /* Check buffer status */
+ if (ms->writeidx[ms->outwritebuf] >= ms->writen[ms->outwritebuf]) {
+ /* We've reached the end of our buffer. Go to the next. */
+ oldbuf = ms->outwritebuf;
+ /* Clear out write index and such */
+ ms->writeidx[oldbuf] = 0;
+ ms->writen[oldbuf] = 0;
+ ms->outwritebuf = (ms->outwritebuf + 1) % ms->numbufs;
+ if (ms->outwritebuf == ms->inwritebuf) {
+ /* Whoopsies, we're run out of buffers. Mark ours
+ as -1 and wait for the filler to notify us that
+ there is something to write */
+ ms->outwritebuf = -1;
+ if (ms->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
+ wake_up_interruptible(&ms->eventbufq);
+ /* If we're only supposed to start when full, disable the transmitter */
+ if (ms->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ms->txdisable = 1;
+ }
+ if (ms->inwritebuf < 0) {
+ /* The filler doesn't have a place to put data. Now
+ that we're done with this buffer, notify them. */
+ ms->inwritebuf = oldbuf;
+ }
+/* In the very orignal driver, it was quite well known to me (Jim) that there
+was a possibility that a channel sleeping on a write block needed to
+be potentially woken up EVERY time a buffer was emptied, not just on the first
+one, because if only done on the first one there is a slight timing potential
+of missing the wakeup (between where it senses the (lack of) active condition
+(with interrupts disabled) and where it does the sleep (interrupts enabled)
+in the read or iomux call, etc). That is why the write and iomux calls start
+with an infinite loop that gets broken out of upon an active condition,
+otherwise keeps sleeping and looking. The part in this code got "optimized"
+out in the later versions, and is put back now. */
+ if (!(ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) {
+ wake_up_interruptible(&ms->writebufq);
+ wake_up_interruptible(&ms->sel);
+ if (ms->iomask & ZT_IOMUX_WRITE)
+ wake_up_interruptible(&ms->eventbufq);
+ }
+ /* Transmit a flag if this is an HDLC channel */
+ if (ms->flags & ZT_FLAG_HDLC)
+ fasthdlc_tx_frame_nocheck(&ms->txhdlc);
+#ifdef CONFIG_ZAPATA_NET
+ if (ms->flags & ZT_FLAG_NETDEV)
+ netif_wake_queue(&ms->hdlcnetdev->netdev.netdev);
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (ms->flags & ZT_FLAG_PPP) {
+ ppp_output_wakeup(ms->ppp);
+ }
+#endif
+ }
+ } else if (ms->curtone && !(ms->flags & ZT_FLAG_PSEUDO)) {
+ left = ms->curtone->tonesamples - ms->tonep;
+ if (left > bytes)
+ left = bytes;
+ for (x=0;x<left;x++) {
+ /* Pick our default value from the next sample of the current tone */
+ getlin = zt_tone_nextsample(&ms->ts, ms->curtone);
+ *(txb++) = ZT_LIN2X(getlin, ms);
+ }
+ ms->tonep+=left;
+ bytes -= left;
+ if (ms->tonep >= ms->curtone->tonesamples) {
+ struct zt_tone *last;
+ /* Go to the next sample of the tone */
+ ms->tonep = 0;
+ last = ms->curtone;
+ ms->curtone = ms->curtone->next;
+ if (!ms->curtone) {
+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */
+ if (ms->dialing)
+ do_dtmf(ms);
+ } else {
+ if (last != ms->curtone)
+ zt_init_tone_state(&ms->ts, ms->curtone);
+ }
+ }
+ } else if (ms->flags & ZT_FLAG_HDLC) {
+ for (x=0;x<bytes;x++) {
+ /* Okay, if we're HDLC, then transmit a flag by default */
+ if (ms->txhdlc.bits < 8)
+ fasthdlc_tx_frame_nocheck(&ms->txhdlc);
+ *(txb++) = fasthdlc_tx_run_nocheck(&ms->txhdlc);
+ }
+ bytes = 0;
+ } else if (ms->flags & ZT_FLAG_CLEAR) {
+ /* Clear channels should idle with 0xff for the sake
+ of silly PRI's that care about idle B channels */
+ memset(txb, 0xff, bytes);
+ bytes = 0;
+ } else {
+ 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)
@@ -3424,38 +3832,32 @@ static inline void rbs_otimer_expire(struct zt_chan *chan)
switch(chan->txstate) {
case ZT_TXSTATE_RINGOFF:
/* Turn on the ringer now that the silent time has passed */
- if (chan->curzone) {
- ++chan->cadencepos;
- if (chan->cadencepos >= ZT_MAX_CADENCE)
- chan->cadencepos = 0;
- len = chan->curzone->ringcadence[chan->cadencepos];
-
- if (!len) {
- chan->cadencepos = 0;
- len = chan->curzone->ringcadence[chan->cadencepos];
- }
+ ++chan->cadencepos;
+ if (chan->cadencepos >= ZT_MAX_CADENCE)
+ chan->cadencepos = 0;
+ len = chan->ringcadence[chan->cadencepos];
+
+ if (!len) {
+ chan->cadencepos = 0;
+ len = chan->ringcadence[chan->cadencepos];
+ }
- } else
- len = chan->starttime;
zt_rbs_sethook(chan, ZT_TXSIG_START, ZT_TXSTATE_RINGON, len);
qevent(chan, ZT_EVENT_RINGERON);
break;
case ZT_TXSTATE_RINGON:
/* Turn off the ringer now that the loud time has passed */
- if (chan->curzone) {
- ++chan->cadencepos;
- if (chan->cadencepos >= ZT_MAX_CADENCE)
- chan->cadencepos = 0;
- len = chan->curzone->ringcadence[chan->cadencepos];
+ ++chan->cadencepos;
+ if (chan->cadencepos >= ZT_MAX_CADENCE)
+ chan->cadencepos = 0;
+ len = chan->ringcadence[chan->cadencepos];
- if (!len) {
- chan->cadencepos = 0;
- len = chan->curzone->ringcadence[chan->cadencepos];
- }
+ if (!len) {
+ chan->cadencepos = 0;
+ len = chan->curzone->ringcadence[chan->cadencepos];
+ }
- } else
- len = ZT_RINGOFFTIME;
zt_rbs_sethook(chan, ZT_TXSIG_OFFHOOK, ZT_TXSTATE_RINGOFF, len);
qevent(chan, ZT_EVENT_RINGEROFF);
break;
@@ -3679,163 +4081,71 @@ void zt_rbsbits(struct zt_chan *chan, int cursig)
zt_hooksig_pvt(chan, ZT_RXSIG_OFFHOOK);
}
break;
- default:
+ case ZT_SIG_CAS:
+ /* send event that something changed */
+ qevent(chan, ZT_EVENT_BITSCHANGED);
+ break;
+
+ default:
break;
}
/* Keep track of signalling for next time */
chan->rxsig = cursig;
}
-#if 0
-
-void zt_rbsbits(struct zt_chan *chan, int cursig)
+void zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
{
- /* if A bit has changed */
- if ((chan->rxsig & ZT_ABIT) != (cursig & ZT_ABIT))
- {
- switch(chan->sig)
- {
- case ZT_SIG_EM: /* E and M */
- if (cursig & ZT_ABIT) /* went off hook */
- {
- /* set wink timer */
- chan->itimer = chan->rxwinktime * 8;
- }
- else /* went on hook */
- {
- if (chan->itimer)
- qevent(chan,ZT_EVENT_WINKFLASH);
- else
- {
- qevent(chan,ZT_EVENT_ONHOOK);
- chan->gotgs = 0;
- }
- chan->itimer = 0;
- }
- break;
- case ZT_SIG_FXSKS: /* FXS Kewlstart */
- /* ignore a bit poopy if loop no closed and stable */
- if (chan->txstate != ZT_TXSTATE_OFFHOOK) break;
- /* fall through intentionally */
- case ZT_SIG_FXSGS: /* FXS Groundstart */
- if (cursig & ZT_ABIT) /* if went on hook */
- {
- /* if not during offhook debounce time */
- if (chan->txstate != ZT_TXSTATE_DEBOUNCE)
- {
- chan->gotgs = 0;
- qevent(chan,ZT_EVENT_ONHOOK);
- }
- }
- break;
- case ZT_SIG_FXOLS: /* FXO Loopstart */
- case ZT_SIG_FXOGS: /* FXO Groundstart */
- case ZT_SIG_FXOKS: /* FXO Kewlstart */
- if (cursig & ZT_ABIT) /* if went off hook */
- {
- /* if asserting ring, stop it */
- if (chan->txstate == ZT_TXSTATE_START)
- {
- zt_rbs_sethook(chan,ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME);
- }
- if (chan->itimer) /* if timer still running */
- qevent(chan,ZT_EVENT_WINKFLASH);
- else
- {
- /* if havent got GS detect */
- if (!chan->gotgs)
- {
- qevent(chan,ZT_EVENT_RINGOFFHOOK);
- chan->gotgs = 1;
- chan->itimer = 0;
- }
- }
- chan->itimer = 0;
- }
- if (!(cursig & ZT_ABIT)) /* if went on hook */
- {
- /* if not during offhook debounce time */
- if ((chan->txstate != ZT_TXSTATE_DEBOUNCE) &&
- (chan->txstate != ZT_TXSTATE_KEWL) &&
- (chan->txstate != ZT_TXSTATE_AFTERKEWL))
- {
- chan->itimer = chan->rxflashtime * 8;
- }
- }
- break;
- default:
- break;
- }
- }
- /* if B bit has changed */
- if ((chan->rxsig & ZT_BBIT) != (cursig & ZT_BBIT))
- {
- switch(chan->sig)
- {
- case ZT_SIG_FXSLS: /* FXS Loopstart */
- case ZT_SIG_FXSGS: /* FXS Groundstart */
- case ZT_SIG_FXSKS: /* FXS Kewlstart */
- if (cursig & ZT_BBIT) /* if trailing edge of ring */
- qevent(chan,ZT_EVENT_RINGOFFHOOK);
- break;
- case ZT_SIG_FXOGS: /* FXO Groundstart */
- if (!(cursig & ZT_BBIT)) /* if ground detected */
- {
- /* if havent got gs, report it */
- if (!chan->gotgs)
- {
- qevent(chan,ZT_EVENT_RINGOFFHOOK);
- chan->gotgs = 1;
- }
- }
- break;
- default:
- break;
- }
- }
- /* Keep track of signalling for next time */
- chan->rxsig = cursig;
+ short rxlin;
+ int x;
+ /* Perform echo cancellation on a chunk if necessary */
+ if (!ss->ec)
+ return;
+ 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);
+ }
}
-#endif
-
-static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos)
+static inline void zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char *rxb)
{
/* We transmit data from our master channel */
struct zt_chan *ms = ss->master;
- /* Our receive buffer */
- unsigned char *buf;
/* Linear version of received data */
- int putlin,k;
-#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
- /* SKB for receiving network stuff */
- struct sk_buff *skb=NULL;
-#endif
- int oldbuf;
- int eof=0;
- int abort=0;
- int res;
-
- if (ms->dialing) ms->afterdialingtimer = ZT_CHUNKSIZE * 50;
+ short putlin[ZT_CHUNKSIZE],k[ZT_CHUNKSIZE];
+ int x;
+
+ if (ms->dialing) ms->afterdialingtimer = 50;
else if (ms->afterdialingtimer) ms->afterdialingtimer--;
- if (ms->afterdialingtimer) rxc = 0x7f; /* receive as silence if dialing */
+ if (ms->afterdialingtimer) {
+ /* Be careful since memset is likely a macro */
+ rxb[0] = ZT_LIN2X(0, ms);
+ memset(&rxb[1], rxb[0], ZT_CHUNKSIZE - 1); /* receive as silence if dialing */
+ }
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ rxb[x] = ms->rxgain[rxb[x]];
+ putlin[x] = ZT_XLAW(rxb[x], ms);
+ }
+
if (ms->ec) {
- putlin = ZT_XLAW(rxc, ms);
- putlin = echo_can_update(ms->ec, ms->getlin[pos], putlin);
- rxc = ZT_LIN2X((int)putlin, ms);
+ for (x=0;x<ZT_CHUNKSIZE;x++) {
+ if (echo_can_disable_detector_update(&ms->rxecdis, putlin[x])) {
+ printk("Disabled echo canceller because of tone (rx)\n");
+ ms->echocancel = 0;
+ kfree(ms->ec);
+ ms->ec = NULL;
+ break;
+ }
+ }
}
- /* Apply gain if appropriate */
- if (ms->flags & ZT_FLAG_AUDIO)
- rxc = ms->rxgain[rxc];
- putlin = ZT_XLAW(rxc, ms);
-
- if (!(ms->flags & ZT_FLAG_PSEUDO))
- ms->putlin[pos] = putlin;
+ if (!(ms->flags & ZT_FLAG_PSEUDO)) {
+ memcpy(ms->putlin, putlin, ZT_CHUNKSIZE * sizeof(short));
+ }
/* Take the rxc, twiddle it for conferencing if appropriate and put it
back */
- if ((ms->flags & ZT_FLAG_AUDIO) && !ms->confmute && !ms->afterdialingtimer) {
+ if (!ms->confmute && !ms->afterdialingtimer) {
switch(ms->confmode & ZT_CONF_MODE_MASK) {
case ZT_CONF_NORMAL: /* Normal mode */
/* Do nothing. rx goes output */
@@ -3844,236 +4154,266 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* if not a pseudo-channel, ignore */
if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
/* Add monitored channel */
- if (chans[ms->confn]->flags & ZT_FLAG_PSEUDO) {
- putlin += chans[ms->confn]->getlin[pos];
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(putlin, chans[ms->confna]->getlin);
} else {
- putlin += chans[ms->confn]->putlin[pos];
+ ACSS(putlin, chans[ms->confna]->putlin);
}
- /* Clip */
- if (putlin > 32767) putlin = 32767;
- if (putlin < -32767) putlin = 32767;
- rxc = ZT_LIN2X(putlin, ms);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
break;
case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
/* if not a pseudo-channel, ignore */
if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
/* Add monitored channel */
- if (chans[ms->confn]->flags & ZT_FLAG_PSEUDO) {
- putlin += chans[ms->confn]->putlin[pos];
+ if (chans[ms->confna]->flags & ZT_FLAG_PSEUDO) {
+ ACSS(putlin, chans[ms->confna]->putlin);
} else {
- putlin += chans[ms->confn]->getlin[pos];
+ ACSS(putlin, chans[ms->confna]->getlin);
}
- /* Clip */
- if (putlin > 32767) putlin = 32767;
- if (putlin < -32767) putlin = 32767;
- rxc = ZT_LIN2X(putlin, ms);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
break;
case ZT_CONF_MONITORBOTH: /* Monitor a channel's tx and rx mode */
/* if not a pseudo-channel, ignore */
if (!(ms->flags & ZT_FLAG_PSEUDO)) break;
- putlin += chans[ms->confn]->putlin[pos] +
- chans[ms->confn]->getlin[pos];
- /* Clip */
- if (putlin > 32767) putlin = 32767;
- if (putlin < -32767) putlin = 32767;
- rxc = ZT_LIN2X(putlin, ms);
+ /* Note: Technically, saturation should be done at
+ the end of the whole addition, but for performance
+ reasons, we don't do that. Besides, it only matters
+ when you're so loud you're clipping anyway */
+ ACSS(putlin, chans[ms->confna]->getlin);
+ ACSS(putlin, chans[ms->confna]->putlin);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
break;
case ZT_CONF_REALANDPSEUDO:
/* do normal conf mode processing */
if (ms->confmode & ZT_CONF_TALKER) {
/* Store temp value */
- k = putlin;
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
/* Add conf value */
- k += (int)conf_sums_next[ms->confn][pos];
- if (k > 32767)
- k = 32767;
- if (k < -32767)
- k = -32767;
+ ACSS(k, conf_sums_next[ms->_confn]);
/* get amount actually added */
- ms->conflast[pos] = ((short)k) -
- conf_sums_next[ms->confn][pos];
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums_next[ms->_confn]);
/* Really add in new value */
- conf_sums_next[ms->confn][pos] += ms->conflast[pos];
- } else ms->conflast[pos] = 0;
+ ACSS(conf_sums_next[ms->_confn], ms->conflast);
+ } else memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
/* do the pseudo-channel part processing */
- putlin = 0;
+ memset(putlin, 0, ZT_CHUNKSIZE * sizeof(short));
if (ms->confmode & ZT_CONF_PSEUDO_LISTENER) {
/* Subtract out previous last sample written to conf */
- putlin -= ms->conflast2[pos];
+ SCSS(putlin, ms->conflast2);
/* Add in conference */
- putlin += conf_sums[ms->confn][pos];
+ ACSS(putlin, conf_sums[ms->_confn]);
}
- /* Clip */
- if (putlin > 32767) putlin = 32767;
- if (putlin < -32767) putlin = 32767;
- rxc = ZT_LIN2X(putlin, ms);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
break;
case ZT_CONF_CONF: /* Normal conference mode */
if (ms->flags & ZT_FLAG_PSEUDO) /* if a pseudo-channel */
{
if (ms->confmode & ZT_CONF_LISTENER) {
/* Subtract out last sample written to conf */
- putlin -= ms->conflast[pos];
+ SCSS(putlin, ms->conflast);
/* Add in conference */
- putlin += conf_sums[ms->confn][pos];
+ ACSS(putlin, conf_sums[ms->_confn]);
}
- /* Clip */
- if (putlin > 32767) putlin = 32767;
- if (putlin < -32767) putlin = 32767;
- rxc = ZT_LIN2X(putlin, ss);
- ss->getlin[pos] = ZT_XLAW(rxc, ss);
+ /* Convert back */
+ for(x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X(putlin[x], ms);
+ memcpy(ss->getlin, putlin, ZT_CHUNKSIZE * sizeof(short));
break;
}
/* fall through */
case ZT_CONF_CONFANN: /* Conference with announce */
if (ms->confmode & ZT_CONF_TALKER) {
/* Store temp value */
- k = putlin;
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
/* Add conf value */
- k += (int)conf_sums_next[ms->confn][pos];
- if (k > 32767)
- k = 32767;
- if (k < -32767)
- k = -32767;
+ ACSS(k, conf_sums_next[ms->_confn]);
/* get amount actually added */
- ms->conflast[pos] = ((short)k) -
- conf_sums_next[ms->confn][pos];
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums_next[ms->_confn]);
/* Really add in new value */
- conf_sums_next[ms->confn][pos] += ms->conflast[pos];
- } else ms->conflast[pos] = 0;
+ ACSS(conf_sums_next[ms->_confn], ms->conflast);
+ } else
+ memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
/* rxc unmodified */
break;
case ZT_CONF_CONFMON:
case ZT_CONF_CONFANNMON:
if (ms->confmode & ZT_CONF_TALKER) {
/* Store temp value */
- k = putlin;
+ memcpy(k, putlin, ZT_CHUNKSIZE * sizeof(short));
/* Subtract last value */
- conf_sums[ms->confn][pos] -= ms->conflast[pos];
+ SCSS(conf_sums[ms->_confn], ms->conflast);
/* Add conf value */
- k += (int)conf_sums[ms->confn][pos];
- if (k > 32767)
- k = 32767;
- if (k < -32767)
- k = -32767;
+ ACSS(k, conf_sums[ms->_confn]);
/* get amount actually added */
- ms->conflast[pos] = ((short)k) -
- conf_sums[ms->confn][pos];
+ memcpy(ms->conflast, k, ZT_CHUNKSIZE * sizeof(short));
+ SCSS(ms->conflast, conf_sums[ms->_confn]);
/* Really add in new value */
- conf_sums[ms->confn][pos] += ms->conflast[pos];
- } else ms->conflast[pos] = 0;
- rxc = ZT_LIN2X((int)conf_sums_prev[ms->confn][pos], ms);
+ ACSS(conf_sums[ms->_confn], ms->conflast);
+ } else
+ memset(ms->conflast, 0, ZT_CHUNKSIZE * sizeof(short));
+ for (x=0;x<ZT_CHUNKSIZE;x++)
+ rxb[x] = ZT_LIN2X((int)conf_sums_prev[ms->_confn][x], ms);
break;
}
}
-
- /* Next, figure out if we've got a buffer to receive into */
- if (ms->inreadbuf > -1) {
- /* Read into the current buffer */
- buf = ms->readbuf[ms->inreadbuf];
- if (ms->flags & ZT_FLAG_HDLC) {
- /* Handle HDLC deframing */
- fasthdlc_rx_load_nocheck(&ms->rxhdlc, rxc);
- res = fasthdlc_rx_run(&ms->rxhdlc);
- /* Return immediately if there is nothing to receive */
- if (res & RETURN_EMPTY_FLAG)
- return;
- else if (res & RETURN_COMPLETE_FLAG) {
- /* Only count this if it's a non-empty frame */
- if (ms->readidx[ms->inreadbuf]) {
- if ((ms->flags & ZT_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) {
- abort = ZT_EVENT_BADFCS;
- } else
- eof=1;
+}
+
+static inline void zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
+{
+ /* We transmit data from our master channel */
+ struct zt_chan *ms = ss->master;
+ /* Our receive buffer */
+ unsigned char *buf;
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+ /* SKB for receiving network stuff */
+ struct sk_buff *skb=NULL;
+#endif
+ int oldbuf;
+ int eof=0;
+ int abort=0;
+ int res;
+ int left, x;
+
+ int bytes = ZT_CHUNKSIZE;
+
+ while(bytes) {
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+ skb = NULL;
+ abort = 0;
+ eof = 0;
+#endif
+ /* Next, figure out if we've got a buffer to receive into */
+ if (ms->inreadbuf > -1) {
+ /* Read into the current buffer */
+ buf = ms->readbuf[ms->inreadbuf];
+ left = ms->blocksize - ms->readidx[ms->inreadbuf];
+ if (left > bytes)
+ left = bytes;
+ if (ms->flags & ZT_FLAG_HDLC) {
+ for (x=0;x<left;x++) {
+ /* Handle HDLC deframing */
+ fasthdlc_rx_load_nocheck(&ms->rxhdlc, *(rxb++));
+ bytes--;
+ res = fasthdlc_rx_run(&ms->rxhdlc);
+ /* If there is nothing there, continue */
+ if (res & RETURN_EMPTY_FLAG)
+ continue;
+ else if (res & RETURN_COMPLETE_FLAG) {
+ /* Only count this if it's a non-empty frame */
+ if (ms->readidx[ms->inreadbuf]) {
+ if ((ms->flags & ZT_FLAG_FCS) && (ms->infcs != PPP_GOODFCS)) {
+ abort = ZT_EVENT_BADFCS;
+ } else
+ eof=1;
+ break;
+ }
+ continue;
+ } else if (res & RETURN_DISCARD_FLAG) {
+ /* This could be someone idling with
+ "idle" instead of "flag" */
+ if (!ms->readidx[ms->inreadbuf])
+ continue;
+ abort = ZT_EVENT_ABORT;
+ break;
+ } else {
+ unsigned char rxc;
+ rxc = res;
+ ms->infcs = PPP_FCS(ms->infcs, rxc);
+ buf[ms->readidx[ms->inreadbuf]++] = rxc;
+ /* Pay attention to the possibility of an overrun */
+ if (ms->readidx[ms->inreadbuf] >= ms->blocksize) {
+ if (!ss->span->alarms)
+ printk(KERN_WARNING "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name);
+ abort=ZT_EVENT_OVERRUN;
+ /* Force the HDLC state back to frame-search mode */
+ ms->rxhdlc.state = 0;
+ ms->rxhdlc.bits = 0;
+ ms->readidx[ms->inreadbuf]=0;
+ break;
+ }
+ }
}
- } else if (res & RETURN_DISCARD_FLAG) {
- /* This could be someone idling with
- "idle" instead of "flag" */
- if (!ms->readidx[ms->inreadbuf])
- return;
- abort = ZT_EVENT_ABORT;
} else {
- rxc = res;
- ms->infcs = PPP_FCS(ms->infcs, rxc);
- buf[ms->readidx[ms->inreadbuf]++] = rxc;
- /* Pay attention to the possibility of an overrun */
- if (ms->readidx[ms->inreadbuf] >= ms->blocksize) {
- if (!ss->span->alarms)
- printk(KERN_WARNING "HDLC Receiver overrun on channel %s (master=%s)\n", ss->name, ss->master->name);
- abort=ZT_EVENT_OVERRUN;
- /* Force the HDLC state back to frame-search mode */
- ms->rxhdlc.state = 0;
- ms->rxhdlc.bits = 0;
- ms->readidx[ms->inreadbuf]=0;
- }
+ /* Not HDLC */
+ memcpy(buf + ms->readidx[ms->inreadbuf], rxb, left);
+ rxb += left;
+ ms->readidx[ms->inreadbuf] += left;
+ bytes -= left;
+ /* End of frame is decided by block size of 'N' */
+ eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize);
}
- } else {
- buf[ms->readidx[ms->inreadbuf]++] = rxc;
- /* End of frame is decided by block size of 'N' */
- eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize);
- }
- if (eof) {
- /* Finished with this buffer, try another. */
- oldbuf = ms->inreadbuf;
- ms->infcs = PPP_INITFCS;
- ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf];
+ if (eof) {
+ /* Finished with this buffer, try another. */
+ oldbuf = ms->inreadbuf;
+ ms->infcs = PPP_INITFCS;
+ ms->readn[ms->inreadbuf] = ms->readidx[ms->inreadbuf];
#if 0
- printk("EOF, len is %d\n", ms->readn[ms->inreadbuf]);
+ printk("EOF, len is %d\n", ms->readn[ms->inreadbuf]);
#endif
#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
- if (ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP)) {
- /* Our network receiver logic is MUCH
- different. We actually only us a single
- buffer */
- if (ms->readn[ms->inreadbuf] > 1) {
- /* Drop the FCS */
- ms->readn[ms->inreadbuf] -= 2;
- /* Allocate an SKB */
- skb = dev_alloc_skb(ms->readn[ms->inreadbuf]);
- if (skb) {
- /* XXX Get rid of this memcpy XXX */
- memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]);
- skb_put(skb, ms->readn[ms->inreadbuf]);
- } else {
+ if (ms->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP)) {
+ /* Our network receiver logic is MUCH
+ different. We actually only us a single
+ buffer */
+ if (ms->readn[ms->inreadbuf] > 1) {
+ /* Drop the FCS */
+ ms->readn[ms->inreadbuf] -= 2;
+ /* Allocate an SKB */
+ skb = dev_alloc_skb(ms->readn[ms->inreadbuf]);
+ if (skb) {
+ /* XXX Get rid of this memcpy XXX */
+ memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]);
+ skb_put(skb, ms->readn[ms->inreadbuf]);
+ } else {
#ifdef CONFIG_ZAPATA_NET
- if (ms->flags & ZT_FLAG_NETDEV)
- ms->hdlcnetdev->netdev.stats.rx_dropped++;
+ if (ms->flags & ZT_FLAG_NETDEV)
+ ms->hdlcnetdev->netdev.stats.rx_dropped++;
#endif
#ifdef CONFIG_ZAPATA_PPP
- if (ms->flags & ZT_FLAG_PPP) {
- printk("Would call ppp_input_error\n");
+ if (ms->flags & ZT_FLAG_PPP) {
+ printk("Would call ppp_input_error\n");
#if 1
- ppp_input_error(ms->ppp, 0);
+ ppp_input_error(ms->ppp, 0);
#endif
- }
+ }
#endif
#if 1
- printk("Memory squeeze, dropped one\n");
+ printk("Memory squeeze, dropped one\n");
#endif
+ }
}
- }
- /* We don't cycle through buffers, just
- reuse the same one */
- ms->readn[ms->inreadbuf] = 0;
- ms->readidx[ms->inreadbuf] = 0;
- } else
+ /* We don't cycle through buffers, just
+ reuse the same one */
+ ms->readn[ms->inreadbuf] = 0;
+ ms->readidx[ms->inreadbuf] = 0;
+ } else
#endif
- {
- ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs;
- if (ms->inreadbuf == ms->outreadbuf) {
- /* Whoops, we're full, and have no where else
- to store into at the moment. We'll drop it
- until there's a buffer available */
+ {
+ ms->inreadbuf = (ms->inreadbuf + 1) % ms->numbufs;
+ if (ms->inreadbuf == ms->outreadbuf) {
+ /* Whoops, we're full, and have no where else
+ to store into at the moment. We'll drop it
+ until there's a buffer available */
#if 0
- printk("Out of storage space\n");
+ printk("Out of storage space\n");
#endif
- ms->inreadbuf = -1;
- /* Enable the receiver in case they've got POLICY_WHEN_FULL */
- ms->rxdisable = 0;
- }
- if (ms->outreadbuf < 0) { /* start out buffer if not already */
- ms->outreadbuf = oldbuf;
- }
+ ms->inreadbuf = -1;
+ /* Enable the receiver in case they've got POLICY_WHEN_FULL */
+ ms->rxdisable = 0;
+ }
+ if (ms->outreadbuf < 0) { /* start out buffer if not already */
+ ms->outreadbuf = oldbuf;
+ }
/* In the very orignal driver, it was quite well known to me (Jim) that there
was a possibility that a channel sleeping on a receive block needed to
be potentially woken up EVERY time a buffer was filled, not just on the first
@@ -4084,69 +4424,71 @@ in the read or iomux call, etc). That is why the read and iomux calls start
with an infinite loop that gets broken out of upon an active condition,
otherwise keeps sleeping and looking. The part in this code got "optimized"
out in the later versions, and is put back now. */
- if (!ms->rxdisable) { /* if receiver enabled */
- /* Notify a blocked reader that there is data available
- to be read, unless we're waiting for it to be full */
+ if (!ms->rxdisable) { /* if receiver enabled */
+ /* Notify a blocked reader that there is data available
+ to be read, unless we're waiting for it to be full */
#if 0
- printk("Notifying reader data in block %d\n", oldbuf);
+ printk("Notifying reader data in block %d\n", oldbuf);
#endif
- wake_up_interruptible(&ms->readbufq);
- wake_up_interruptible(&ms->sel);
- if (ms->iomask & ZT_IOMUX_READ)
- wake_up_interruptible(&ms->eventbufq);
+ wake_up_interruptible(&ms->readbufq);
+ wake_up_interruptible(&ms->sel);
+ if (ms->iomask & ZT_IOMUX_READ)
+ wake_up_interruptible(&ms->eventbufq);
+ }
}
}
- }
- if (abort) {
- /* Start over reading frame */
- ms->readidx[ms->inreadbuf] = 0;
- ms->infcs = PPP_INITFCS;
+ if (abort) {
+ /* Start over reading frame */
+ ms->readidx[ms->inreadbuf] = 0;
+ ms->infcs = PPP_INITFCS;
#ifdef CONFIG_ZAPATA_NET
- if (ms->flags & ZT_FLAG_NETDEV) {
- ms->hdlcnetdev->netdev.stats.rx_errors++;
- if (abort == ZT_EVENT_OVERRUN)
- ms->hdlcnetdev->netdev.stats.rx_over_errors++;
- if (abort == ZT_EVENT_BADFCS)
- ms->hdlcnetdev->netdev.stats.rx_crc_errors++;
- if (abort == ZT_EVENT_ABORT)
- ms->hdlcnetdev->netdev.stats.rx_frame_errors++;
- } else
+ if (ms->flags & ZT_FLAG_NETDEV) {
+ ms->hdlcnetdev->netdev.stats.rx_errors++;
+ if (abort == ZT_EVENT_OVERRUN)
+ ms->hdlcnetdev->netdev.stats.rx_over_errors++;
+ if (abort == ZT_EVENT_BADFCS)
+ ms->hdlcnetdev->netdev.stats.rx_crc_errors++;
+ if (abort == ZT_EVENT_ABORT)
+ ms->hdlcnetdev->netdev.stats.rx_frame_errors++;
+ } else
#endif
#ifdef CONFIG_ZAPATA_PPP
- if (ms->flags & ZT_FLAG_PPP) {
- ppp_input_error(ms->ppp, 0);
- } else
+ if (ms->flags & ZT_FLAG_PPP) {
+ ppp_input_error(ms->ppp, 0);
+ } else
#endif
if ((ms->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
- /* Notify the receiver... */
- qevent(ss->master, abort);
+ /* Notify the receiver... */
+ qevent(ss->master, abort);
#if 0
- printk("torintr_receive: Aborted %d bytes of frame on %d\n", amt, ss->master);
+ printk("torintr_receive: Aborted %d bytes of frame on %d\n", amt, ss->master);
#endif
- }
- }
+ }
+ } else /* No place to receive -- drop on the floor */
+ break;
#ifdef CONFIG_ZAPATA_NET
- if (skb && (ms->flags & ZT_FLAG_NETDEV))
- hdlc_netif_rx(&ms->hdlcnetdev->netdev, skb);
+ if (skb && (ms->flags & ZT_FLAG_NETDEV))
+ hdlc_netif_rx(&ms->hdlcnetdev->netdev, skb);
#endif
#ifdef CONFIG_ZAPATA_PPP
- if (skb && (ms->flags & ZT_FLAG_PPP)) {
- unsigned char *tmp;
- tmp = skb->data;
- skb_pull(skb, 2);
- /* Make sure that it's addressed to ALL STATIONS and UNNUMBERED */
- if (!tmp || (tmp[0] != 0xff) || (tmp[1] != 0x03)) {
- /* Invalid SKB -- drop */
- if (tmp)
- printk("Received invalid SKB (%02x, %02x)\n", tmp[0], tmp[1]);
- kfree_skb(skb);
- } else
- ppp_input(ms->ppp, skb);
- }
+ if (skb && (ms->flags & ZT_FLAG_PPP)) {
+ unsigned char *tmp;
+ tmp = skb->data;
+ skb_pull(skb, 2);
+ /* Make sure that it's addressed to ALL STATIONS and UNNUMBERED */
+ if (!tmp || (tmp[0] != 0xff) || (tmp[1] != 0x03)) {
+ /* Invalid SKB -- drop */
+ if (tmp)
+ printk("Received invalid SKB (%02x, %02x)\n", tmp[0], tmp[1]);
+ kfree_skb(skb);
+ } else
+ ppp_input(ms->ppp, skb);
+ }
#endif
+ }
}
@@ -4205,10 +4547,112 @@ static unsigned int zt_poll(struct file *file, struct poll_table_struct *wait_ta
return zt_chan_poll(file, wait_table, unit);
}
+static void zt_transmit_chunk(struct zt_chan *chan, unsigned char *buf)
+{
+ unsigned char silly[ZT_CHUNKSIZE];
+ if (!buf)
+ buf = silly;
+ zt_getbuf_chunk(chan, buf);
+
+ if (chan->flags & ZT_FLAG_AUDIO) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ zt_process_getaudio_chunk(chan, buf);
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
+ }
+}
+
+static inline void zt_real_transmit(struct zt_chan *chan)
+{
+ if (chan->confmode) {
+ /* Pull queued data off the conference */
+ buf_pull(&chan->confout, chan->writechunk, chan, "zt_real_transmit");
+ } else {
+ zt_transmit_chunk(chan, chan->writechunk);
+ }
+}
+
+static void zt_getempty(struct zt_chan *ms, unsigned char *buf)
+{
+ int bytes = ZT_CHUNKSIZE;
+ int left;
+ unsigned char *txb = buf;
+ int x;
+ short getlin;
+ while(bytes) {
+ /* Receive silence, or tone */
+ if (ms->curtone) {
+ left = ms->curtone->tonesamples - ms->tonep;
+ if (left > bytes)
+ left = bytes;
+ for (x=0;x<left;x++) {
+ /* Pick our default value from the next sample of the current tone */
+ getlin = zt_tone_nextsample(&ms->ts, ms->curtone);
+ *(txb++) = ZT_LIN2X(getlin, ms);
+ }
+ ms->tonep+=left;
+ bytes -= left;
+ if (ms->tonep >= ms->curtone->tonesamples) {
+ struct zt_tone *last;
+ /* Go to the next sample of the tone */
+ ms->tonep = 0;
+ last = ms->curtone;
+ ms->curtone = ms->curtone->next;
+ if (!ms->curtone) {
+ /* No more tones... Is this dtmf or mf? If so, go to the next digit */
+ if (ms->dialing)
+ do_dtmf(ms);
+ } else {
+ if (last != ms->curtone)
+ zt_init_tone_state(&ms->ts, ms->curtone);
+ }
+ }
+ } else {
+ /* Use silence */
+ memset(txb, ZT_LIN2X(0, ms), bytes);
+ bytes = 0;
+ }
+ }
+
+}
+
+static void zt_receive_chunk(struct zt_chan *chan, unsigned char *buf)
+{
+ char waste[ZT_CHUNKSIZE];
+ if (!buf) {
+ memset(waste, ZT_LIN2X(0, chan), sizeof(waste));
+ buf = waste;
+ }
+ if (chan->flags & ZT_FLAG_AUDIO) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ zt_process_putaudio_chunk(chan, buf);
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
+ }
+ zt_putbuf_chunk(chan, buf);
+}
+
+static inline void zt_real_receive(struct zt_chan *chan)
+{
+ if (chan->confmode) {
+ /* Load into queue if we have space */
+ buf_push(&chan->confin, chan->readchunk, "zt_real_receive");
+ } else {
+ zt_receive_chunk(chan, chan->readchunk);
+ }
+}
+
int zt_transmit(struct zt_span *span)
{
int x,y,z;
unsigned long flags;
+#if 1
for (x=0;x<span->channels;x++) {
spin_lock_irqsave(&span->chans[x].lock, flags);
if (&span->chans[x] == span->chans[x].master) {
@@ -4219,26 +4663,29 @@ int zt_transmit(struct zt_span *span)
}
}
if (span->chans[x].flags & ZT_FLAG_AUDIO) {
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- span->chans[x].writechunk[y] = span->chans[x].txgain[zt_getbuf_byte(&span->chans[x], y)];
- }
+ zt_real_transmit(&span->chans[x]);
} else {
- if (span->chans[x].slavemask) {
+ if (span->chans[x].nextslave) {
+ u_char data[ZT_CHUNKSIZE];
+ int pos=ZT_CHUNKSIZE;
+ /* Process master/slaves one way */
for (y=0;y<ZT_CHUNKSIZE;y++) {
- span->chans[x].writechunk[y] = zt_getbuf_byte(&span->chans[x], y);
-
/* Process slaves for this byte too */
- for (z=0;z<span->channels;z++) {
- if (span->chans[x].slavemask & (1 << z)) {
-
- span->chans[z].writechunk[y] = zt_getbuf_byte(&span->chans[z], y);
+ z = x;
+ do {
+ if (pos==ZT_CHUNKSIZE) {
+ /* Get next chunk */
+ zt_transmit_chunk(&span->chans[x], data);
+ pos = 0;
}
- }
- }
- } else
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- span->chans[x].writechunk[y] = zt_getbuf_byte(&span->chans[x], y);
+ span->chans[z].writechunk[y] = data[pos++];
+ z = span->chans[z].nextslave;
+ } while(z);
}
+ } else {
+ /* Process independents elsewise */
+ zt_real_transmit(&span->chans[x]);
+ }
}
}
spin_unlock_irqrestore(&span->chans[x].lock, flags);
@@ -4252,40 +4699,37 @@ int zt_transmit(struct zt_span *span)
wake_up_interruptible(&span->maintq);
}
}
+#endif
return 0;
}
int zt_receive(struct zt_span *span)
{
- int x,y,z,lin;
+ int x,y,z;
unsigned long flags;
+#if 1
for (x=0;x<span->channels;x++) {
- spin_lock_irqsave(&span->chans[x].lock, flags);
- if (&span->chans[x] == span->chans[x].master) {
- if (span->chans[x].slavemask) {
+ if (span->chans[x].master == &span->chans[x]) {
+ spin_lock_irqsave(&span->chans[x].lock, flags);
+ if (span->chans[x].nextslave) {
/* Must process each slave at the same time */
+ u_char data[ZT_CHUNKSIZE];
+ int pos = 0;
for (y=0;y<ZT_CHUNKSIZE;y++) {
- /* Start with this channel */
- zt_putbuf_byte(&span->chans[x], span->chans[x].readchunk[y], y);
-
/* Put all its slaves, too */
- for (z=x+1;z<span->channels;z++) {
- if (span->chans[x].slavemask & (1 << z)) {
-#if 0
- static int notify = 0;
- if (notify < 3) {
- notify++;
- printk("Channel index %d is slave to %d\n", span->chans[z].channo, span->chans[z].master->channo);
- }
-#endif
- zt_putbuf_byte(&span->chans[z], span->chans[z].readchunk[y], y);
+ z = x;
+ do {
+ data[pos++] = span->chans[z].readchunk[y];
+ if (pos == ZT_CHUNKSIZE) {
+ zt_receive_chunk(&span->chans[x], data);
+ pos = 0;
}
- }
+ z=span->chans[z].nextslave;
+ } while(z);
}
} else {
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- zt_putbuf_byte(&span->chans[x], span->chans[x].readchunk[y], y);
- }
+ /* Process a normal channel */
+ zt_real_receive(&span->chans[x]);
}
if (span->chans[x].itimer) {
span->chans[x].itimer -= ZT_CHUNKSIZE;
@@ -4293,49 +4737,73 @@ int zt_receive(struct zt_span *span)
rbs_itimer_expire(&span->chans[x]);
}
}
+ spin_unlock_irqrestore(&span->chans[x].lock, flags);
}
- spin_unlock_irqrestore(&span->chans[x].lock, flags);
}
+
if (span == master) {
/* If we have dynamic stuff, call the ioctl with 0,0 parameters to
make it run */
if (zt_dynamic_ioctl)
zt_dynamic_ioctl(0,0);
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ u_char *data;
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ data = buf_peek(&chans[x]->confin);
+ zt_receive_chunk(chans[x], data);
+ if (data)
+ buf_pull(&chans[x]->confin, NULL,chans[x], "confreceive");
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
/* This is the master channel, so make things switch over */
rotate_sums();
- /* do all the pseudo channel receives (getbuf's) */
- for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ /* do all the pseudo and/or conferenced channel receives (getbuf's) */
+ for (x=1;x<maxchans;x++) {
if (chans[x] && (chans[x]->flags & ZT_FLAG_PSEUDO)) {
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- (void) zt_getbuf_byte(chans[x], y);
- }
+ zt_transmit_chunk(chans[x], NULL);
}
}
- /* process all the conf links */
- for(x = 1; x <= ZT_MAX_CONF; x++) {
- /* if we have a destination conf */
- if ((z = conf_links[x].dst)) {
- /* go thru whole chunk. Do it chunky style! */
- for(y = 0; y < ZT_CHUNKSIZE; y++) {
- /* get sum of us and them */
- lin = conf_sums[conf_links[x].src][y] + conf_sums[z][y];
- /* clip it..... clip it good.. da da da da da.. da da da da */
- if (lin > 32767) lin = 32767;
- if (lin < -32767) lin = -32767;
- /* put it back into accumulator */
- conf_sums[z][y] = lin;
- }
+ if (maxlinks) {
+#ifdef CONFIG_ZAPTEL_MMX
+ zt_kernel_fpu_begin();
+#endif
+ /* process all the conf links */
+ for(x = 1; x <= maxlinks; x++) {
+ /* if we have a destination conf */
+ if (((z = confalias[conf_links[x].dst]) > 0) &&
+ ((y = confalias[conf_links[x].src]) > 0)) {
+ ACSS(conf_sums[z], conf_sums[y]);
+ }
}
+#ifdef CONFIG_ZAPTEL_MMX
+ kernel_fpu_end();
+#endif
}
- /* do all the pseudo channel transmits (putbuf's) */
- for (x=1;x<ZT_MAX_CHANNELS;x++) {
+ /* do all the pseudo/conferenced channel transmits (putbuf's) */
+ for (x=1;x<maxchans;x++) {
if (chans[x] && (chans[x]->flags & ZT_FLAG_PSEUDO)) {
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- zt_putbuf_byte(chans[x], 0x7f, y);
- }
+ unsigned char tmp[ZT_CHUNKSIZE];
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ zt_getempty(chans[x], tmp);
+ zt_receive_chunk(chans[x], tmp);
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
+ }
+ }
+ for (x=1;x<maxchans;x++) {
+ if (chans[x] && chans[x]->confmode && !(chans[x]->flags & ZT_FLAG_PSEUDO)) {
+ u_char *data;
+ spin_lock_irqsave(&chans[x]->lock, flags);
+ data = buf_pushpeek(&chans[x]->confout);
+ zt_transmit_chunk(chans[x], data);
+ if (data)
+ buf_push(&chans[x]->confout, NULL, "conftransmit");
+ spin_unlock_irqrestore(&chans[x]->lock, flags);
}
}
}
+#endif
return 0;
}