--- zaptel-1.4.9.2/kernel/ztdynamic.c	2010-04-07 16:52:31.000000000 -0400
+++ zaptel-1.4.9.2-harhdlc/kernel/ztdynamic.c	2010-04-16 10:54:51.000000000 -0400
@@ -79,7 +79,18 @@
 
 #define ZTD_FLAG_YELLOW_ALARM		(1 << 0)
 #define ZTD_FLAG_SIGBITS_PRESENT	(1 << 1)
-#define ZTD_FLAG_LOOPBACK			(1 << 2)
+#define ZTD_FLAG_LOOPBACK		(1 << 2)
+
+#define ZTD_SIG_SIZE(x)                 ((x) & 0x7)
+#define ZTD_SIG_STATUS(x)              (((x) >> 4) & 0x7)
+
+#define ZTD_SIG_OK                     0
+#define ZTD_SIG_ABORT                  1
+#define ZTD_SIG_OVERRUN                2
+#define ZTD_SIG_BADFCS                 3
+
+#define ZTD_SIG_CONT                   (1 << 7)
+#define ZTD_SIG_IS_LAST(x)             (((x) & ZTD_SIG_CONT) == 0)
 
 #define ERR_NSAMP					(1 << 16)
 #define ERR_NCHAN					(1 << 17)
@@ -100,6 +111,7 @@
 static void ztd_tasklet(unsigned long data);
 #endif
 
+static void ztd_hdlc_xmit(struct zt_chan *chan);
 
 struct zt_dynamic {
 	char addr[40];
@@ -117,6 +129,11 @@
 	int timing;
 	int master;
 	unsigned char *msgbuf;
+	
+	/*HDLC stuff */
+	struct zt_chan *sigchan;
+	atomic_t sigactive;
+	
 	struct list_head list;
 };
 
@@ -168,6 +185,7 @@
 	int msglen = 0;
 	int x;
 	int offset;
+	struct zt_span *span = &z->span;
 
 	/* Byte 0: Number of samples per channel */
 	*buf = ZT_CHUNKSIZE;
@@ -212,15 +230,82 @@
 	}
 	
 	for (x=0;x<z->span.channels;x++) {
+
 		memcpy(buf, z->chans[x].writechunk, ZT_CHUNKSIZE);
-		buf += ZT_CHUNKSIZE;
-		msglen += ZT_CHUNKSIZE;
+                buf += ZT_CHUNKSIZE;
+                msglen += ZT_CHUNKSIZE;
+
+		if ((ZT_SIG_HARDHDLC == (*span).chans[x].sig)) {
+			ztd_hdlc_xmit(z->sigchan);
+                }
 	}
 	
 	z->driver->transmit(z->pvt, z->msgbuf, msglen);
 	
 }
 
