summaryrefslogtreecommitdiff
path: root/zaptel.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-03-14 15:44:51 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2002-03-14 15:44:51 +0000
commitdf72c1e4f5719ca85705cce46dd794f6f6ef640d (patch)
tree38d6ee3b87bf67b839a299adb3fd0846c2e42528 /zaptel.c
parent85e79a5401b14577b4cd7e098651a3371c4513fe (diff)
Version 0.1.6 from FTP
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@65 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'zaptel.c')
-rwxr-xr-xzaptel.c743
1 files changed, 609 insertions, 134 deletions
diff --git a/zaptel.c b/zaptel.c
index 55c838d..1712a22 100755
--- a/zaptel.c
+++ b/zaptel.c
@@ -36,10 +36,17 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/version.h>
+#include <linux/kmod.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif /* CONFIG_DEVFS_FS */
#ifdef CONFIG_ZAPATA_NET
#include <linux/netdevice.h>
#endif /* CONFIG_ZAPATA_NET */
#include <linux/ppp_defs.h>
+#ifdef CONFIG_ZAPATA_PPP
+#include <linux/if_ppp.h>
+#endif
/* Grab fasthdlc with tables */
#define FAST_HDLC_NEED_TABLES
@@ -51,7 +58,7 @@
#include <linux/zaptel.h>
#endif
-#define hdlc_to_ztchan(h) ((struct zt_chan *)(h))
+#define hdlc_to_ztchan(h) (((struct zt_hdlc *)(h))->chan)
/* macro-oni for determining a unit (channel) number */
#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev)
@@ -81,9 +88,19 @@ EXPORT_SYMBOL(zt_rbsbits);
EXPORT_SYMBOL(zt_qevent);
EXPORT_SYMBOL(zt_hooksig);
EXPORT_SYMBOL(zt_alarm_notify);
-
+EXPORT_SYMBOL(zt_set_dynamic_ioctl);
+
+/* Here are a couple important little additions for devfs */
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t zaptel_devfs_dir;
+static devfs_handle_t channel;
+static devfs_handle_t pseudo;
+static devfs_handle_t ctl;
+#endif
/* There is a table like this in the PPP driver, too */
+static int deftaps = 64;
+
static
__u16 fcstab[256] =
{
@@ -140,6 +157,7 @@ static sumtype *conf_sums;
static sumtype *conf_sums_prev;
static struct zt_span *master;
+static struct file_operations zt_fops;
static struct
{
@@ -231,8 +249,8 @@ u_char defgain[256];
-static rwlock_t zone_lock;
-static rwlock_t chan_lock;
+static rwlock_t zone_lock = RW_LOCK_UNLOCKED;
+static rwlock_t chan_lock = RW_LOCK_UNLOCKED;
static struct zt_zone *tone_zones[ZT_TONE_ZONE_MAX];
@@ -410,8 +428,19 @@ static void close_channel(struct zt_chan *chan)
{
unsigned int flags;
void *rxgain = NULL;
+ echo_can_state_t *ec = NULL;
+#ifdef CONFIG_ZAPATA_PPP
+ struct ppp_channel *ppp;
+#endif
+
zt_reallocbufs(chan, 0, 0);
spin_lock_irqsave(&chan->lock, flags);
+#ifdef CONFIG_ZAPATA_PPP
+ ppp = chan->ppp;
+ chan->ppp = NULL;
+#endif
+ ec = chan->ec;
+ chan->ec = NULL;
chan->curtone = NULL;
chan->curzone = NULL;
chan->cadencepos = 0;
@@ -441,7 +470,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;
+ chan->flags &= ~(ZT_FLAG_LINEAR | ZT_FLAG_PPP);
+
zt_set_law(chan,chan->deflaw);
memset(chan->conflast, 0, sizeof(chan->conflast));
@@ -452,21 +482,23 @@ static void close_channel(struct zt_chan *chan)
if (rxgain)
kfree(rxgain);
+ if (ec)
+ echo_can_free(ec);
+
+#ifdef CONFIG_ZAPATA_PPP
+ if (ppp) {
+ ppp_unregister_channel(ppp);
+ kfree(ppp);
+ }
+#endif
+
}
static int tone_zone_init(void)
{
int x;
- static int inited = 0;
- write_lock(&zone_lock);
- if (inited) {
- write_unlock(&zone_lock);
- return 0;
- }
for (x=0;x<ZT_TONE_ZONE_MAX;x++)
tone_zones[x] = NULL;
- inited++;
- write_unlock(&zone_lock);
return 0;
}
@@ -566,6 +598,51 @@ static void zt_set_law(struct zt_chan *chan, int law)
}
}
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t register_devfs_channel(struct zt_chan *chan, devfs_handle_t dir)
+{
+ char path[100];
+ char link[100];
+ char buf[50];
+ char tmp[100];
+ int link_offset = 0;
+ int tmp_offset = 0;
+ int path_offset = 0;
+ int err = 0;
+ devfs_handle_t chan_dev;
+ umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
+ unsigned int flags = DEVFS_FL_AUTO_OWNER;
+
+ sprintf(path, "%d", chan->chanpos);
+ chan_dev = devfs_register(dir, path, flags, ZT_MAJOR, chan->channo, mode, &zt_fops, NULL);
+ if (!chan_dev) {
+ printk("zaptel: Something really bad happened. Unable to register devfs entry\n");
+ return NULL;
+ }
+
+ /* Set up the path of the destination of the link */
+ link_offset = devfs_generate_path(chan_dev, link, sizeof(link) - 1);
+ /* Now we need to strip off the leading "zap/". If we don't, then we build a broken symlink */
+ path_offset = devfs_generate_path(zaptel_devfs_dir, path, sizeof(path) - 1); /* We'll just "borrow" path for a second */
+ path_offset = strlen(path+path_offset);
+ link_offset += path_offset; /* Taking out the "zap" */
+ link_offset++; /* Add one more place for the '/'. The path generated does not contain the '/' we need to strip */
+
+ /* Set up the path of the file/link itself */
+ tmp_offset = devfs_generate_path(zaptel_devfs_dir, tmp, sizeof(tmp) - 1);
+ sprintf(buf, "/%d", chan->channo);
+ strncpy(path, tmp+tmp_offset, sizeof(path) - 1);
+ strncat(path, buf, sizeof(path) - 1);
+
+ err = devfs_mk_symlink(NULL, path, DEVFS_FL_DEFAULT, link+link_offset, &chan->fhandle_symlink, NULL);
+ if (err != 0) {
+ printk("Problem with making devfs symlink: %d\n", err);
+ }
+
+ return chan_dev;
+}
+#endif /* CONFIG_DEVFS_FS */
+
static int zt_chan_reg(struct zt_chan *chan)
{
int x;
@@ -575,6 +652,7 @@ static int zt_chan_reg(struct zt_chan *chan)
write_lock_irqsave(&chan_lock, flags);
for (x=1;x<ZT_MAX_CHANNELS;x++) {
if (!chans[x]) {
+ spin_lock_init(&chan->lock);
chans[x] = chan;
if (maxchans < x + 1)
maxchans = x + 1;
@@ -605,6 +683,9 @@ char *zt_lboname(int x)
return zt_txlevelnames[x];
}
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
+#endif
+
#ifdef CONFIG_ZAPATA_NET
static int zt_net_open(hdlc_device *hdlc)
{
@@ -657,10 +738,20 @@ static void zt_net_close(hdlc_device *hdlc)
return;
}
+static struct zt_hdlc *zt_hdlc_alloc(void)
+{
+ struct zt_hdlc *tmp;
+ tmp = kmalloc(sizeof(struct zt_hdlc), GFP_KERNEL);
+ if (tmp) {
+ memset(tmp, 0, sizeof(struct zt_hdlc));
+ }
+ return tmp;
+}
+
static int zt_xmit(hdlc_device *hdlc, struct sk_buff *skb)
{
struct zt_chan *ss = hdlc_to_ztchan(hdlc);
- struct net_device *dev = &ss->netdev.netdev;
+ struct net_device *dev = &ss->hdlcnetdev->netdev.netdev;
int retval = 1;
int x,oldbuf;
unsigned int fcs;
@@ -670,7 +761,7 @@ static int zt_xmit(hdlc_device *hdlc, struct sk_buff *skb)
spin_lock_irqsave(&ss->lock, flags);
if (skb->len > ss->blocksize - 2) {
printk(KERN_ERR "zt_xmit(%s): skb is too large (%d > %d)\n", dev->name, skb->len, ss->blocksize -2);
- ss->netdev.stats.tx_dropped++;
+ ss->hdlcnetdev->netdev.stats.tx_dropped++;
retval = 0;
} else if (ss->inwritebuf >= 0) {
/* We have a place to put this packet */
@@ -723,7 +814,107 @@ static int zt_net_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
#endif
+#ifdef CONFIG_ZAPATA_PPP
+
+static int zt_ppp_xmit(struct ppp_channel *ppp, struct sk_buff *skb)
+{
+
+ /*
+ * If we can't handle the packet right now, return 0. If we
+ * we handle or drop it, return 1. Always free if we return
+ * 1 and never if we return 0
+ */
+ struct zt_chan *ss = ppp->private;
+ int x,oldbuf;
+ unsigned int fcs;
+ unsigned char *data;
+ long flags;
+ int retval = 0;
+
+ /* See if we have any buffers */
+ spin_lock_irqsave(&ss->lock, flags);
+ if (!(ss->flags & ZT_FLAG_OPEN)) {
+ printk("Can't transmit on closed channel\n");
+ retval = 1;
+ } else if (skb->len > ss->blocksize - 4) {
+ printk(KERN_ERR "zt_ppp_xmit(%s): skb is too large (%d > %d)\n", ss->name, skb->len, ss->blocksize -2);
+ retval = 1;
+ } else if (ss->inwritebuf >= 0) {
+ /* We have a place to put this packet */
+ /* XXX We should keep the SKB and avoid the memcpy XXX */
+ data = ss->writebuf[ss->inwritebuf];
+ /* Start with header of two bytes */
+ /* Add "ALL STATIONS" and "UNNUMBERED" */
+ data[0] = 0xff;
+ data[1] = 0x03;
+ ss->writen[ss->inwritebuf] = 2;
+
+ /* Copy real data and increment amount written */
+ memcpy(data + 2, skb->data, skb->len);
+
+ ss->writen[ss->inwritebuf] += skb->len;
+
+ /* Re-set index back to zero */
+ ss->writeidx[ss->inwritebuf] = 0;
+
+ /* Calculate the FCS */
+ fcs = PPP_INITFCS;
+ for (x=0;x<skb->len + 2;x++)
+ fcs = PPP_FCS(fcs, data[x]);
+ /* Invert it */
+ fcs ^= 0xffff;
+
+ /* Point past the real data now */
+ data += (skb->len + 2);
+
+ /* Send FCS out LSB first */
+ data[0] = (fcs & 0xff);
+ data[1] = (fcs >> 8) & 0xff;
+
+ /* Account for FCS length */
+ ss->writen[ss->inwritebuf]+=2;
+
+ /* Advance to next window */
+ oldbuf = ss->inwritebuf;
+ ss->inwritebuf = (ss->inwritebuf + 1) % ss->numbufs;
+
+ if (ss->inwritebuf == ss->outwritebuf) {
+ /* Whoops, no more space. */
+ ss->inwritebuf = -1;
+ }
+ if (ss->outwritebuf < 0) {
+ /* Let the interrupt handler know there's
+ some space for us */
+ ss->outwritebuf = oldbuf;
+ }
+#if 0
+ printk("Buffered %d bytes (skblen = %d) to go out in buffer %d\n", ss->writen[oldbuf], skb->len, oldbuf);
+ for (x=0;x<ss->writen[oldbuf];x++)
+ printk("%02x ", ss->writebuf[oldbuf][x]);
+ printk("\n");
+#endif
+ retval = 1;
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+ if (retval) {
+ /* Get rid of the SKB if we're returning non-zero */
+ dev_kfree_skb(skb);
+ }
+ return retval;
+}
+
+static int zt_ppp_ioctl(struct ppp_channel *ppp, unsigned int cmd, unsigned long flags)
+{
+ return -EIO;
+}
+
+static struct ppp_channel_ops ztppp_ops =
+{
+ start_xmit: zt_ppp_xmit,
+ ioctl: zt_ppp_ioctl,
+};
+#endif
static void zt_chan_unreg(struct zt_chan *chan)
{
int x;
@@ -734,9 +925,17 @@ static void zt_chan_unreg(struct zt_chan *chan)
chan->flags &= ~ZT_FLAG_REGISTERED;
}
#ifdef CONFIG_ZAPATA_NET
- if (chan->flags & ZT_FLAG_NETDEV)
- unregister_hdlc_device(&chan->netdev);
-#endif
+ if (chan->flags & ZT_FLAG_NETDEV) {
+ unregister_hdlc_device(&chan->hdlcnetdev->netdev);
+ kfree(chan->hdlcnetdev);
+ chan->hdlcnetdev = NULL;
+ }
+#endif
+#ifdef CONFIG_ZAPATA_PPP
+ if (chan->ppp) {
+ printk("HUH??? PPP still attached??\n");
+ }
+#endif
maxchans = 0;
for (x=1;x<ZT_MAX_CHANNELS;x++)
if (chans[x]) {
@@ -1018,7 +1217,6 @@ who cares what the sig bits are as long as they are stable */
static int zt_hangup(struct zt_chan *chan)
{
int res=0;
- unsigned int flags;
/* Can't hangup pseudo channels */
if (!chan->span)
return 0;
@@ -1028,12 +1226,10 @@ static int zt_hangup(struct zt_chan *chan)
chan->kewlonhook = 0;
if (chan->span->flags & ZT_FLAG_RBS) {
/* Do RBS signalling on the channel's behalf */
- spin_lock_irqsave(&chan->lock, flags);
if ((chan->sig == ZT_SIG_FXOKS) && (chan->txstate != ZT_TXSTATE_ONHOOK)) {
zt_rbs_sethook(chan, ZT_TXSIG_KEWL, ZT_TXSTATE_KEWL, ZT_KEWLTIME);
} else
zt_rbs_sethook(chan, ZT_TXSIG_ONHOOK, ZT_TXSTATE_ONHOOK, 0);
- spin_unlock_irqrestore(&chan->lock, flags);
} else {
/* Let the driver hang up the line if it wants to */
if (chan->span->sethook)
@@ -1047,6 +1243,7 @@ static int initialize_channel(struct zt_chan *chan)
int res;
unsigned int flags;
void *rxgain=NULL;
+ echo_can_state_t *ec=NULL;
if ((res = zt_reallocbufs(chan, ZT_DEFAULT_BLOCKSIZE, ZT_DEFAULT_NUM_BUFS)))
return res;
@@ -1055,6 +1252,11 @@ static int initialize_channel(struct zt_chan *chan)
chan->rxbufpolicy = ZT_POLICY_IMMEDIATE;
chan->txbufpolicy = ZT_POLICY_IMMEDIATE;
+ /* Free up the echo canceller if there is one */
+ ec = chan->ec;
+ chan->ec = NULL;
+ chan->echocancel = 0;
+
chan->txdisable = 0;
chan->rxdisable = 0;
@@ -1085,7 +1287,6 @@ static int initialize_channel(struct zt_chan *chan)
/* Initialize RBS timers */
chan->itimer = chan->otimer = 0;
- chan->echocancel = 0;
init_waitqueue_head(&chan->sel);
init_waitqueue_head(&chan->readbufq);
@@ -1115,14 +1316,20 @@ static int initialize_channel(struct zt_chan *chan)
zt_hangup(chan);
/* Make sure that the audio flag is cleared on a clear channel */
- if (chan->sig & ZT_SIG_CLEAR)
+ if (chan->sig & ZT_SIG_CLEAR)
chan->flags &= ~ZT_FLAG_AUDIO;
+
+ if (chan->sig == ZT_SIG_CLEAR)
+ chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC);
+
chan->flags &= ~ZT_FLAG_LINEAR;
spin_unlock_irqrestore(&chan->lock, flags);
if (rxgain)
kfree(rxgain);
+ if (ec)
+ echo_can_free(ec);
return 0;
}
@@ -1148,10 +1355,10 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in
if (chans[unit]->span && chans[unit]->span->open)
res = chans[unit]->span->open(chans[unit]);
if (!res) {
- chans[unit]->flags |= ZT_FLAG_OPEN;
chans[unit]->file = file;
if (inc)
MOD_INC_USE_COUNT;
+ chans[unit]->flags |= ZT_FLAG_OPEN;
} else {
close_channel(chans[unit]);
}
@@ -1228,8 +1435,9 @@ static ssize_t zt_read(struct file *file, char *usrbuf, size_t count, loff_t *pp
struct zt_chan *chan;
/* Can't read from control */
- if (!unit)
+ if (!unit) {
return -EINVAL;
+ }
if (unit == 254) {
chan = file->private_data;
@@ -1248,8 +1456,8 @@ static ssize_t zt_read(struct file *file, char *usrbuf, size_t count, loff_t *pp
}
if (count < 0)
return -EINVAL;
+
return zt_chan_read(file, usrbuf, count, unit);
-
}
static ssize_t zt_write(struct file *file, const char *usrbuf, size_t count, loff_t *ppos)
@@ -1592,6 +1800,7 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
param.channo = chan->channo;
if (chan->span) param.spanno = chan->span->spanno;
else param.spanno = 0;
+ strncpy(param.name, chan->name, sizeof(param.name) - 1);
param.chanpos = chan->chanpos;
/* Return current law */
if (chan->xlaw == __zt_alaw)
@@ -1710,6 +1919,13 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
return 0;
}
+static int (*zt_dynamic_ioctl)(unsigned int cmd, unsigned long data);
+
+void zt_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data))
+{
+ zt_dynamic_ioctl = func;
+}
+
static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data)
{
/* I/O CTL's for control interface */
@@ -1746,7 +1962,9 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
for (x=0;x<spans[j]->channels;x++) {
y = zt_q_sig(&spans[j]->chans[x]) & 0xff;
if (y >= 0) spans[j]->chans[x].rxsig = (unsigned char)y;
+ spin_lock_irqsave(&spans[j]->chans[x].lock, flags);
zt_hangup(&spans[j]->chans[x]);
+ spin_unlock_irqrestore(&spans[j]->chans[x].lock, flags);
spans[j]->chans[x].rxhooksig = ZT_RXSIG_INITIAL;
}
}
@@ -1775,12 +1993,14 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&chans[ch.chan]->lock, flags);
#ifdef CONFIG_ZAPATA_NET
if (chans[ch.chan]->flags & ZT_FLAG_NETDEV) {
- if (chans[ch.chan]->netdev.netdev.flags & IFF_UP) {
+ if (chans[ch.chan]->hdlcnetdev->netdev.netdev.flags & IFF_UP) {
spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
printk(KERN_WARNING "Can't switch HDLC net mode on channel %s, since current interface is up\n", chans[ch.chan]->name);
return -EBUSY;
}
- unregister_hdlc_device(&chans[ch.chan]->netdev);
+ unregister_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
+ kfree(chans[ch.chan]->hdlcnetdev);
+ chans[ch.chan]->hdlcnetdev = NULL;
chans[ch.chan]->flags &= ~ZT_FLAG_NETDEV;
}
#else
@@ -1801,6 +2021,10 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!res && chans[ch.chan]->span->chanconfig)
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));
+ }
if (!res) {
chans[ch.chan]->sig = ch.sigtype;
if ((ch.sigtype & ZT_SIG_CLEAR) == ZT_SIG_CLEAR) {
@@ -1827,25 +2051,33 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
}
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));
}
#ifdef CONFIG_ZAPATA_NET
if (!res &&
(newmaster == chans[ch.chan]) &&
(chans[ch.chan]->sig == ZT_SIG_HDLCNET)) {
- memset(&chans[ch.chan]->netdev, 0, sizeof(chans[ch.chan]->netdev));
- chans[ch.chan]->netdev.ioctl = zt_net_ioctl;
- chans[ch.chan]->netdev.open = zt_net_open;
- chans[ch.chan]->netdev.close = zt_net_close;
- chans[ch.chan]->netdev.set_mode = NULL;
- chans[ch.chan]->netdev.xmit = zt_xmit;
- chans[ch.chan]->netdev.netdev.irq = chans[ch.chan]->span->irq;
- chans[ch.chan]->netdev.netdev.tx_queue_len = 50;
- res = register_hdlc_device(&chans[ch.chan]->netdev);
- if (!res)
- chans[ch.chan]->flags |= ZT_FLAG_NETDEV;
+ chans[ch.chan]->hdlcnetdev = zt_hdlc_alloc();
+ if (chans[ch.chan]->hdlcnetdev) {
+ chans[ch.chan]->hdlcnetdev->chan = chans[ch.chan];
+ chans[ch.chan]->hdlcnetdev->netdev.ioctl = zt_net_ioctl;
+ chans[ch.chan]->hdlcnetdev->netdev.open = zt_net_open;
+ chans[ch.chan]->hdlcnetdev->netdev.close = zt_net_close;
+ chans[ch.chan]->hdlcnetdev->netdev.set_mode = NULL;
+ chans[ch.chan]->hdlcnetdev->netdev.xmit = zt_xmit;
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.irq = chans[ch.chan]->span->irq;
+ chans[ch.chan]->hdlcnetdev->netdev.netdev.tx_queue_len = 50;
+ res = register_hdlc_device(&chans[ch.chan]->hdlcnetdev->netdev);
+ if (!res)
+ chans[ch.chan]->flags |= ZT_FLAG_NETDEV;
+ } else {
+ printk("Unable to allocate netdev: out of memory\n");
+ res = -1;
+ }
}
#endif
- spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
if ((chans[ch.chan]->sig == ZT_SIG_HDLCNET) &&
(chans[ch.chan] == newmaster) &&
!(chans[ch.chan]->flags & ZT_FLAG_NETDEV))
@@ -1854,8 +2086,10 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* Setup default law */
chans[ch.chan]->deflaw = ch.deflaw;
/* Copy back any modified settings */
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
if (copy_to_user((struct zt_chanconfig *)data, &ch, sizeof(ch)))
return -EFAULT;
+ spin_lock_irqsave(&chans[ch.chan]->lock, flags);
/* And hangup */
zt_hangup(chans[ch.chan]);
y = zt_q_sig(chans[ch.chan]) & 0xff;
@@ -1865,6 +2099,7 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
#if 0
printk("Configured channel %s, flags %04x, sig %04x\n", chans[ch.chan]->name, chans[ch.chan]->flags, chans[ch.chan]->sig);
#endif
+ spin_unlock_irqrestore(&chans[ch.chan]->lock, flags);
return res;
case ZT_DEFAULTZONE:
if (get_user(j,(int *)data))
@@ -1946,6 +2181,16 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
zt_alarm_notify(spans[maint.spanno]); /* process alarm-related events */
spin_unlock_irqrestore(&spans[maint.spanno]->lock, flags);
break;
+ case ZT_DYNAMIC_CREATE:
+ case ZT_DYNAMIC_DESTROY:
+ if (zt_dynamic_ioctl)
+ return zt_dynamic_ioctl(cmd, data);
+ else {
+ request_module("ztdynamic");
+ if (zt_dynamic_ioctl)
+ return zt_dynamic_ioctl(cmd, data);
+ }
+ return -ENOSYS;
default:
return zt_common_ioctl(inode, file, cmd, data, 0);
}
@@ -2358,6 +2603,7 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
unsigned int flags;
int j, rv;
int ret;
+ echo_can_state_t *ec, *tec;
if (!chan)
return -ENOSYS;
@@ -2374,6 +2620,59 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
chan->flags &= ~ZT_FLAG_AUDIO;
}
break;
+ case ZT_HDLCPPP:
+#ifdef CONFIG_ZAPATA_PPP
+ if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
+ get_user(j, (int *)data);
+ if (j) {
+ if (!chan->ppp) {
+ chan->ppp = kmalloc(sizeof(struct ppp_channel), GFP_KERNEL);
+ if (chan->ppp) {
+ memset(chan->ppp, 0, sizeof(struct ppp_channel));
+ chan->ppp->private = chan;
+ chan->ppp->ops = &ztppp_ops;
+ chan->ppp->mtu = ZT_DEFAULT_MTU_MRU;
+ chan->ppp->hdrlen = 0;
+ if ((ret = zt_reallocbufs(chan, ZT_DEFAULT_MTU_MRU, ZT_DEFAULT_NUM_BUFS))) {
+ kfree(chan->ppp);
+ chan->ppp = NULL;
+ return ret;
+ }
+
+ if ((ret = ppp_register_channel(chan->ppp))) {
+ kfree(chan->ppp);
+ chan->ppp = NULL;
+ return ret;
+ }
+ tec = chan->ec;
+ chan->ec = NULL;
+ chan->echocancel = 0;
+ /* Make sure there's no gain */
+ if (chan->gainalloc)
+ kfree(chan->rxgain);
+ chan->rxgain = defgain;
+ chan->txgain = defgain;
+ chan->gainalloc = 0;
+ chan->flags &= ~ZT_FLAG_AUDIO;
+ chan->flags |= (ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (tec)
+ echo_can_free(tec);
+ } else
+ return -ENOMEM;
+ }
+ } else {
+ chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_HDLC | ZT_FLAG_FCS);
+ if (chan->ppp) {
+ ppp_unregister_channel(chan->ppp);
+ kfree(chan->ppp);
+ chan->ppp = NULL;
+ }
+ }
+#else
+ printk("Zaptel: Zaptel PPP support not compiled in\n");
+ return -ENOSYS;
+#endif
+ break;
case ZT_HDLCRAWMODE:
if (chan->sig != ZT_SIG_CLEAR) return (-EINVAL);
get_user(j, (int *)data);
@@ -2414,10 +2713,34 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
return -EINVAL;
get_user(j, (int *)data);
if (j) {
- chan->echocancel = 1;
- init_cc(&chan->ec);
- } else
+ if ((j == 32) ||
+ (j == 64) ||
+ (j == 128) ||
+ (j == 256)) {
+ /* Okay */
+ } else {
+ j = deftaps;
+ }
+ ec = echo_can_create(j, 0);
+ if (!ec)
+ return -ENOMEM;
+ spin_lock_irqsave(&chan->lock, flags);
+ /* If we had an old echo can, zap it now */
+ tec = chan->ec;
+ chan->echocancel = j;
+ chan->ec = ec;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (tec)
+ echo_can_free(tec);
+ } else {
+ spin_lock_irqsave(&chan->lock, flags);
+ tec = chan->ec;
chan->echocancel = 0;
+ chan->ec = NULL;
+ spin_unlock_irqrestore(&chan->lock, flags);
+ if (tec)
+ echo_can_free(tec);
+ }
break;
case ZT_HOOK:
if (chan->flags & ZT_FLAG_CLEAR)
@@ -2426,7 +2749,9 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
if (chan->span->flags & ZT_FLAG_RBS) {
switch (j) {
case ZT_ONHOOK:
+ spin_lock_irqsave(&chan->lock, flags);
zt_hangup(chan);
+ spin_unlock_irqrestore(&chan->lock, flags);
break;
case ZT_OFFHOOK:
spin_lock_irqsave(&chan->lock, flags);
@@ -2501,6 +2826,20 @@ static int zt_chan_ioctl(struct inode *inode, struct file *file, unsigned int cm
else
return -ENOSYS;
break;
+#ifdef CONFIG_ZAPATA_PPP
+ case PPPIOCGCHAN:
+ if (chan->flags & ZT_FLAG_PPP)
+ return put_user(ppp_channel_index(chan->ppp), (int *)data) ? -EFAULT : 0;
+ else
+ return -EINVAL;
+ break;
+ case PPPIOCGUNIT:
+ if (chan->flags & ZT_FLAG_PPP)
+ return put_user(ppp_unit_number(chan->ppp), (int *)data) ? -EFAULT : 0;
+ else
+ return -EINVAL;
+ break;
+#endif
default:
return zt_chanandpseudo_ioctl(inode, file, cmd, data, unit);
}
@@ -2593,10 +2932,24 @@ int zt_register(struct zt_span *span, int prefmaster)
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]);
}
+
+#ifdef CONFIG_DEVFS_FS
+ {
+ char span_name[50];
+ sprintf(span_name, "span%d", span->spanno);
+ span->dhandle = devfs_mk_dir(zaptel_devfs_dir, span_name, NULL);
+ for (x = 0; x < span->channels; x++) {
+ struct zt_chan *chan = &span->chans[x];
+ chan->fhandle = register_devfs_channel(chan, chan->span->dhandle); /* Register our stuff with devfs */
+ }
+ }
+#endif /* CONFIG_DEVFS_FS */
+
if (debug)
printk("Registered Span %d ('%s') with %d channels\n", span->spanno, span->name, span->channels);
if (!master || prefmaster) {
@@ -2625,6 +2978,13 @@ int zt_unregister(struct zt_span *span)
}
if (debug)
printk("Unregistering Span '%s' with %d channels\n", span->name, span->channels);
+#ifdef CONFIG_DEVFS_FS
+ for (x = 0; x < span->channels; x++) {
+ devfs_unregister(span->chans[x].fhandle);
+ devfs_unregister(span->chans[x].fhandle_symlink);
+ }
+ devfs_unregister(span->dhandle);
+#endif /* CONFIG_DEVFS_FS */
spans[span->spanno] = NULL;
span->spanno = 0;
span->flags &= ~ZT_FLAG_REGISTERED;
@@ -2640,6 +3000,7 @@ int zt_unregister(struct zt_span *span)
master = spans[x];
}
}
+
return 0;
}
@@ -2849,7 +3210,7 @@ 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)) {
+ 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)
@@ -2860,8 +3221,13 @@ out in the later versions, and is put back now. */
fasthdlc_tx_frame_nocheck(&ms->txhdlc);
#ifdef CONFIG_ZAPATA_NET
if (ms->flags & ZT_FLAG_NETDEV)
- netif_wake_queue(&ms->netdev.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 */
@@ -2888,6 +3254,10 @@ 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 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 */
@@ -3156,20 +3526,29 @@ static inline void rbs_otimer_expire(struct zt_chan *chan)
static void zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
{
+ int oldrxsig = chan->rxhooksig;
+
+ /* State machines for receive hookstate transitions */
+
+ if ((chan->rxhooksig) == rxsig) return;
+
chan->rxhooksig = rxsig;
switch(chan->sig) {
case ZT_SIG_EM: /* E and M */
switch(rxsig) {
case ZT_RXSIG_OFFHOOK: /* went off hook */
- /* set wink timer */
+ /* The interface is going off hook */
+ /* set wink timer */
chan->itimer = chan->rxwinktime * 8;
break;
case ZT_RXSIG_ONHOOK: /* went on hook */
+ /* This interface is now going on hook.
+ Check for WINK, etc */
if (chan->itimer)
- qevent(chan,ZT_EVENT_WINKFLASH);
+ qevent(chan,ZT_EVENT_WINKFLASH);
else {
- qevent(chan,ZT_EVENT_ONHOOK);
- chan->gotgs = 0;
+ qevent(chan,ZT_EVENT_ONHOOK);
+ chan->gotgs = 0;
}
chan->itimer = 0;
break;
@@ -3178,32 +3557,31 @@ static void zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
}
break;
case ZT_SIG_FXSLS: /* FXS loopstart */
- if (rxsig == ZT_RXSIG_RING) {
+ if ((oldrxsig == ZT_RXSIG_RING) &&
+ (rxsig == ZT_RXSIG_OFFHOOK)) {
qevent(chan,ZT_EVENT_RINGOFFHOOK);
}
break;
case ZT_SIG_FXSKS: /* FXS Kewlstart */
- if (rxsig == ZT_RXSIG_RING) {
+ if ((oldrxsig == ZT_RXSIG_RING) &&
+ (rxsig == ZT_RXSIG_OFFHOOK)) {
qevent(chan,ZT_EVENT_RINGOFFHOOK);
break;
}
- /* ignore a bit poopy if loop no closed and stable */
+ /* ignore a bit poopy if loop not closed and stable */
if (chan->txstate != ZT_TXSTATE_OFFHOOK) break;
/* fall through intentionally */
case ZT_SIG_FXSGS: /* FXS Groundstart */
- switch(rxsig) {
- case ZT_RXSIG_RING:
+ if ((oldrxsig == ZT_RXSIG_RING) &&
+ (rxsig == ZT_RXSIG_OFFHOOK)) {
qevent(chan,ZT_EVENT_RINGOFFHOOK);
break;
- case ZT_RXSIG_ONHOOK: /* went on hook */
- /* if not during offhook debounce time */
+ }
+ if (rxsig == ZT_RXSIG_ONHOOK) {
if (chan->txstate != ZT_TXSTATE_DEBOUNCE) {
chan->gotgs = 0;
qevent(chan,ZT_EVENT_ONHOOK);
}
- break;
- default:
- break;
}
break;
case ZT_SIG_FXOGS: /* FXO Groundstart */
@@ -3219,7 +3597,7 @@ static void zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
case ZT_SIG_FXOKS: /* FXO Kewlstart */
switch(rxsig) {
case ZT_RXSIG_OFFHOOK: /* went off hook */
- /* if asserting ring, stop it */
+ /* if asserti ng ring, stop it */
if (chan->txstate == ZT_TXSTATE_START) {
zt_rbs_sethook(chan,ZT_TXSIG_OFFHOOK, ZT_TXSTATE_AFTERSTART, ZT_AFTERSTART_TIME);
}
@@ -3260,53 +3638,50 @@ static void zt_hooksig_pvt(struct zt_chan *chan, zt_rxsig_t rxsig)
void zt_hooksig(struct zt_chan *chan, zt_rxsig_t rxsig)
{
/* skip if no change */
- if ((chan->rxhooksig) == rxsig) return;
zt_hooksig_pvt(chan,rxsig);
}
void zt_rbsbits(struct zt_chan *chan, int cursig)
{
- /* if A bit has changed */
- if ((chan->rxsig & ZT_ABIT) != (cursig & ZT_ABIT)) {
- switch(chan->sig) {
- case ZT_SIG_EM: /* E and M */
- case ZT_SIG_FXOLS: /* FXO Loopstart */
- case ZT_SIG_FXOGS: /* FXO Groundstart */
- case ZT_SIG_FXOKS: /* FXO Kewlstart */
- if (cursig & ZT_ABIT) /* went off hook */
- zt_hooksig_pvt(chan,ZT_RXSIG_OFFHOOK);
- else /* went on hook */
- zt_hooksig_pvt(chan,ZT_RXSIG_ONHOOK);
- 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 */
- zt_hooksig_pvt(chan,ZT_RXSIG_ONHOOK);
- 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 */
- zt_hooksig_pvt(chan,ZT_RXSIG_RING);
- break;
- case ZT_SIG_FXOGS: /* FXO Groundstart */
- if (!(cursig & ZT_BBIT)) /* if ground detected */
- zt_hooksig_pvt(chan,ZT_RXSIG_START);
+ if (cursig == chan->rxsig)
+ return;
+
+ switch(chan->sig) {
+ case ZT_SIG_FXOGS: /* FXO Groundstart */
+ /* B-bit only matters for FXO GS */
+ if (!(cursig & ZT_BBIT)) {
+ zt_hooksig_pvt(chan, ZT_RXSIG_START);
break;
- default:
+ }
+ /* Fall through */
+ case ZT_SIG_EM: /* E and M */
+ case ZT_SIG_FXOLS: /* FXO Loopstart */
+ case ZT_SIG_FXOKS: /* FXO Kewlstart */
+ if (cursig & ZT_ABIT) /* off hook */
+ zt_hooksig_pvt(chan,ZT_RXSIG_OFFHOOK);
+ else /* on hook */
+ zt_hooksig_pvt(chan,ZT_RXSIG_ONHOOK);
+ break;
+
+ case ZT_SIG_FXSKS: /* FXS Kewlstart */
+ case ZT_SIG_FXSGS: /* FXS Groundstart */
+ /* Fall through */
+ case ZT_SIG_FXSLS:
+ if (!(cursig & ZT_BBIT)) {
+ /* Check for ringing first */
+ zt_hooksig_pvt(chan, ZT_RXSIG_RING);
break;
- }
- }
+ }
+ if ((chan->sig != ZT_SIG_FXSLS) && (cursig & ZT_ABIT)) {
+ /* if went on hook */
+ zt_hooksig_pvt(chan, ZT_RXSIG_ONHOOK);
+ } else {
+ zt_hooksig_pvt(chan, ZT_RXSIG_OFFHOOK);
+ }
+ break;
+ default:
+ break;
+ }
/* Keep track of signalling for next time */
chan->rxsig = cursig;
}
@@ -3432,7 +3807,7 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
unsigned char *buf;
/* Linear version of received data */
int putlin,k;
-#ifdef CONFIG_ZAPATA_NET
+#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
/* SKB for receiving network stuff */
struct sk_buff *skb=NULL;
#endif
@@ -3444,10 +3819,9 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
if (ms->dialing) ms->afterdialingtimer = ZT_CHUNKSIZE * 50;
else if (ms->afterdialingtimer) ms->afterdialingtimer--;
if (ms->afterdialingtimer) rxc = 0x7f; /* receive as silence if dialing */
- if (ms->echocancel) {
+ if (ms->ec) {
putlin = ZT_XLAW(rxc, ms);
- putlin = process_cc(&ms->ec, ms->getlin_lastchunk[pos],
- abs(ms->getlin_lastchunk[pos]), putlin, abs(putlin));
+ putlin = echo_can_update(ms->ec, ms->getlin[pos], putlin);
rxc = ZT_LIN2X((int)putlin, ms);
}
@@ -3646,8 +4020,8 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
#if 0
printk("EOF, len is %d\n", ms->readn[ms->inreadbuf]);
#endif
-#ifdef CONFIG_ZAPATA_NET
- if (ms->flags & ZT_FLAG_NETDEV) {
+#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 */
@@ -3661,7 +4035,18 @@ static inline void zt_putbuf_byte(struct zt_chan *ss, unsigned char rxc, int pos
memcpy(skb->data, ms->readbuf[ms->inreadbuf], ms->readn[ms->inreadbuf]);
skb_put(skb, ms->readn[ms->inreadbuf]);
} else {
- ms->netdev.stats.rx_dropped++;
+#ifdef CONFIG_ZAPATA_NET
+ 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 1
+ ppp_input_error(ms->ppp, 0);
+#endif
+ }
+#endif
#if 1
printk("Memory squeeze, dropped one\n");
#endif
@@ -3719,15 +4104,21 @@ out in the later versions, and is put back now. */
#ifdef CONFIG_ZAPATA_NET
if (ms->flags & ZT_FLAG_NETDEV) {
- ms->netdev.stats.rx_errors++;
+ ms->hdlcnetdev->netdev.stats.rx_errors++;
if (abort == ZT_EVENT_OVERRUN)
- ms->netdev.stats.rx_over_errors++;
+ ms->hdlcnetdev->netdev.stats.rx_over_errors++;
if (abort == ZT_EVENT_BADFCS)
- ms->netdev.stats.rx_crc_errors++;
+ ms->hdlcnetdev->netdev.stats.rx_crc_errors++;
if (abort == ZT_EVENT_ABORT)
- ms->netdev.stats.rx_frame_errors++;
+ 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
+#endif
+
if ((ms->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
/* Notify the receiver... */
qevent(ss->master, abort);
@@ -3738,8 +4129,23 @@ out in the later versions, and is put back now. */
}
}
#ifdef CONFIG_ZAPATA_NET
- if (skb)
- hdlc_netif_rx(&ms->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);
+ }
#endif
}
@@ -3801,23 +4207,38 @@ static unsigned int zt_poll(struct file *file, struct poll_table_struct *wait_ta
int zt_transmit(struct zt_span *span)
{
- int x,y;
+ int x,y,z;
unsigned long flags;
for (x=0;x<span->channels;x++) {
spin_lock_irqsave(&span->chans[x].lock, flags);
- if (span->chans[x].otimer) {
- span->chans[x].otimer -= ZT_CHUNKSIZE;
- if (span->chans[x].otimer <= 0) {
- rbs_otimer_expire(&span->chans[x]);
- }
- }
- 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)];
+ if (&span->chans[x] == span->chans[x].master) {
+ if (span->chans[x].otimer) {
+ span->chans[x].otimer -= ZT_CHUNKSIZE;
+ if (span->chans[x].otimer <= 0) {
+ rbs_otimer_expire(&span->chans[x]);
+ }
}
- } else {
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- span->chans[x].writechunk[y] = zt_getbuf_byte(&span->chans[x], y);
+ 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)];
+ }
+ } else {
+ if (span->chans[x].slavemask) {
+ 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);
+ }
+ }
+ }
+ } else
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ span->chans[x].writechunk[y] = zt_getbuf_byte(&span->chans[x], y);
+ }
}
}
spin_unlock_irqrestore(&span->chans[x].lock, flags);
@@ -3840,18 +4261,46 @@ int zt_receive(struct zt_span *span)
unsigned long flags;
for (x=0;x<span->channels;x++) {
spin_lock_irqsave(&span->chans[x].lock, flags);
- for (y=0;y<ZT_CHUNKSIZE;y++) {
- zt_putbuf_byte(&span->chans[x], span->chans[x].readchunk[y], y);
- }
- if (span->chans[x].itimer) {
- span->chans[x].itimer -= ZT_CHUNKSIZE;
- if (span->chans[x].itimer <= 0) {
- rbs_itimer_expire(&span->chans[x]);
+ if (&span->chans[x] == span->chans[x].master) {
+ if (span->chans[x].slavemask) {
+ /* Must process each slave at the same time */
+ 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);
+ }
+ }
+ }
+ } else {
+ for (y=0;y<ZT_CHUNKSIZE;y++) {
+ zt_putbuf_byte(&span->chans[x], span->chans[x].readchunk[y], y);
+ }
+ }
+ if (span->chans[x].itimer) {
+ span->chans[x].itimer -= ZT_CHUNKSIZE;
+ if (span->chans[x].itimer <= 0) {
+ rbs_itimer_expire(&span->chans[x]);
+ }
}
}
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);
/* This is the master channel, so make things switch over */
rotate_sums();
/* do all the pseudo channel receives (getbuf's) */
@@ -3892,7 +4341,11 @@ int zt_receive(struct zt_span *span)
MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");
MODULE_DESCRIPTION("Zapata Telephony Interface");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
MODULE_PARM(debug, "i");
+MODULE_PARM(deftaps, "i");
static struct file_operations zt_fops = {
owner: THIS_MODULE,
@@ -3910,16 +4363,30 @@ static struct file_operations zt_fops = {
};
static int __init zt_init(void) {
- int res;
+ int res = 0;
+#ifdef CONFIG_DEVFS_FS
+ {
+ umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
+ devfs_register_chrdev(ZT_MAJOR, "zaptel", &zt_fops);
+ zaptel_devfs_dir = devfs_mk_dir(NULL, "zap", NULL);
+ if (!zaptel_devfs_dir) return -EBUSY; /* This would be bad */
+ channel = devfs_register(zaptel_devfs_dir, "channel", DEVFS_FL_DEFAULT, ZT_MAJOR, 254, mode, &zt_fops, NULL);
+ pseudo = devfs_register(zaptel_devfs_dir, "pseudo", DEVFS_FL_DEFAULT, ZT_MAJOR, 255, mode, &zt_fops, NULL);
+ ctl = devfs_register(zaptel_devfs_dir, "ctl", DEVFS_FL_DEFAULT, ZT_MAJOR, 0, mode, &zt_fops, NULL);
+ }
+#else
if ((res = register_chrdev(ZT_MAJOR, "zaptel", &zt_fops))) {
printk(KERN_ERR "Unable to register tor device on %d\n", ZT_MAJOR);
return res;
}
+#endif /* CONFIG_DEVFS_FS */
+
printk(KERN_INFO "Zapata Telephony Interface Registered on major %d\n", ZT_MAJOR);
zt_conv_init();
tone_zone_init();
fasthdlc_precalc();
rotate_sums();
+ rwlock_init(&chan_lock);
return res;
}
@@ -3929,7 +4396,15 @@ static void __exit zt_cleanup(void) {
for (x=0;x<ZT_TONE_ZONE_MAX;x++)
if (tone_zones[x])
kfree(tone_zones[x]);
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(channel);
+ devfs_unregister(pseudo);
+ devfs_unregister(ctl);
+ devfs_unregister(zaptel_devfs_dir);
+ devfs_unregister_chrdev(ZT_MAJOR, "zaptel");
+#else
unregister_chrdev(ZT_MAJOR, "zaptel");
+#endif
}
module_init(zt_init);