diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2001-12-09 16:42:25 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2001-12-09 16:42:25 +0000 |
commit | f1b2be7e6d4d46aa03578ca2e2d772e839ea1f6c (patch) | |
tree | 2dac1cc2b770162feb38f2cc7514403dac1bb51e /zaptel.c | |
parent | b03535c16b2443c521ad4474e5065d3d3496df8a (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-x | zaptel.c | 599 |
1 files changed, 410 insertions, 189 deletions
@@ -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(¶m,(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,¶m,sizeof(param)); + break; + case ZT_SET_PARAMS: /* set channel timing paramters */ + copy_from_user(¶m,(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,¶m,sizeof(param)); - break; - case ZT_SET_PARAMS: /* set channel timing paramters */ - /* point to relevant structure */ - copy_from_user(¶m,(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; } } |