summaryrefslogtreecommitdiff
path: root/zaptel.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-12-09 16:42:25 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2001-12-09 16:42:25 +0000
commitf1b2be7e6d4d46aa03578ca2e2d772e839ea1f6c (patch)
tree2dac1cc2b770162feb38f2cc7514403dac1bb51e /zaptel.c
parentb03535c16b2443c521ad4474e5065d3d3496df8a (diff)
Version 0.1.4 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@40 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'zaptel.c')
-rwxr-xr-xzaptel.c599
1 files changed, 410 insertions, 189 deletions
diff --git a/zaptel.c b/zaptel.c
index 1303290..55c838d 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -4,6 +4,10 @@
* Written by Mark Spencer <markster@linux-support.net>
* Based on previous works, designs, and architectures conceived and
* written by Jim Dixon <jim@lambdatel.com>.
+ *
+ * Special thanks to Steve Underwood <steve@coppice.org>
+ * for substantial contributions to signal processing functions
+ * in zaptel and the zapata library.
*
* Copyright (C) 2001 Jim Dixon / Zapata Telephony.
* Copyright (C) 2001 Linux Support Services, Inc.
@@ -64,10 +68,12 @@ static char *zt_txlevelnames[] = {
"-22.5db (CSU)"
} ;
+EXPORT_SYMBOL(zt_init_tone_state);
+EXPORT_SYMBOL(zt_dtmf_tone);
EXPORT_SYMBOL(zt_register);
EXPORT_SYMBOL(zt_unregister);
-EXPORT_SYMBOL(zt_mulaw);
-EXPORT_SYMBOL(zt_lin2mu);
+EXPORT_SYMBOL(__zt_mulaw);
+EXPORT_SYMBOL(__zt_lin2mu);
EXPORT_SYMBOL(zt_lboname);
EXPORT_SYMBOL(zt_transmit);
EXPORT_SYMBOL(zt_receive);
@@ -117,14 +123,6 @@ __u16 fcstab[256] =
static int debug;
-struct zt_tone {
- unsigned char *tonedata; /* u-law tone data */
- int datalen; /* Length of tone data */
- int tonesamples; /* How long to play this tone before
- going to the next (in samples) */
- struct zt_tone *next; /* Next tone in this sequence */
-};
-
/* states for transmit signalling */
typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START,
ZT_TXSTATE_PREWINK,ZT_TXSTATE_WINK,ZT_TXSTATE_PREFLASH,
@@ -132,10 +130,6 @@ typedef enum {ZT_TXSTATE_ONHOOK,ZT_TXSTATE_OFFHOOK,ZT_TXSTATE_START,
ZT_TXSTATE_RINGON,ZT_TXSTATE_RINGOFF,ZT_TXSTATE_KEWL,
ZT_TXSTATE_AFTERKEWL} ZT_TXSTATE_t;
-
-static struct zt_tone dtmf_tones[16];
-static struct zt_tone mfv1_tones[15];
-
typedef short sumtype[ZT_MAX_CHUNKSIZE];
static sumtype sums[(ZT_MAX_CONF + 1) * 3];
@@ -227,11 +221,16 @@ static int maxchans = 0;
static int default_zone = DEFAULT_TONE_ZONE;
-short zt_mulaw[256];
-u_char zt_lin2mu[65536];
+short __zt_mulaw[256];
+u_char __zt_lin2mu[16384];
+
+short __zt_alaw[256];
+u_char __zt_lin2a[16384];
u_char defgain[256];
+
+
static rwlock_t zone_lock;
static rwlock_t chan_lock;
@@ -246,13 +245,13 @@ int x;
static unsigned int in_sig[NUM_SIGS][2] = {
{ ZT_SIG_NONE, 0},
- { ZT_SIG_EM, 0},
- { ZT_SIG_FXSLS,ZT_BBIT},
- { ZT_SIG_FXSGS,ZT_ABIT | ZT_BBIT},
- { ZT_SIG_FXSKS,ZT_BBIT},
- { ZT_SIG_FXOLS,ZT_BBIT},
- { ZT_SIG_FXOGS,ZT_BBIT},
- { ZT_SIG_FXOKS,ZT_BBIT}
+ { ZT_SIG_EM, 0 | (ZT_ABIT << 8)},
+ { ZT_SIG_FXSLS,ZT_BBIT | (ZT_BBIT << 8)},
+ { ZT_SIG_FXSGS,ZT_ABIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXSKS,ZT_BBIT | ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXOLS,0 | (ZT_ABIT << 8)},
+ { ZT_SIG_FXOGS,ZT_BBIT | ((ZT_ABIT | ZT_BBIT) << 8)},
+ { ZT_SIG_FXOKS,0 | (ZT_ABIT << 8)}
} ;
/* if RBS does not apply, return error */
@@ -260,8 +259,7 @@ static unsigned int in_sig[NUM_SIGS][2] = {
!chan->span->rbsbits) return(-1);
for (x=0;x<NUM_SIGS;x++) {
if (in_sig[x][0] == chan->sig) return(in_sig[x][1]);
- }
- return(-1); /* not found -- error */
+ } return(-1); /* not found -- error */
}
static int zt_first_empty_conference(void)
@@ -406,6 +404,7 @@ 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);
static void close_channel(struct zt_chan *chan)
{
@@ -442,6 +441,8 @@ static void close_channel(struct zt_chan *chan)
chan->txgain = defgain;
chan->gainalloc = 0;
chan->eventinidx = chan->eventoutidx = 0;
+ chan->flags &= ~ZT_FLAG_LINEAR;
+ zt_set_law(chan,chan->deflaw);
memset(chan->conflast, 0, sizeof(chan->conflast));
memset(chan->conflast1, 0, sizeof(chan->conflast1));
@@ -516,10 +517,12 @@ static int start_tone(struct zt_chan *chan, int tone)
if (chan->curzone->tones[tone]) {
chan->curtone = chan->curzone->tones[tone];
res = 0;
- } else /* Inidicate that zone is loaded but no such tone exists */
+ } else /* Indicate that zone is loaded but no such tone exists */
res = -ENOSYS;
} else /* Note that no tone zone exists at the moment */
res = -ENODATA;
+ if (chan->curtone)
+ zt_init_tone_state(&chan->ts, chan->curtone);
return res;
}
@@ -530,7 +533,7 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
if ((zone >= ZT_TONE_ZONE_MAX) || (zone < -1))
return -EINVAL;
- read_lock(&zone_lock);
+ read_lock(&zone_lock);
if (zone == -1) {
zone = default_zone;
}
@@ -545,6 +548,24 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
return res;
}
+static void zt_set_law(struct zt_chan *chan, int law)
+{
+ if (!law) {
+ if (chan->deflaw)
+ law = chan->deflaw;
+ else
+ if (chan->span) law = chan->span->deflaw;
+ else law = ZT_LAW_MULAW;
+ }
+ if (law == ZT_LAW_ALAW) {
+ chan->xlaw = __zt_alaw;
+ chan->lin2x = __zt_lin2a;
+ } else {
+ chan->xlaw = __zt_mulaw;
+ chan->lin2x = __zt_lin2mu;
+ }
+}
+
static int zt_chan_reg(struct zt_chan *chan)
{
int x;
@@ -565,6 +586,7 @@ static int zt_chan_reg(struct zt_chan *chan)
chan->readchunk = chan->sreadchunk;
if (!chan->writechunk)
chan->writechunk = chan->swritechunk;
+ zt_set_law(chan, 0);
close_channel(chan);
res = 0;
break;
@@ -572,7 +594,7 @@ static int zt_chan_reg(struct zt_chan *chan)
}
write_unlock_irqrestore(&chan_lock, flags);
if (x >= ZT_MAX_CHANNELS)
- printk(KERN_ERR "No more channels avaialable\n");
+ printk(KERN_ERR "No more channels available\n");
return res;
}
@@ -741,7 +763,7 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u
struct zt_chan *chan = chans[unit];
int amnt;
int res, rv;
- int oldbuf;
+ int oldbuf,x;
unsigned int flags;
if (!chan)
return -EINVAL;
@@ -764,11 +786,35 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u
if (rv) return (rv);
}
amnt = count;
- if (amnt > chan->readn[chan->outreadbuf])
- amnt = chan->readn[chan->outreadbuf];
- if (amnt) {
- if (copy_to_user(usrbuf, chan->readbuf[chan->outreadbuf], amnt))
- return -EFAULT;
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ if (amnt > (chan->readn[chan->outreadbuf] << 1))
+ amnt = chan->readn[chan->outreadbuf] << 1;
+ if (amnt) {
+ /* There seems to be a max stack size, so we have
+ to do this in smaller pieces */
+ short lindata[512];
+ int left = amnt;
+ int pos = 0;
+ int pass;
+ while(left) {
+ pass = left;
+ if (pass > 512)
+ pass = 512;
+ for (x=0;x<pass;x++)
+ lindata[x] = ZT_XLAW(chan->readbuf[chan->outreadbuf][x + pos], chan);
+ if (copy_to_user(usrbuf + (pos << 1), lindata, pass << 1))
+ return -EFAULT;
+ left -= pass;
+ pos += pass;
+ }
+ }
+ } else {
+ if (amnt > chan->readn[chan->outreadbuf])
+ amnt = chan->readn[chan->outreadbuf];
+ if (amnt) {
+ if (copy_to_user(usrbuf, chan->readbuf[chan->outreadbuf], amnt))
+ return -EFAULT;
+ }
}
spin_lock_irqsave(&chan->lock, flags);
chan->readidx[chan->outreadbuf] = 0;
@@ -794,7 +840,7 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
{
unsigned int flags;
struct zt_chan *chan = chans[unit];
- int res, amnt, oldbuf, rv;
+ int res, amnt, oldbuf, rv,x;
if (!chan)
return -EINVAL;
for(;;) {
@@ -819,9 +865,15 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
if (rv)
return rv;
}
+
amnt = count;
- if (amnt > chan->blocksize)
- amnt = chan->blocksize;
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ if (amnt > (chan->blocksize << 1))
+ amnt = chan->blocksize << 1;
+ } else {
+ if (amnt > chan->blocksize)
+ amnt = chan->blocksize;
+ }
#if 0
printk("zt_chan_write(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n",
@@ -829,8 +881,29 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
#endif
if (amnt) {
- copy_from_user(chan->writebuf[chan->inwritebuf], usrbuf, amnt);
- chan->writen[chan->inwritebuf] = amnt;
+ if (chan->flags & ZT_FLAG_LINEAR) {
+ /* There seems to be a max stack size, so we have
+ to do this in smaller pieces */
+ short lindata[512];
+ int left = amnt;
+ int pos = 0;
+ int pass;
+ while(left) {
+ pass = left;
+ if (pass > 512)
+ pass = 512;
+ if (copy_from_user(lindata, usrbuf + (pos << 1), pass << 1))
+ return -EFAULT;
+ left -= pass;
+ for (x=0;x<pass;x++)
+ chan->writebuf[chan->inwritebuf][x + pos] = ZT_LIN2X(lindata[x], chan);
+ pos += pass;
+ }
+ chan->writen[chan->inwritebuf] = amnt >> 1;
+ } else {
+ copy_from_user(chan->writebuf[chan->inwritebuf], usrbuf, amnt);
+ chan->writen[chan->inwritebuf] = amnt;
+ }
chan->writeidx[chan->inwritebuf] = 0;
if (chan->flags & ZT_FLAG_FCS)
calc_fcs(chan);
@@ -884,14 +957,25 @@ static int zt_chan_release(struct inode *inode, struct file *file)
static void zt_rbs_sethook(struct zt_chan *chan, int txsig, int txstate, int timeout)
{
static int outs[NUM_SIGS][5] = {
- { ZT_SIG_NONE, 0, 0, 0, 0 }, /* no signalling */
- { ZT_SIG_EM, 0, ZT_ABIT | ZT_BBIT,ZT_ABIT | ZT_BBIT, 0 }, /* E and M */
- { ZT_SIG_FXSLS, ZT_BBIT, ZT_ABIT | ZT_BBIT, ZT_ABIT | ZT_BBIT, 0 }, /* FXS Loopstart */
- { ZT_SIG_FXSGS, ZT_BBIT, ZT_ABIT | ZT_BBIT, ZT_ABIT, 0 }, /* FXS Groundstart */
- { ZT_SIG_FXSKS, ZT_BBIT, ZT_ABIT | ZT_BBIT, ZT_ABIT | ZT_BBIT, 0 }, /* FXS Kewlstart */
- { ZT_SIG_FXOLS, ZT_BBIT, ZT_BBIT, 0, 0 }, /* FXO Loopstart */
- { ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT, ZT_BBIT, 0, 0 }, /* FXO Groundstart */
- { ZT_SIG_FXOKS, ZT_BBIT, ZT_BBIT, 0, ZT_ABIT | ZT_BBIT } /* FXO Kewlstart */
+/* We set the idle case of the ZT_SIG_NONE to this pattern to make idle E1 CAS
+channels happy. Should not matter with T1, since on an un-configured channel,
+who cares what the sig bits are as long as they are stable */
+ { ZT_SIG_NONE, ZT_ABIT | ZT_CBIT | ZT_DBIT, 0, 0, 0 }, /* no signalling */
+ { ZT_SIG_EM, 0, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* E and M */
+ { ZT_SIG_FXSLS, ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Loopstart */
+ { ZT_SIG_FXSGS, ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, ZT_ABIT | ZT_CBIT, 0 }, /* FXS Groundstart */
+ { ZT_SIG_FXSKS, ZT_BBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT, 0 }, /* FXS Kewlstart */
+ { ZT_SIG_FXOLS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Loopstart */
+ { ZT_SIG_FXOGS, ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT,
+ ZT_BBIT | ZT_DBIT, 0, 0 }, /* FXO Groundstart */
+ { ZT_SIG_FXOKS, ZT_BBIT | ZT_DBIT, ZT_BBIT | ZT_DBIT, 0,
+ ZT_ABIT | ZT_BBIT | ZT_CBIT | ZT_DBIT } /* FXO Kewlstart */
} ;
int x;
if (!chan->span->flags & ZT_FLAG_RBS) {
@@ -910,6 +994,7 @@ static int outs[NUM_SIGS][5] = {
chan->txstate = txstate;
if (chan->span->hooksig) {
+ chan->txhooksig = txsig;
chan->span->hooksig(chan, txsig);
chan->otimer = timeout * 8; /* Otimer is timer in samples */
return;
@@ -919,7 +1004,9 @@ static int outs[NUM_SIGS][5] = {
#if 0
printk("Setting bits to %d for channel %s state %d in %d signalling\n", outs[x][txsig + 1], chan->name, txsig, chan->sig);
#endif
- chan->span->rbsbits(chan, outs[x][txsig+1]);
+ chan->txhooksig = txsig;
+ chan->txsig = outs[x][txsig+1];
+ chan->span->rbsbits(chan, chan->txsig);
chan->otimer = timeout * 8; /* Otimer is timer in samples */
return;
}
@@ -1024,11 +1111,13 @@ static int initialize_channel(struct zt_chan *chan)
chan->txgain = defgain;
chan->gainalloc = 0;
chan->eventinidx = chan->eventoutidx = 0;
+ zt_set_law(chan,chan->deflaw);
zt_hangup(chan);
/* Make sure that the audio flag is cleared on a clear channel */
if (chan->sig & ZT_SIG_CLEAR)
chan->flags &= ~ZT_FLAG_AUDIO;
+ chan->flags &= ~ZT_FLAG_LINEAR;
spin_unlock_irqrestore(&chan->lock, flags);
@@ -1216,11 +1305,8 @@ ioctl_load_zone(unsigned long data)
copy_from_user(&th, (struct zt_tone_def_header *)data, sizeof(th));
if ((th.count < 0) || (th.count > MAX_TONES))
return -EINVAL;
- if ((th.size < 0) || (th.size > MAX_SIZE))
- return -EINVAL;
space = size = sizeof(struct zt_zone) +
- th.count * sizeof(struct zt_tone) +
- th.size;
+ th.count * sizeof(struct zt_tone);
if ((size > MAX_SIZE) || (size < 0))
return -E2BIG;
ptr = slab = (char *)kmalloc(size, GFP_KERNEL);
@@ -1265,26 +1351,16 @@ ioctl_load_zone(unsigned long data)
ptr += sizeof(struct zt_tone);
data += sizeof(struct zt_tone_def);
/* Fill in tonedata, datalen, and tonesamples fields */
- t->tonedata = (unsigned char *)(ptr);
- t->datalen = td.size;
t->tonesamples = td.samples;
+ t->fac1 = td.fac1;
+ t->init_v2_1 = td.init_v2_1;
+ t->init_v3_1 = td.init_v3_1;
+ t->fac2 = td.fac2;
+ t->init_v2_2 = td.init_v2_2;
+ t->init_v3_2 = td.init_v3_2;
t->next = NULL; /* XXX Unnecessary XXX */
- /* Now some checks: Enough space? */
- if (space < t->datalen) {
- kfree(slab);
- return -EINVAL;
- }
- /* Put actual tone data */
- if (copy_from_user(t->tonedata, (unsigned char *)data, t->datalen)) {
- kfree(slab);
- return -EIO;
- }
if (!z->tones[td.tone])
z->tones[td.tone] = t;
- /* Update pointers and space */
- data += t->datalen;
- ptr += t->datalen;
- space -= t->datalen;
}
for (x=0;x<th.count;x++)
/* Set "next" pointers */
@@ -1297,62 +1373,70 @@ ioctl_load_zone(unsigned long data)
return res;
}
-static inline void do_dtmf(struct zt_chan *chan)
+void zt_init_tone_state(struct zt_tone_state *ts, struct zt_tone *zt)
+{
+ ts->v1_1 = 0;
+ ts->v2_1 = zt->init_v2_1;
+ ts->v3_1 = zt->init_v3_1;
+ ts->v1_2 = 0;
+ ts->v2_2 = zt->init_v2_2;
+ ts->v3_2 = zt->init_v3_2;
+}
+
+struct zt_tone *zt_dtmf_tone(char digit, int mf)
{
- char c;
struct zt_tone *z;
+ if (!mf)
+ z = dtmf_tones;
+ else
+ z = mfv1_tones;
+ switch(digit) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return z + (int)(digit - '0');
+ case '*':
+ return z + 10;
+ case '#':
+ return z + 11;
+ case 'A':
+ case 'B':
+ case 'C':
+ return z + (digit + 12 - 'A');
+ case 'D':
+ if (!mf)
+ return z + ( digit + 12 - 'A');
+ return NULL;
+ case 'a':
+ case 'b':
+ case 'c':
+ return z + (digit + 12 - 'a');
+ case 'd':
+ if (!mf)
+ return z + ( digit + 12 - 'a');
+ return NULL;
+ case 'W':
+ case 'w':
+ return &tone_pause;
+ }
+ return NULL;
+}
+static inline void do_dtmf(struct zt_chan *chan)
+{
+ char c;
while (strlen(chan->txdialbuf)) {
- if (chan->digitmode == DIGIT_MODE_DTMF)
- z = dtmf_tones;
- else
- z = mfv1_tones;
c = chan->txdialbuf[0];
/* Skooch */
memmove(chan->txdialbuf, chan->txdialbuf + 1, sizeof(chan->txdialbuf) - 1);
switch(c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- chan->curtone = z + (int)(c - '0');
- chan->tonep = 0;
- return;
- case '*':
- chan->curtone = z + 10;
- chan->tonep = 0;
- return;
- case '#':
- chan->curtone = z + 11;
- return;
- case 'A':
- case 'B':
- case 'C':
- chan->curtone = z + (c + 12 - 'A');
- chan->tonep = 0;
- return;
- case 'D':
- if (chan->digitmode == DIGIT_MODE_DTMF)
- chan->curtone = z + ( c + 12 - 'A');
- chan->tonep = 0;
- return;
- case 'a':
- case 'b':
- case 'c':
- chan->curtone = z + (c + 12 - 'a');
- chan->tonep = 0;
- return;
- case 'd':
- if (chan->digitmode == DIGIT_MODE_DTMF)
- chan->curtone = z + ( c + 12 - 'a');
- chan->tonep = 0;
- return;
case 'T':
case 't':
chan->digitmode = DIGIT_MODE_DTMF;
@@ -1363,12 +1447,14 @@ static inline void do_dtmf(struct zt_chan *chan)
chan->digitmode = DIGIT_MODE_MFV1;
chan->tonep = 0;
break;
- case 'W':
- case 'w':
- chan->curtone = &tone_pause;
- chan->tonep = 0;
- return;
default:
+ chan->curtone = zt_dtmf_tone(c, (chan->digitmode == DIGIT_MODE_MFV1));
+ chan->tonep = 0;
+ /* All done */
+ if (chan->curtone) {
+ zt_init_tone_state(&chan->ts, chan->curtone);
+ return;
+ }
}
}
/* Notify userspace process if there is nothing left */
@@ -1452,8 +1538,89 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
{
struct zt_gains gain;
struct zt_spaninfo span;
+ struct zt_chan *chan;
int i,j;
+ struct zt_params param;
+
switch(cmd) {
+ case ZT_GET_PARAMS: /* get channel timing parameters */
+ copy_from_user(&param,(struct zt_params *)data,sizeof(param));
+ /* Pick the right channo's */
+ if (!param.channo || unit) {
+ param.channo = unit;
+ }
+ /* Check validity of channel */
+ VALID_CHANNEL(param.channo);
+ chan = chans[param.channo];
+
+ /* point to relevant structure */
+ param.sigtype = chan->sig; /* get signalling type */
+ /* return non-zero if rx not in idle state */
+ if (chan->span) {
+ j = zt_q_sig(chan);
+ if (j >= 0) { /* if returned with success */
+ param.rxisoffhook = ((chan->rxsig & (j >> 8)) != (j & 0xff));
+ }
+ else {
+ param.rxisoffhook = ((chan->rxhooksig != ZT_RXSIG_ONHOOK) &&
+ (chan->rxhooksig != ZT_RXSIG_INITIAL));
+ }
+ } else param.rxisoffhook = 0;
+ if (chan->span && chan->span->rbsbits && !(chan->sig & ZT_SIG_CLEAR)) {
+ param.rxbits = chan->rxsig;
+ param.txbits = chan->txsig;
+ } else {
+ param.rxbits = -1;
+ param.txbits = -1;
+ }
+ if (chan->span && (chan->span->rbsbits || chan->span->hooksig) &&
+ !(chan->sig & ZT_SIG_CLEAR)) {
+ param.rxhooksig = chan->rxhooksig;
+ param.txhooksig = chan->txhooksig;
+ } else {
+ param.rxhooksig = -1;
+ param.txhooksig = -1;
+ }
+ param.prewinktime = chan->prewinktime;
+ param.preflashtime = chan->preflashtime;
+ param.winktime = chan->winktime;
+ param.flashtime = chan->flashtime;
+ param.starttime = chan->starttime;
+ param.rxwinktime = chan->rxwinktime;
+ param.rxflashtime = chan->rxflashtime;
+ param.debouncetime = chan->debouncetime;
+ param.channo = chan->channo;
+ if (chan->span) param.spanno = chan->span->spanno;
+ else param.spanno = 0;
+ param.chanpos = chan->chanpos;
+ /* Return current law */
+ if (chan->xlaw == __zt_alaw)
+ param.curlaw = ZT_LAW_ALAW;
+ else
+ param.curlaw = ZT_LAW_MULAW;
+ copy_to_user((struct zt_params *)data,&param,sizeof(param));
+ break;
+ case ZT_SET_PARAMS: /* set channel timing paramters */
+ copy_from_user(&param,(struct zt_params *)data,sizeof(param));
+ /* Pick the right channo's */
+ if (!param.channo || unit) {
+ param.channo = unit;
+ }
+ /* Check validity of channel */
+ VALID_CHANNEL(param.channo);
+ chan = chans[param.channo];
+ /* point to relevant structure */
+ /* NOTE: sigtype is *not* included in this */
+ /* get timing paramters */
+ chan->prewinktime = param.prewinktime;
+ chan->preflashtime = param.preflashtime;
+ chan->winktime = param.winktime;
+ chan->flashtime = param.flashtime;
+ chan->starttime = param.starttime;
+ chan->rxwinktime = param.rxwinktime;
+ chan->rxflashtime = param.rxflashtime;
+ chan->debouncetime = param.debouncetime;
+ break;
case ZT_GETGAINS: /* get gain stuff */
if (copy_from_user(&gain,(struct zt_gains *) data,sizeof(gain)))
return -EIO;
@@ -1496,6 +1663,15 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
chans[i]->rxgain[j] = gain.rxgain[j];
chans[i]->txgain[j] = gain.txgain[j];
}
+ if (!memcmp(chans[i]->rxgain, defgain, 256) &&
+ !memcmp(chans[i]->txgain, defgain, 256)) {
+ /* This is really just a normal gain, so
+ deallocate the memory and go back to defaults */
+ kfree(chans[i]->rxgain);
+ chans[i]->rxgain = defgain;
+ chans[i]->txgain = defgain;
+ chans[i]->gainalloc = 0;
+ }
if (copy_to_user((struct zt_gains *) data,&gain,sizeof(gain)))
return -EIO;
break;
@@ -1514,11 +1690,14 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
span.spanno = i; /* put the span # in here */
span.totalspans = 0;
if (maxspans) span.totalspans = maxspans - 1; /* put total number of spans here */
+ strncpy(span.desc, spans[i]->desc, sizeof(span.desc) - 1);
+ strncpy(span.name, spans[i]->name, sizeof(span.name) - 1);
span.alarms = spans[i]->alarms; /* get alarm status */
span.bpvcount = spans[i]->bpvcount; /* get BPV count */
span.rxlevel = spans[i]->rxlevel; /* get rx level */
span.txlevel = spans[i]->txlevel; /* get tx level */
span.syncsrc = spans[i]->syncsrc; /* get active sync source */
+ span.totalchans = spans[i]->channels;
span.numchans = 0;
for (j=0; j < spans[i]->channels; j++)
if (spans[i]->chans[j].sig)
@@ -1565,7 +1744,7 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* Mark as running and hangup any channels */
spans[j]->flags |= ZT_FLAG_RUNNING;
for (x=0;x<spans[j]->channels;x++) {
- y = zt_q_sig(&spans[j]->chans[x]);
+ y = zt_q_sig(&spans[j]->chans[x]) & 0xff;
if (y >= 0) spans[j]->chans[x].rxsig = (unsigned char)y;
zt_hangup(&spans[j]->chans[x]);
spans[j]->chans[x].rxhooksig = ZT_RXSIG_INITIAL;
@@ -1672,12 +1851,14 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
!(chans[ch.chan]->flags & ZT_FLAG_NETDEV))
printk("Unable to register HDLC device for channel %s\n", chans[ch.chan]->name);
if (!res) {
+ /* Setup default law */
+ chans[ch.chan]->deflaw = ch.deflaw;
/* Copy back any modified settings */
if (copy_to_user((struct zt_chanconfig *)data, &ch, sizeof(ch)))
return -EFAULT;
/* And hangup */
zt_hangup(chans[ch.chan]);
- y = zt_q_sig(chans[ch.chan]);
+ y = zt_q_sig(chans[ch.chan]) & 0xff;
if (y >= 0) chans[ch.chan]->rxsig = (unsigned char)y;
chans[ch.chan]->rxhooksig = ZT_RXSIG_INITIAL;
}
@@ -1746,12 +1927,14 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case ZT_MAINT_REMOTELOOP:
/* if same, ignore it */
if (i == maint.command) break;
- spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ if (rv) return rv;
break;
case ZT_MAINT_LOOPUP:
case ZT_MAINT_LOOPDOWN:
spans[maint.spanno]->mainttimer = ZT_LOOPCODE_TIME * 8;
- spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ rv = spans[maint.spanno]->maint(spans[maint.spanno], maint.command);
+ if (rv) return rv;
spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags);
rv = schluffen(&spans[maint.spanno]->maintq);
if (rv) return rv;
@@ -2141,6 +2324,23 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
case ZT_CHANNO: /* get channel number of stream */
put_user(unit,(int *)data); /* return unit/channel number */
break;
+ case ZT_SETLAW:
+ get_user(j, (int *)data);
+ if ((j < 0) || (j > ZT_LAW_ALAW))
+ return -EINVAL;
+ zt_set_law(chan, j);
+ break;
+ case ZT_SETLINEAR:
+ get_user(j, (int *)data);
+ /* Makes no sense on non-audio channels */
+ if (!(chan->flags & ZT_FLAG_AUDIO))
+ return -EINVAL;
+
+ if (j)
+ chan->flags |= ZT_FLAG_LINEAR;
+ else
+ chan->flags &= ~ZT_FLAG_LINEAR;
+ break;
default:
/* Check for common ioctl's and private ones */
rv = zt_common_ioctl(inode, file, cmd, data, unit);
@@ -2154,7 +2354,6 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit)
{
- struct zt_params param;
struct zt_chan *chan = chans[unit];
unsigned int flags;
int j, rv;
@@ -2195,44 +2394,6 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
fasthdlc_init(&chan->txhdlc);
}
break;
- case ZT_GET_PARAMS: /* get channel timing parameters */
- /* point to relevant structure */
- param.sigtype = chan->sig; /* get signalling type */
- /* return non-zero if rx not in idle state */
- j = zt_q_sig(chan);
- if (j >= 0) /* if returned with success */
- param.rxisoffhook = (chan->rxsig != (unsigned char)j);
- else {
- param.rxisoffhook = ((chan->rxhooksig != ZT_RXSIG_ONHOOK) &&
- (chan->rxhooksig != ZT_RXSIG_INITIAL));
- }
- param.prewinktime = chan->prewinktime;
- param.preflashtime = chan->preflashtime;
- param.winktime = chan->winktime;
- param.flashtime = chan->flashtime;
- param.starttime = chan->starttime;
- param.rxwinktime = chan->rxwinktime;
- param.rxflashtime = chan->rxflashtime;
- param.debouncetime = chan->debouncetime;
- param.channo = chan->channo;
- param.spanno = chan->span->spanno;
- param.chanpos = chan->chanpos;
- copy_to_user((struct zt_params *)data,&param,sizeof(param));
- break;
- case ZT_SET_PARAMS: /* set channel timing paramters */
- /* point to relevant structure */
- copy_from_user(&param,(struct zt_params *)data,sizeof(param));
- /* NOTE: sigtype is *not* included in this */
- /* get timing paramters */
- chan->prewinktime = param.prewinktime;
- chan->preflashtime = param.preflashtime;
- chan->winktime = param.winktime;
- chan->flashtime = param.flashtime;
- chan->starttime = param.starttime;
- chan->rxwinktime = param.rxwinktime;
- chan->rxflashtime = param.rxflashtime;
- chan->debouncetime = param.debouncetime;
- break;
case ZT_GETEVENT: /* Get event on queue */
spin_lock_irqsave(&chan->lock, flags);
/* set up for no event */
@@ -2428,6 +2589,10 @@ int zt_register(struct zt_span *span, int prefmaster)
}
span->flags |= ZT_FLAG_REGISTERED;
span->spanno = x;
+ if (!span->deflaw) {
+ printk("zaptel: Span %s didn't specify default law. Assuming mulaw, please fix driver!\n", span->name);
+ span->deflaw = ZT_LAW_MULAW;
+ }
for (x=0;x<span->channels;x++) {
span->chans[x].span = span;
zt_chan_reg(&span->chans[x]);
@@ -2537,10 +2702,59 @@ static unsigned char __init linear2ulaw(short sample)
#ifdef ZEROTRAP
if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
#endif
-
+ if (ulawbyte == 0xff) ulawbyte = 0x7f; /* never return 0xff */
return(ulawbyte);
}
+#define AMI_MASK 0x55
+
+static inline uint8_t linear2alaw (short int linear)
+{
+ int mask;
+ int seg;
+ int pcm_val;
+ static int seg_end[8] =
+ {
+ 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
+ };
+
+ pcm_val = linear;
+ if (pcm_val >= 0)
+ {
+ /* Sign (7th) bit = 1 */
+ mask = AMI_MASK | 0x80;
+ }
+ else
+ {
+ /* Sign bit = 0 */
+ mask = AMI_MASK;
+ pcm_val = -pcm_val;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ for (seg = 0; seg < 8; seg++)
+ {
+ if (pcm_val <= seg_end[seg])
+ break;
+ }
+ /* Combine the sign, segment, and quantization bits. */
+ return ((seg << 4) | ((pcm_val >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask;
+}
+/*- End of function --------------------------------------------------------*/
+
+static inline short int alaw2linear (uint8_t alaw)
+{
+ int i;
+ int seg;
+
+ alaw ^= AMI_MASK;
+ i = ((alaw & 0x0F) << 4);
+ seg = (((int) alaw & 0x70) >> 4);
+ if (seg)
+ i = (i + 0x100) << (seg - 1);
+ return (short int) ((alaw & 0x80) ? i : -i);
+}
+/*- End of function --------------------------------------------------------*/
static void __init zt_conv_init(void)
{
int i;
@@ -2558,16 +2772,17 @@ static void __init zt_conv_init(void)
y = f * (1 << (e + 3));
y += etab[e];
if (mu & 0x80) y = -y;
- zt_mulaw[i] = y;
+ __zt_mulaw[i] = y;
+ __zt_alaw[i] = alaw2linear(i);
/* Default (0.0 db) gain table */
defgain[i] = i;
}
/* set up the reverse (mu-law) conversion table */
- for(i = 0; i < 65536; i++)
+ for(i = -32768; i < 32768; i += 4)
{
- zt_lin2mu[i] = linear2ulaw(i - 32768);
+ __zt_lin2mu[((unsigned short)(short)i) >> 2] = linear2ulaw(i);
+ __zt_lin2a[((unsigned short)(short)i) >> 2] = linear2alaw(i);
}
-
}
static inline unsigned char zt_getbuf_byte(struct zt_chan *ss, int pos)
@@ -2585,7 +2800,6 @@ static inline unsigned char zt_getbuf_byte(struct zt_chan *ss, int pos)
/* and how about another int */
int k;
-
/* 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. */
@@ -2651,15 +2865,22 @@ out in the later versions, and is put back now. */
}
} else if (ms->curtone) {
/* Pick our default value from the next sample of the current tone */
- txc = ms->curtone->tonedata[ms->tonep++ % ms->curtone->datalen];
+ 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);
}
}
} else if (ms->flags & ZT_FLAG_HDLC) {
@@ -2667,16 +2888,16 @@ out in the later versions, and is put back now. */
if (ms->txhdlc.bits < 8)
fasthdlc_tx_frame_nocheck(&ms->txhdlc);
txc = fasthdlc_tx_run_nocheck(&ms->txhdlc);
- } else txc = 0x7f; /* Lastly we use 0x7f on telephony channels */
+ } else txc = ZT_LIN2X(0, ms); /* Lastly we use silence on telephony channels */
/* Okay, now we've got something to transmit */
- getlin = zt_mulaw[txc];
+ getlin = ZT_XLAW(txc, ms);
if ((ms->flags & ZT_FLAG_AUDIO) && !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_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_MONITOR: /* Monitor a channel's rx mode */
/* Add monitored channel */
@@ -2688,7 +2909,7 @@ out in the later versions, and is put back now. */
/* Clip */
if (getlin > 32767) getlin = 32767;
if (getlin < -32767) getlin = 32767;
- txc = zt_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
/* Add monitored channel */
@@ -2700,7 +2921,7 @@ out in the later versions, and is put back now. */
/* Clip */
if (getlin > 32767) getlin = 32767;
if (getlin < -32767) getlin = 32767;
- txc = zt_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_MONITORBOTH: /* monitor a channel's rx and tx mode */
getlin += chans[ms->confn]->putlin[pos] +
@@ -2708,7 +2929,7 @@ out in the later versions, and is put back now. */
/* Clip */
if (getlin > 32767) getlin = 32767;
if (getlin < -32767) getlin = 32767;
- txc = zt_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_REALANDPSEUDO:
/* This strange mode takes the transmit buffer and
@@ -2769,7 +2990,7 @@ out in the later versions, and is put back now. */
/* Clip */
if (getlin > 32767) getlin = 32767;
if (getlin < -32767) getlin = 32767;
- txc = zt_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
case ZT_CONF_CONFANN:
case ZT_CONF_CONFANNMON:
@@ -2791,7 +3012,7 @@ out in the later versions, and is put back now. */
/* Clip */
if (getlin > 32767) getlin = 32767;
if (getlin < -32767) getlin = -32767;
- txc = zt_lin2mu[getlin + 32768];
+ txc = ZT_LIN2X(getlin, ms);
break;
}
}
@@ -3224,16 +3445,16 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
else if (ms->afterdialingtimer) ms->afterdialingtimer--;
if (ms->afterdialingtimer) rxc = 0x7f; /* receive as silence if dialing */
if (ms->echocancel) {
- putlin = zt_mulaw[rxc];
+ putlin = ZT_XLAW(rxc, ms);
putlin = process_cc(&ms->ec, ms->getlin_lastchunk[pos],
abs(ms->getlin_lastchunk[pos]), putlin, abs(putlin));
- rxc = zt_lin2mu[(int)putlin + 32768];
+ rxc = ZT_LIN2X((int)putlin, ms);
}
/* Apply gain if appropriate */
if (ms->flags & ZT_FLAG_AUDIO)
rxc = ms->rxgain[rxc];
- putlin = (int) zt_mulaw[rxc];
+ putlin = ZT_XLAW(rxc, ms);
if (!(ms->flags & ZT_FLAG_PSEUDO))
ms->putlin[pos] = putlin;
@@ -3257,7 +3478,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Clip */
if (putlin > 32767) putlin = 32767;
if (putlin < -32767) putlin = 32767;
- rxc = zt_lin2mu[putlin + 32768];
+ rxc = ZT_LIN2X(putlin, ms);
break;
case ZT_CONF_MONITORTX: /* Monitor a channel's tx mode */
/* if not a pseudo-channel, ignore */
@@ -3271,7 +3492,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Clip */
if (putlin > 32767) putlin = 32767;
if (putlin < -32767) putlin = 32767;
- rxc = zt_lin2mu[putlin + 32768];
+ rxc = ZT_LIN2X(putlin, ms);
break;
case ZT_CONF_MONITORBOTH: /* Monitor a channel's tx and rx mode */
/* if not a pseudo-channel, ignore */
@@ -3281,7 +3502,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Clip */
if (putlin > 32767) putlin = 32767;
if (putlin < -32767) putlin = 32767;
- rxc = zt_lin2mu[putlin + 32768];
+ rxc = ZT_LIN2X(putlin, ms);
break;
case ZT_CONF_REALANDPSEUDO:
/* do normal conf mode processing */
@@ -3311,7 +3532,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Clip */
if (putlin > 32767) putlin = 32767;
if (putlin < -32767) putlin = 32767;
- rxc = zt_lin2mu[putlin + 32768];
+ rxc = ZT_LIN2X(putlin, ms);
break;
case ZT_CONF_CONF: /* Normal conference mode */
if (ms->flags & ZT_FLAG_PSEUDO) /* if a pseudo-channel */
@@ -3325,8 +3546,8 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Clip */
if (putlin > 32767) putlin = 32767;
if (putlin < -32767) putlin = 32767;
- rxc = zt_lin2mu[putlin + 32768];
- ss->getlin[pos] = zt_mulaw[rxc];
+ rxc = ZT_LIN2X(putlin, ss);
+ ss->getlin[pos] = ZT_XLAW(rxc, ss);
break;
}
/* fall through */
@@ -3367,7 +3588,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
/* Really add in new value */
conf_sums[ms->confn][pos] += ms->conflast[pos];
} else ms->conflast[pos] = 0;
- rxc = zt_lin2mu[(int)conf_sums_prev[ms->confn][pos] + 32768];
+ rxc = ZT_LIN2X((int)conf_sums_prev[ms->confn][pos], ms);
break;
}
}