+static void ztdynamic_receive_hdlc(struct zt_chan *chan)
+{
+	unsigned char control = chan->readchunk[0];
+	static unsigned char fcs[2];
+	int size = ZTD_SIG_SIZE(control);
+
+	if (!size)
+                return;
+	
+	chan->readchunk[0] = 0;
+	
+	if (debug > 1 && printk_ratelimit()) {
+                printk(KERN_DEBUG "%s: control 0x%02x\n",
+                    __FUNCTION__, control);
+        }
+
+	if (ZTD_SIG_IS_LAST(control)) {
+                int abort_event = ZT_EVENT_NONE;
+
+                switch (ZTD_SIG_STATUS(control)) {
+                case ZTD_SIG_ABORT:
+                        abort_event = ZT_EVENT_ABORT;
+                        break;
+                case ZTD_SIG_OVERRUN:
+                        abort_event = ZT_EVENT_OVERRUN;
+                        break;
+                case ZTD_SIG_BADFCS:
+                        abort_event = ZT_EVENT_BADFCS;
+                        break;
+                }
+	
+		if (abort_event != ZT_EVENT_NONE) {
+                        if (debug) {
+                                printk(KERN_DEBUG "%s: dahdi_hdlc_abort(%d)\n",
+                                    __FUNCTION__, abort_event);
+                        }
+			zt_hdlc_abort(chan, abort_event);
+			return;
+
+		}
+	}
+	
+	if (debug > 1 && printk_ratelimit()) {
+                printk(KERN_DEBUG "%s: received HDLC frame chunk (%d bytes)\n",
+                    __FUNCTION__, size);
+        }
+
+	zt_hdlc_putbuf(chan, chan->readchunk + 1, size);
+	if (ZTD_SIG_IS_LAST(control)) {
+
+		if (debug > 1 && printk_ratelimit()) {
+                        printk(KERN_DEBUG "%s: received complete HDLC frame\n",
+                            __FUNCTION__);
+                }
+	
+	zt_hdlc_putbuf(chan, fcs, sizeof(fcs));
+	zt_hdlc_finish(chan);
+
+	}
+
+}
+
 static void __ztdynamic_run(void)
 {
 	struct zt_dynamic *z;
@@ -232,7 +317,15 @@
 			/* Ignore dead spans */
 			for (y=0;y<z->span.channels;y++) {
 				/* Echo cancel double buffered data */
-				zt_ec_chunk(&z->span.chans[y], z->span.chans[y].readchunk, z->span.chans[y].writechunk);
+				
+				if (z->span.chans[y].sig != ZT_SIG_HARDHDLC){
+		 
+					zt_ec_chunk(&z->span.chans[y], z->span.chans[y].readchunk, z->span.chans[y].writechunk);
+				} else {
+				
+					ztdynamic_receive_hdlc(&z->span.chans[y]);
+				}
+
 			}
 			zt_receive(&z->span);
 			zt_transmit(&z->span);
@@ -384,6 +477,7 @@
 		newalarm |= ZT_ALARM_YELLOW;
 
 	if (newalarm != span->alarms) {
+		atomic_set(&ztd->sigactive, 0);
 		span->alarms = newalarm;
 		zt_alarm_notify(span);
 		checkmaster();
@@ -510,6 +604,32 @@
 
 static int ztd_chanconfig(struct zt_chan *chan, int sigtype)
 {
+	//unsigned long flags;
+	struct zt_dynamic *z = chan->span->pvt;
+
+	if (!z)
+              return 0;
+
+	if (sigtype == ZT_SIG_HARDHDLC || z->sigchan == chan) {
+
+		spin_lock(&dspan_lock);
+		z->sigchan = (sigtype == ZT_SIG_HARDHDLC) ? chan : NULL;
+		atomic_set(&z->sigactive, 0);
+		if (debug) {
+                       printk(KERN_DEBUG "%s: chan %s(%d): sigchan %p\n",
+                           __FUNCTION__, chan->name, chan->channo, z->sigchan);
+               	}
+		spin_unlock(&dspan_lock);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
+        	synchronize_kernel();
+#else
+        	synchronize_rcu();
+#endif
+	
+		
+
+	}
 	return 0;
 }
 
@@ -529,6 +649,65 @@
 	return 0;
 }
 
+
+
+static void ztd_hdlc_xmit(struct zt_chan *chan)
+{
+	int res;
+	unsigned size = ZT_CHUNKSIZE - 1;
+	struct zt_dynamic *z = chan->span->pvt;
+	
+	chan->writechunk[0] = 0;
+	
+	res = zt_hdlc_getbuf(chan, chan->writechunk + 1, &size);
+
+	if (size == 0) {
+		atomic_set(&z->sigactive, 0);
+		if (debug > 1 && printk_ratelimit())
+			printk(KERN_DEBUG "%s: no more data\n", __FUNCTION__);
+		return;
+
+	}
+
+	if (debug > 1 && printk_ratelimit()) {
+		printk(KERN_DEBUG "%s: %d bytes of data (res %d)\n",
+			__FUNCTION__, size, res);
+	}
+
+	chan->writechunk[0] |= size & 0x7;
+	if (res == 0)
+		chan->writechunk[0] |= ZTD_SIG_CONT;
+	
+}
+static void ztd_hdlc_hard_xmit(struct zt_chan *chan)
+{
+
+	struct zt_chan *sigchan;
+	struct zt_dynamic *z = chan->span->pvt;
+	
+	rcu_read_lock();
+	sigchan = z->sigchan;
+	rcu_read_unlock();
+
+	if (sigchan == NULL) {
+		printk(KERN_NOTICE "%s: Invalid (NULL) signalling channel\n",
+			__FUNCTION__);
+		return;
+	}
+
+	if (sigchan != chan || atomic_read(&z->sigactive)) {
+               if (debug > 1 && printk_ratelimit()) {
+                       printk(KERN_DEBUG "%s: invalid channel (sigchan %p, chan %p) or transmitter active\n",
+                           __FUNCTION__, sigchan, chan);
+               }
+               return;
+       	}
+	atomic_set(&z->sigactive, 1);
+	ztd_hdlc_xmit(sigchan);
+	
+	
+}
+
 static int create_dynamic(ZT_DYNAMIC_SPAN *zds)
 {
 	struct zt_dynamic *z;
@@ -595,12 +774,16 @@
 	z->span.open = ztd_open;
 	z->span.close = ztd_close;
 	z->span.chanconfig = ztd_chanconfig;
+	z->span.hdlc_hard_xmit = ztd_hdlc_hard_xmit;
+	z->sigchan = NULL;
+	atomic_set(&z->sigactive, 0);
+
 	for (x=0;x<zds->numchans;x++) {
 		sprintf(z->chans[x].name, "ZTD/%s/%s/%d", zds->driver, zds->addr, x+1);
 		z->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS |
 				     ZT_SIG_FXSKS | ZT_SIG_FXSGS | ZT_SIG_FXOLS |
 				     ZT_SIG_FXOKS | ZT_SIG_FXOGS | ZT_SIG_SF | 
-				     ZT_SIG_DACS_RBS | ZT_SIG_CAS;
+				     ZT_SIG_DACS_RBS | ZT_SIG_CAS | ZT_SIG_HARDHDLC;
 		z->chans[x].chanpos = x + 1;
 		z->chans[x].pvt = z;
 	}
@@ -769,6 +952,7 @@
 			if (z->span.alarms != newalarm) {
 				z->span.alarms = newalarm;
 				zt_alarm_notify(&z->span);
+				atomic_set(&z->sigactive, 0);
 				alarmchanged++;
 			}
 		}

