[zaptel-commits] trunk - r887 in /trunk: zaptel.c zaptel.h ztcfg.c
zaptel-commits at lists.digium.com
zaptel-commits at lists.digium.com
Tue Jan 10 16:06:30 CST 2006
Author: mattf
Date: Tue Jan 10 16:06:29 2006
New Revision: 887
URL: http://svn.digium.com/view/zaptel?rev=887&view=rev
Log:
Commits for HardHDLC API in zaptel (#5313)
Modified:
trunk/zaptel.c
trunk/zaptel.h
trunk/ztcfg.c
Modified: trunk/zaptel.c
URL: http://svn.digium.com/view/zaptel/trunk/zaptel.c?rev=887&r1=886&r2=887&view=diff
==============================================================================
--- trunk/zaptel.c (original)
+++ trunk/zaptel.c Tue Jan 10 16:06:29 2006
@@ -174,6 +174,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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];
- }
- 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 */
+ rxgain[j] = stack.gain.rxgain[j];
+ txgain[j] = stack.gain.txgain[j];
+ }
+
+ 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 @@
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_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 */
@@ -5807,8 +5858,6 @@
int abort=0;
int res;
int left, x;
-
- int bytes = ZT_CHUNKSIZE;
while(bytes) {
#if defined(CONFIG_ZAPATA_NET) || defined(CONFIG_ZAPATA_PPP)
@@ -5875,6 +5924,10 @@
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 @@
}
}
+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 @@
#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 @@
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 @@
}
} 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;
Modified: trunk/zaptel.h
URL: http://svn.digium.com/view/zaptel/trunk/zaptel.h?rev=887&r1=886&r2=887&view=diff
==============================================================================
--- trunk/zaptel.h (original)
+++ trunk/zaptel.h Tue Jan 10 16:06:29 2006
@@ -115,6 +115,7 @@
#define ZT_SIG_DACS (__ZT_SIG_DACS | ZT_SIG_CLEAR) /* Cross connect */
#define ZT_SIG_EM_E1 (1 << 17) /* E1 E&M Variation */
#define ZT_SIG_DACS_RBS ((1 << 18) | __ZT_SIG_DACS) /* Cross connect w/ RBS */
+#define ZT_SIG_HARDHDLC ((1 << 19) | ZT_SIG_CLEAR)
/* tone flag values */
#define ZT_REVERSE_RXTONE 1 /* reverse polarity rx tone logic */
@@ -1209,6 +1210,7 @@
#define ZT_FLAG_PPP (1 << 14) /* PPP is available */
#define ZT_FLAG_T1PPP (1 << 15)
#define ZT_FLAG_SIGFREEZE (1 << 16) /* Freeze signalling */
+#define ZT_FLAG_NOSTDTXRX (1 << 17) /* Do NOT do standard transmit and receive on every interrupt */
struct zt_span {
spinlock_t lock;
@@ -1295,6 +1297,9 @@
/* Opt: Dacs the contents of chan2 into chan1 if possible */
int (*dacs)(struct zt_chan *chan1, struct zt_chan *chan2);
+ /* Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */
+ void (*hdlc_hard_xmit)(struct zt_chan *chan);
+
/* Used by zaptel only -- no user servicable parts inside */
int spanno; /* Span number for zaptel */
int offset; /* Offset within a given card */
@@ -1356,6 +1361,20 @@
/* Prepare writechunk buffers on all channels for this span */
extern int zt_transmit(struct zt_span *span);
+
+/* Abort the buffer currently being receive with event "event" */
+extern void zt_hdlc_abort(struct zt_chan *ss, int event);
+
+/* Indicate to zaptel that the end of frame was received and rotate buffers */
+extern void zt_hdlc_finish(struct zt_chan *ss);
+
+/* Put a chunk of data into the current receive buffer */
+extern void zt_hdlc_putbuf(struct zt_chan *ss, unsigned char *rxb, int bytes);
+
+/* Get a chunk of data from the current transmit buffer. Returns -1 if no data
+ * is left to send, 0 if there is data remaining in the current message to be sent
+ * and 1 if the currently transmitted message is now done */
+extern int zt_hdlc_getbuf(struct zt_chan *ss, unsigned char *bufptr, unsigned int *size);
/* Register a span. Returns 0 on success, -1 on failure. Pref-master is non-zero if
Modified: trunk/ztcfg.c
URL: http://svn.digium.com/view/zaptel/trunk/ztcfg.c?rev=887&r1=886&r2=887&view=diff
==============================================================================
--- trunk/ztcfg.c (original)
+++ trunk/ztcfg.c Tue Jan 10 16:06:29 2006
@@ -571,6 +571,9 @@
} else if (!strcasecmp(keyword, "dchan")) {
sig[x] = "D-channel";
cc[x].sigtype = ZT_SIG_HDLCFCS;
+ } else if (!strcasecmp(keyword, "hardhdlc")) {
+ sig[x] = "Hardware assisted D-channel";
+ cc[x].sigtype = ZT_SIG_HARDHDLC;
} else {
fprintf(stderr, "Huh? (%s)\n", keyword);
}
@@ -1091,6 +1094,7 @@
{ "rawhdlc", chanconfig },
{ "nethdlc", chanconfig },
{ "fcshdlc", chanconfig },
+ { "hardhdlc", chanconfig },
{ "dchan", chanconfig },
{ "bchan", chanconfig },
{ "indclear", chanconfig },
More information about the zaptel-commits
mailing list