[svn-commits] trunk - r887 in /trunk: zaptel.c zaptel.h ztcfg.c

svn-commits at lists.digium.com svn-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 svn-commits mailing list