summaryrefslogtreecommitdiff
path: root/zaptel.c
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-01-10 22:06:29 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-01-10 22:06:29 +0000
commit46962b1907b7c476a969e898f682e82405ef317e (patch)
tree26df36eae566ccde4c3f71897e0951463038d822 /zaptel.c
parent55dd99f511d3d3aa8e91c013b18c5771c319fcf5 (diff)
Commits for HardHDLC API in zaptel (#5313)
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@887 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'zaptel.c')
-rw-r--r--zaptel.c273
1 files changed, 244 insertions, 29 deletions
diff --git a/zaptel.c b/zaptel.c
index 4ccd3e8..1dad83d 100644
--- a/zaptel.c
+++ b/zaptel.c
@@ -174,6 +174,10 @@ EXPORT_SYMBOL(zt_alarm_notify);
EXPORT_SYMBOL(zt_set_dynamic_ioctl);
EXPORT_SYMBOL(zt_ec_chunk);
EXPORT_SYMBOL(zt_ec_span);
+EXPORT_SYMBOL(zt_hdlc_abort);
+EXPORT_SYMBOL(zt_hdlc_finish);
+EXPORT_SYMBOL(zt_hdlc_getbuf);
+EXPORT_SYMBOL(zt_hdlc_putbuf);
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_entries[ZT_MAX_SPANS];
@@ -499,6 +503,8 @@ static char *sigstr(int sig)
return "HDLCFCS";
case ZT_SIG_HDLCNET:
return "HDLCNET";
+ case ZT_SIG_HARDHDLC:
+ return "Hardware-assisted HDLC";
case ZT_SIG_SLAVE:
return "Slave";
case ZT_SIG_CAS:
@@ -971,7 +977,9 @@ static void close_channel(struct zt_chan *chan)
struct ppp_channel *ppp;
#endif
- zt_reallocbufs(chan, 0, 0);
+ /* XXX Buffers should be send out before reallocation!!! XXX */
+ if (!(chan->flags & ZT_FLAG_NOSTDTXRX))
+ zt_reallocbufs(chan, 0, 0);
spin_lock_irqsave(&chan->lock, flags);
#ifdef CONFIG_ZAPATA_PPP
ppp = chan->ppp;
@@ -1670,7 +1678,7 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u
spin_lock_irqsave(&chan->lock, flags);
if (chan->eventinidx != chan->eventoutidx) {
spin_unlock_irqrestore(&chan->lock, flags);
- return -ELAST;
+ return -ELAST /* - chan->eventbuf[chan->eventoutidx]*/;
}
res = chan->outreadbuf;
if (chan->rxdisable)
@@ -1683,6 +1691,20 @@ static ssize_t zt_chan_read(struct file *file, char *usrbuf, size_t count, int u
if (rv) return (rv);
}
amnt = count;
+/* added */
+#if 0
+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) {
+ int myamnt = amnt;
+ int x;
+ if (amnt > chan->readn[chan->outreadbuf])
+ myamnt = chan->readn[chan->outreadbuf];
+ printk("zt_chan_read(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n",
+ unit, chan->inwritebuf, chan->outwritebuf, myamnt);
+ printk("\t("); for (x = 0; x < myamnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]);
+ printk(")\n");
+ }
+#endif
+/* end addition */
if (chan->flags & ZT_FLAG_LINEAR) {
if (amnt > (chan->readn[chan->outreadbuf] << 1))
amnt = chan->readn[chan->outreadbuf] << 1;
@@ -1782,6 +1804,15 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
printk("zt_chan_write(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n",
unit, chan->inwritebuf, chan->outwritebuf, amnt);
#endif
+#if 0
+ if ((unit == 24) || (unit == 48) || (unit == 16) || (unit == 47)) {
+ int x;
+ printk("zt_chan_write/in(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d, txdisable: %d)\n",
+ unit, chan->inwritebuf, chan->outwritebuf, amnt, chan->txdisable);
+ printk("\t("); for (x = 0; x < amnt; x++) printk((x ? " %02x" : "%02x"), (unsigned char)usrbuf[x]);
+ printk(")\n");
+ }
+#endif
if (amnt) {
if (chan->flags & ZT_FLAG_LINEAR) {
@@ -1826,6 +1857,9 @@ static ssize_t zt_chan_write(struct file *file, const char *usrbuf, size_t count
chan->outwritebuf = oldbuf;
}
spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (chan->flags & ZT_FLAG_NOSTDTXRX && chan->span->hdlc_hard_xmit)
+ chan->span->hdlc_hard_xmit(chan);
}
return amnt;
}
@@ -2000,7 +2034,7 @@ static int zt_hangup(struct zt_chan *chan)
if (!chan->span)
return 0;
/* Can't hang up a clear channel */
- if (chan->flags & ZT_FLAG_CLEAR)
+ if (chan->flags & (ZT_FLAG_CLEAR | ZT_FLAG_NOSTDTXRX))
return -EINVAL;
chan->kewlonhook = 0;
@@ -2150,11 +2184,11 @@ static int initialize_channel(struct zt_chan *chan)
zt_set_law(chan,0);
zt_hangup(chan);
- /* Make sure that the audio flag is cleared on a clear channel */
- if (chan->sig & ZT_SIG_CLEAR)
+ /* Make sure that the audio flag is cleared on a clear channel */
+ if ((chan->sig & ZT_SIG_CLEAR) || (chan->sig & ZT_SIG_HARDHDLC))
chan->flags &= ~ZT_FLAG_AUDIO;
- if (chan->sig == ZT_SIG_CLEAR)
+ if ((chan->sig == ZT_SIG_CLEAR) || (chan->sig == ZT_SIG_HARDHDLC))
chan->flags &= ~(ZT_FLAG_PPP | ZT_FLAG_FCS | ZT_FLAG_HDLC);
chan->flags &= ~ZT_FLAG_LINEAR;
@@ -2796,10 +2830,11 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
struct zt_params param;
} stack;
struct zt_chan *chan;
+ unsigned long flags;
+ unsigned char *txgain, *rxgain;
#ifdef ALLOW_CHAN_DIAG
/* This structure is huge and will bork a 4k stack */
struct zt_chan mychan;
- unsigned long flags;
#endif
int i,j;
int return_master = 0;
@@ -2937,30 +2972,39 @@ static int zt_common_ioctl(struct inode *node, struct file *file, unsigned int c
/* make sure channel number makes sense */
if ((i < 0) || (i > ZT_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
if (!(chans[i]->flags & ZT_FLAG_AUDIO)) return (-EINVAL);
- if (!chans[i]->gainalloc) {
- chans[i]->rxgain = kmalloc(512, GFP_KERNEL);
- if (!chans[i]->rxgain) {
- chans[i]->rxgain = defgain;
- return -ENOMEM;
- } else {
- chans[i]->gainalloc = 1;
- chans[i]->txgain = chans[i]->rxgain + 256;
- }
- }
+
+ rxgain = kmalloc(512, GFP_KERNEL);
+ if (!rxgain)
+ return -ENOMEM;
+
stack.gain.chan = i; /* put the span # in here */
+ txgain = rxgain + 256;
+
for (j=0;j<256;j++) {
- chans[i]->rxgain[j] = stack.gain.rxgain[j];
- chans[i]->txgain[j] = stack.gain.txgain[j];
+ rxgain[j] = stack.gain.rxgain[j];
+ txgain[j] = stack.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 */
+
+ if (!memcmp(rxgain, defgain, 256) &&
+ !memcmp(txgain, defgain, 256)) {
+ if (rxgain)
+ kfree(rxgain);
+ spin_lock_irqsave(&chans[i]->lock, flags);
if (chans[i]->gainalloc)
kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 0;
chans[i]->rxgain = defgain;
chans[i]->txgain = defgain;
- chans[i]->gainalloc = 0;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ } else {
+ /* This is a custom gain setting */
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 1;
+ chans[i]->rxgain = rxgain;
+ chans[i]->txgain = txgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
}
if (copy_to_user((struct zt_gains *) data,&stack.gain,sizeof(stack.gain)))
return -EFAULT;
@@ -3262,6 +3306,12 @@ static int zt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (newmaster != chans[ch.chan]) {
recalc_slaves(chans[ch.chan]->master);
}
+ if ((ch.sigtype & ZT_SIG_HARDHDLC) == ZT_SIG_HARDHDLC) {
+ chans[ch.chan]->flags &= ~ZT_FLAG_FCS;
+ chans[ch.chan]->flags &= ~ZT_FLAG_HDLC;
+ chans[ch.chan]->flags |= ZT_FLAG_NOSTDTXRX;
+ } else
+ chans[ch.chan]->flags &= ~ZT_FLAG_NOSTDTXRX;
}
#ifdef CONFIG_ZAPATA_NET
if (!res &&
@@ -5791,7 +5841,8 @@ static inline void __zt_process_putaudio_chunk(struct zt_chan *ss, unsigned char
}
}
-static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
+/* HDLC (or other) receiver buffer functions for read side */
+static inline void __putbuf_chunk(struct zt_chan *ss, unsigned char *rxb, int bytes)
{
/* We transmit data from our master channel */
/* Called with ss->lock held */
@@ -5808,8 +5859,6 @@ static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
int res;
int left, x;
- int bytes = ZT_CHUNKSIZE;
-
while(bytes) {
#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
skb = NULL;
@@ -5875,6 +5924,10 @@ static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
bytes -= left;
/* End of frame is decided by block size of 'N' */
eof = (ms->readidx[ms->inreadbuf] >= ms->blocksize);
+ if (eof && (ss->flags & ZT_FLAG_NOSTDTXRX)) {
+ eof = 0;
+ abort = ZT_EVENT_OVERRUN;
+ }
}
if (eof) {
/* Finished with this buffer, try another. */
@@ -6059,6 +6112,162 @@ out in the later versions, and is put back now. */
}
}
+static inline void __zt_putbuf_chunk(struct zt_chan *ss, unsigned char *rxb)
+{
+ __putbuf_chunk(ss, rxb, ZT_CHUNKSIZE);
+}
+
+extern void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes)
+{
+ unsigned long flags;
+ int res;
+ int left;
+
+ spin_lock_irqsave(&ss->lock, flags);
+ if (ss->inreadbuf < 0) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("No place to receive HDLC frame\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+ /* Read into the current buffer */
+ left = ss->blocksize - ss->readidx[ss->inreadbuf];
+ if (left > bytes)
+ left = bytes;
+ if (left > 0) {
+ memcpy(ss->readbuf[ss->inreadbuf] + ss->readidx[ss->inreadbuf], rxb, left);
+ rxb += left;
+ ss->readidx[ss->inreadbuf] += left;
+ bytes -= left;
+ }
+ /* Something isn't fit into buffer */
+ if (bytes) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("HDLC frame isn't fit into buffer space\n");
+#endif
+ zt_hdlc_abort(ss, ZT_EVENT_OVERRUN);
+ }
+ res = left;
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+extern void zt_hdlc_abort(struct zt_chan *ss, int event)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ss->lock, flags);
+ if (ss->inreadbuf >= 0)
+ ss->readidx[ss->inreadbuf] = 0;
+ if ((ss->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
+ __qevent(ss->master, event);
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+extern void zt_hdlc_finish(struct zt_chan *ss)
+{
+ int oldreadbuf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ss->lock, flags);
+
+ if ((oldreadbuf = ss->inreadbuf) < 0) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("No buffers to finish\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+
+ if (!ss->readidx[ss->inreadbuf]) {
+#ifdef CONFIG_ZAPATA_DEBUG
+ printk("Empty HDLC frame received\n");
+#endif
+ spin_unlock_irqrestore(&ss->lock, flags);
+ return;
+ }
+
+ ss->readn[ss->inreadbuf] = ss->readidx[ss->inreadbuf];
+ ss->inreadbuf = (ss->inreadbuf + 1) % ss->numbufs;
+ if (ss->inreadbuf == ss->outreadbuf) {
+ ss->inreadbuf = -1;
+#if CONFIG_ZAPATA_DEBUG
+ printk("Notifying reader data in block %d\n", oldreadbuf);
+#endif
+ ss->rxdisable = 0;
+ }
+ if (ss->outreadbuf < 0) {
+ ss->outreadbuf = oldreadbuf;
+ }
+
+ if (!ss->rxdisable) {
+ wake_up_interruptible(&ss->readbufq);
+ wake_up_interruptible(&ss->sel);
+ if (ss->iomask & ZT_IOMUX_READ)
+ wake_up_interruptible(&ss->eventbufq);
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+/* Returns 1 if EOF, 0 if data is still in frame, -1 if EOF and no buffers left */
+extern int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size)
+{
+ unsigned char *buf;
+ unsigned long flags;
+ int left = 0;
+ int res;
+ int oldbuf;
+
+ spin_lock_irqsave(&ss->lock, flags);
+ if (ss->outwritebuf > -1) {
+ buf = ss->writebuf[ss->outwritebuf];
+ left = ss->writen[ss->outwritebuf] - ss->writeidx[ss->outwritebuf];
+ /* Strip off the empty HDLC CRC end */
+ left -= 2;
+ if (left <= *size) {
+ *size = left;
+ res = 1;
+ } else
+ res = 0;
+
+ memcpy(bufptr, &buf[ss->writeidx[ss->outwritebuf]], *size);
+ ss->writeidx[ss->outwritebuf] += *size;
+
+ if (res) {
+ /* Rotate buffers */
+ oldbuf = ss->outwritebuf;
+ ss->writeidx[oldbuf] = 0;
+ ss->writen[oldbuf] = 0;
+ ss->outwritebuf = (ss->outwritebuf + 1) % ss->numbufs;
+ if (ss->outwritebuf == ss->inwritebuf) {
+ ss->outwritebuf = -1;
+ if (ss->iomask & (ZT_IOMUX_WRITE | ZT_IOMUX_WRITEEMPTY))
+ wake_up_interruptible(&ss->eventbufq);
+ /* If we're only supposed to start when full, disable the transmitter */
+ if (ss->txbufpolicy == ZT_POLICY_WHEN_FULL)
+ ss->txdisable = 1;
+ res = -1;
+ }
+
+ if (ss->inwritebuf < 0)
+ ss->inwritebuf = oldbuf;
+
+ if (!(ss->flags & (ZT_FLAG_NETDEV | ZT_FLAG_PPP))) {
+ wake_up_interruptible(&ss->writebufq);
+ wake_up_interruptible(&ss->sel);
+ if ((ss->iomask & ZT_IOMUX_WRITE) && (res >= 0))
+ wake_up_interruptible(&ss->eventbufq);
+ }
+ }
+ } else {
+ res = -1;
+ *size = 0;
+ }
+ spin_unlock_irqrestore(&ss->lock, flags);
+
+ return res;
+}
+
+
static void process_timers(void)
{
unsigned long flags;
@@ -6271,6 +6480,10 @@ int zt_transmit(struct zt_span *span)
#if 1
for (x=0;x<span->channels;x++) {
spin_lock_irqsave(&span->chans[x].lock, flags);
+ if (span->chans[x].flags & ZT_FLAG_NOSTDTXRX) {
+ spin_unlock_irqrestore(&span->chans[x].lock, flags);
+ continue;
+ }
if (&span->chans[x] == span->chans[x].master) {
if (span->chans[x].otimer) {
span->chans[x].otimer -= ZT_CHUNKSIZE;
@@ -6352,7 +6565,8 @@ int zt_receive(struct zt_span *span)
do {
data[pos++] = span->chans[z].readchunk[y];
if (pos == ZT_CHUNKSIZE) {
- __zt_receive_chunk(&span->chans[x], data);
+ if(!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX))
+ __zt_receive_chunk(&span->chans[x], data);
pos = 0;
}
z=span->chans[z].nextslave;
@@ -6360,7 +6574,8 @@ int zt_receive(struct zt_span *span)
}
} else {
/* Process a normal channel */
- __zt_real_receive(&span->chans[x]);
+ if (!(span->chans[x].flags & ZT_FLAG_NOSTDTXRX))
+ __zt_real_receive(&span->chans[x]);
}
if (span->chans[x].itimer) {
span->chans[x].itimer -= ZT_CHUNKSIZE;