- /* 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;
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;
/* 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
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum