Index: fxotune.c
===================================================================
RCS file: /usr/cvsroot/zaptel/fxotune.c,v
retrieving revision 1.28
diff -u -r1.28 fxotune.c
--- fxotune.c	19 Sep 2005 18:52:35 -0000	1.28
+++ fxotune.c	4 Oct 2005 16:49:11 -0000
@@ -48,6 +48,8 @@
 
 static short outbuf[TEST_DURATION];
 static int debug = 0;
+static int record = 1;
+static int recordfd = 1;
 
 
 /* Generates a tone of hz frequency.  Index is the current sample
@@ -204,6 +206,8 @@
 					return -1;
 				}
 
+				usleep(500000);
+
 				memset(&dop, 0, sizeof(dop));
 				dop.op = ZT_DIAL_OP_REPLACE;
 				dop.dialstr[0] = 'T';
@@ -239,6 +243,14 @@
 				return -1;
 			}
 
+			if (record) {
+				char ourfile[128];
+				sprintf(ourfile, "/tmp/acim%dfreq%d.raw", acim, freq);
+				recordfd = open(ourfile, O_CREAT|O_TRUNC|O_RDWR);
+				write(recordfd, inbuf, BUFFER_LENGTH);
+				close(recordfd);
+			}
+
 			/* calculate power of response */
 			
 			freq_results[(freq/200)-1] = power_of(inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1);
Index: wct4xxp.c
===================================================================
RCS file: /usr/cvsroot/zaptel/wct4xxp.c,v
retrieving revision 1.91
diff -u -r1.91 wct4xxp.c
--- wct4xxp.c	29 Sep 2005 14:00:57 -0000	1.91
+++ wct4xxp.c	4 Oct 2005 16:49:11 -0000
@@ -33,6 +33,8 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
 #ifdef STANDALONE_ZAPATA
 #include "zaptel.h"
 #else
@@ -170,6 +172,7 @@
 static int highestorder;
 static int t1e1override = -1;
 static int j1mode = 0;
+static int sigmode = FRMR_MODE_NO_ADDR_CMP;
 static int loopback = 0;
 static int alarmdebounce = 0;
 #ifdef VPM_SUPPORT
@@ -251,6 +254,14 @@
 	unsigned char ec_chunk2[31][ZT_CHUNKSIZE]; /* second EC chunk buffer */
 #endif
 	int irqmisses;
+	
+	/* HDLC controller fields */
+	struct zt_chan *sigchan;
+	unsigned char sigmode;
+	int sigactive;
+	int frames_out;
+	int frames_in;
+
 #ifdef VPM_SUPPORT
 	unsigned int dtmfactive;
 	unsigned int dtmfmask;
@@ -334,6 +345,7 @@
 #ifdef SUPPORT_GEN1
 static int t4_reset_dma(struct t4 *wc);
 #endif
+static void t4_hdlc_hard_xmit(struct zt_chan *chan);
 static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data);
 static void t4_tsi_assign(struct t4 *wc, int fromspan, int fromchan, int tospan, int tochan);
 static void t4_tsi_unassign(struct t4 *wc, int tospan, int tochan);
@@ -349,11 +361,12 @@
 /* #define WC_GPIO		5 */
 #define WC_VERSION	6
 #define WC_LEDS		7
-#define WC_ACTIVATE	(1 << 12)
 #define WC_GPIOCTL	8
 #define WC_GPIO		9
 #define WC_LADDR	10
 #define WC_LDATA		11
+#define WC_LFRMR_CS	(1 << 10)	/* Framer's ChipSelect signal */
+#define WC_ACTIVATE	(1 << 12)
 #define WC_LREAD			(1 << 15)
 #define WC_LWRITE		(1 << 16)
 
@@ -374,23 +387,24 @@
 #define MAX_TDM_CHAN 32
 #define MAX_DTMF_DET 16
 
+static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr)
+{
+	unsigned int res = le32_to_cpu(wc->membase[addr]);
+	return res;
+}
+
 static inline void __t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
 {
 	unsigned int tmp;
 	wc->membase[addr] = cpu_to_le32(value);
 #if 1
-	tmp = le32_to_cpu(wc->membase[addr]);
+	tmp = __t4_pci_in(wc, addr);
 	if ((value != tmp) && (addr != WC_LEDS) && (addr != WC_LDATA) &&
 		(addr != WC_GPIO) && (addr != WC_INTR))
 		printk("Tried to load %08x into %08x, but got %08x instead\n", value, addr, tmp);
 #endif		
 }
 
-static inline unsigned int __t4_pci_in(struct t4 *wc, const unsigned int addr)
-{
-	return le32_to_cpu(wc->membase[addr]);
-}
-
 static inline void t4_pci_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
 {
 	unsigned long flags;
@@ -430,9 +444,9 @@
 	unsigned int ret;
 	unit &= 0x3;
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
-	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | ( 1 << 10) | WC_LREAD);
+	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LREAD);
 	ret = __t4_pci_in(wc, WC_LDATA);
-	__t4_pci_out(wc, WC_LADDR, 0);
+ 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
 	return ret & 0xff;
 }
 
@@ -454,15 +468,13 @@
 		printk("Writing %02x to address %02x of unit %d\n", value, addr, unit);
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));
 	__t4_pci_out(wc, WC_LDATA, value);
-	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));
-	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10) | WC_LWRITE);
-	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | (1 << 10));
+	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff) | WC_LFRMR_CS | WC_LWRITE);
 	__t4_pci_out(wc, WC_LADDR, (unit << 8) | (addr & 0xff));	
-	__t4_pci_out(wc, WC_LADDR, 0);
 	if (debug & DEBUG_REGS) printk("Write complete\n");
 #if 0
+	if ((addr != FRMR_TXFIFO) && (addr != FRMR_CMDR) && (addr != 0xbc))
 	{ unsigned int tmp;
-	tmp = t4_framer_in(wc, unit, addr);
+	tmp = __t4_framer_in(wc, unit, addr);
 	if (tmp != value) {
 		printk("Expected %d from unit %d register %d but got %d instead\n", value, unit, addr, tmp);
 	} }
@@ -608,6 +620,112 @@
 }
 #endif
 
+static void __hdlc_stop(struct t4 *wc, unsigned int span)
+{
+	struct t4_span *t = wc->tspans[span];
+	unsigned char imr0, imr1, mode;
+	int i = 0;
+
+	/* Clear receive and transmit timeslots */
+	for (i = 0; i < 4; i++) {
+		__t4_framer_out(wc, span, FRMR_RTR_BASE + i, 0x00);
+		__t4_framer_out(wc, span, FRMR_TTR_BASE + i, 0x00);
+	}
+
+	imr0 = __t4_framer_in(wc, span, FRMR_IMR0);
+	imr1 = __t4_framer_in(wc, span, FRMR_IMR1);
+
+	/* Disable HDLC interrupts */
+	imr0 |= FRMR_IMR0_RME | FRMR_IMR0_RPF;
+	__t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+#if 0
+	imr1 |= FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR;
+#endif
+	imr1 |= FRMR_IMR1_XDU | FRMR_IMR1_XPR;
+	__t4_framer_out(wc, span, FRMR_IMR1, imr1);
+
+	mode = __t4_framer_in(wc, span, FRMR_MODE);
+	mode &= ~FRMR_MODE_HRAC;
+	__t4_framer_out(wc, span, FRMR_MODE, mode);
+
+	t->sigchan = NULL;
+	t->sigactive = 0;
+}
+
+static inline void __t4_framer_cmd(struct t4 *wc, unsigned int span, int cmd)
+{
+	__t4_framer_out(wc, span, FRMR_CMDR, cmd);
+}
+
+static inline void __t4_framer_cmd_wait(struct t4 *wc, unsigned int span, int cmd)
+{
+	int sis;
+	int loops = 0;
+
+	/* XXX could be time consuming XXX */
+	for (;;) {
+		sis = __t4_framer_in(wc, span, FRMR_SIS);
+		if (!(sis & 0x04))
+			break;
+		if (!loops++) {
+			printk("!!!SIS Waiting before cmd %02x\n", cmd);
+		}
+	}
+	if (loops)
+		printk("!!!SIS waited %d loops\n", loops);
+
+	__t4_framer_out(wc, span, FRMR_CMDR, cmd);
+}
+
+static int __hdlc_start(struct t4 *wc, unsigned int span, struct zt_chan *chan, unsigned char mode)
+{
+	struct t4_span *t = wc->tspans[span];
+	unsigned char imr0, imr1;
+	int offset = chan->chanpos;
+
+	if (debug & DEBUG_FRAMER) printk("Initializing signalling controller for channel %d span %d\n", chan->chanpos, chan->span->offset);
+
+	if (mode != FRMR_MODE_NO_ADDR_CMP)
+		return -1;
+
+	mode |= FRMR_MODE_HRAC;
+
+	/* Make sure we're in the right mode */
+	__t4_framer_out(wc, span, FRMR_MODE, mode);
+	__t4_framer_out(wc, span, FRMR_TSEO, 0x00);
+	__t4_framer_out(wc, span, FRMR_TSBS1, 0xff);
+
+	/* Set the interframe gaps, etc */
+	__t4_framer_out(wc, span, FRMR_CCR1, FRMR_CCR1_ITF|FRMR_CCR1_EITS);
+
+	__t4_framer_out(wc, span, FRMR_CCR2, FRMR_CCR2_RCRC);
+	
+	/* Set up the time slot that we want to tx/rx on */
+	__t4_framer_out(wc, span, FRMR_TTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
+	__t4_framer_out(wc, span, FRMR_RTR_BASE + (offset / 8), (0x80 >> (offset % 8)));
+
+	imr0 = __t4_framer_in(wc, span, FRMR_IMR0);
+	imr1 = __t4_framer_in(wc, span, FRMR_IMR1);
+
+	/* Enable our interrupts again */
+	imr0 &= ~(FRMR_IMR0_RME | FRMR_IMR0_RPF);
+	__t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+#if 0
+	imr1 &= ~(FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR);
+#endif
+	imr1 &= ~(FRMR_IMR1_XDU | FRMR_IMR1_XPR);
+	__t4_framer_out(wc, span, FRMR_IMR1, imr1);
+
+	/* Reset the signaling controller */
+	__t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
+
+	t->sigchan = chan;
+	t->sigactive = 0;
+
+	return 0;
+}
 
 static void __set_clear(struct t4 *wc, int span)
 {
@@ -791,6 +909,58 @@
 	return 0;
 }
 
+static void inline __t4_hdlc_xmit_fifo(struct t4 *wc, unsigned int span, struct t4_span *ts)
+{
+	int res, i, size = 32;
+	unsigned char buf[32];
+
+	res = zt_hdlc_getbuf(ts->sigchan, buf, &size);
+	if (debug & DEBUG_FRAMER) printk("Got buffer sized %d and res %d for %d\n", size, res, span);
+	if (size > 0) {
+		ts->sigactive = 1;
+
+		if (debug & DEBUG_FRAMER) {
+			printk("TX(");
+			for (i = 0; i < size; i++)
+				printk((i ? " %02x" : "%02x"), buf[i]);
+			printk(")\n");
+		}
+
+		for (i = 0; i < size; i++)
+			__t4_framer_out(wc, span, FRMR_TXFIFO, buf[i]);
+
+		if (res) /* End of message */ {
+			if (debug & DEBUG_FRAMER) printk("transmiting XHF|XME\n");
+			__t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF | FRMR_CMDR_XME);
+#if 0
+			ts->sigactive = (__t4_framer_in(wc, span, FRMR_SIS) & FRMR_SIS_XFW) ? 0 : 1;
+#endif
+			++ts->frames_out;
+			if ((debug & DEBUG_FRAMER) && !(ts->frames_out & 0x0f))
+				printk("Transmitted %d frames on span %d\n", ts->frames_out, span);
+		} else { /* Still more to transmit */
+			if (debug & DEBUG_FRAMER) printk("transmiting XHF\n");
+			__t4_framer_cmd_wait(wc, span, FRMR_CMDR_XHF);
+		}
+	}
+	else if (res < 0)
+		ts->sigactive = 0;
+}
+
+static void t4_hdlc_hard_xmit(struct zt_chan *chan)
+{
+	struct t4 *wc = chan->pvt;
+	int span = chan->span->offset;
+	struct t4_span *ts = wc->tspans[span];
+	unsigned long flags; 
+
+	spin_lock_irqsave(&wc->reglock, flags);
+	if (debug & DEBUG_FRAMER) printk("t4_hdlc_hard_xmit, sigactive=%d\n", ts->sigactive);
+	if ((ts->sigchan == chan) && !ts->sigactive)
+		__t4_hdlc_xmit_fifo(wc, span, ts);
+	spin_unlock_irqrestore(&wc->reglock, flags);
+}
+
 static int t4_maint(struct zt_span *span, int cmd)
 {
 	struct t4_span *ts = span->pvt;
@@ -922,6 +1092,11 @@
 	span->flags &= ~ZT_FLAG_RUNNING;
 	if (wasrunning)
 		wc->spansstarted--;
+
+	/* Stop HDLC controller if runned */
+	if (ts->sigchan)
+		__hdlc_stop(wc, ts->sigchan->span->offset);
+
 	__t4_set_led(wc, span->offset, WC_OFF);
 	if (((wc->numspans == 4) && 
 	    (!(wc->tspans[0]->span.flags & ZT_FLAG_RUNNING)) &&
@@ -978,6 +1153,15 @@
 		wc->tspans[lc->sync - 1]->psync = span->offset + 1;
 	}
 	wc->checktiming = 1;
+	/* HDLC controller part */
+	if (ts->sigchan) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&wc->reglock, flags);
+		__hdlc_stop(wc, ts->sigchan->span->offset);
+		spin_unlock_irqrestore(&wc->reglock, flags);
+	}
+	
 	/* If we're already running, then go ahead and apply the changes */
 	if (span->flags & ZT_FLAG_RUNNING)
 		return t4_startup(span);
@@ -990,17 +1174,36 @@
 	int alreadyrunning;
 	unsigned long flags;
 	struct t4 *wc = chan->pvt;
+	struct t4_span *ts = wc->tspans[chan->span->offset];
 
-	alreadyrunning = wc->tspans[chan->span->offset]->span.flags & ZT_FLAG_RUNNING;
+	alreadyrunning = ts->span.flags & ZT_FLAG_RUNNING;
 	if (debug & DEBUG_MAIN) {
 		if (alreadyrunning)
 			printk("TE%dXXP: Reconfigured channel %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype);
 		else
 			printk("TE%dXXP: Configured channel %d (%s) sigtype %d\n", wc->numspans, chan->channo, chan->name, sigtype);
-	}		
+	}
+
 	spin_lock_irqsave(&wc->reglock, flags);	
+
 	if (alreadyrunning)
 		__set_clear(wc, chan->span->offset);
+
+	if ((sigtype == ZT_SIG_HARDHDLC) && (ts->sigchan != chan)) {
+		if (alreadyrunning) {
+			if (ts->sigchan)
+				__hdlc_stop(wc, ts->sigchan->span->offset);
+			if (__hdlc_start(wc, chan->span->offset, chan, ts->sigmode)) {
+				printk("Error initializing signalling controller\n");
+				spin_unlock_irqrestore(&wc->reglock, flags);
+				return -1;
+			}
+		}
+		else {
+			ts->sigchan = chan;
+			ts->sigactive = 0;
+		}
+	}
 	spin_unlock_irqrestore(&wc->reglock, flags);	
 	return 0;
 }
@@ -1049,6 +1252,12 @@
 		ts->span.maint = t4_maint;
 		ts->span.open = t4_open;
 		ts->span.close  = t4_close;
+
+		/* HDLC Specific init */
+		ts->sigchan = NULL;
+		ts->sigmode = sigmode;
+		ts->sigactive = 0;
+		
 		if (ts->spantype == TYPE_T1 || ts->spantype == TYPE_J1) {
 			ts->span.channels = 24;
 			ts->span.deflaw = ZT_LAW_MULAW;
@@ -1060,6 +1269,7 @@
 		ts->span.flags = ZT_FLAG_RBS;
 		ts->span.linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
 		ts->span.ioctl = t4_ioctl;
+		ts->span.hdlc_hard_xmit = t4_hdlc_hard_xmit;
 		if (gen2) {
 #ifdef VPM_SUPPORT
 			ts->span.echocan = t4_echocan;
@@ -1075,7 +1285,7 @@
 		for (y=0;y<wc->tspans[x]->span.channels;y++) {
 			struct zt_chan *mychans = ts->chans + y;
 			sprintf(mychans->name, "TE%d/%d/%d/%d", wc->numspans, wc->num, x + 1, y + 1);
-			mychans->sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS |
+			mychans->sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS | ZT_SIG_HARDHDLC |
 									 ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_EM_E1 | ZT_SIG_DACS_RBS;
 			c = (x * ts->span.channels) + y;
 			mychans->pvt = wc;
@@ -1108,26 +1318,26 @@
 	}
 
 	/* Configure interrupts */	
-	t4_framer_out(wc, unit, 0x46, 0x00);	/* GCR: Interrupt on Activation/Deactivation of each */
+	t4_framer_out(wc, unit, FRMR_GCR, 0x00);	/* GCR: Interrupt on Activation/Deactivation of each */
 
 	/* Configure system interface */
-	t4_framer_out(wc, unit, 0x3e, 0xc2);	/* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
-	t4_framer_out(wc, unit, 0x3f, 0x20 | (unit << 1)); /* SIC2: No FFS, no center receive eliastic buffer, phase */
-	t4_framer_out(wc, unit, 0x40, 0x04);	/* SIC3: Edges for capture */
-	t4_framer_out(wc, unit, 0x45, 0x00);	/* CMR2: We provide sync and clock for tx and rx. */
+	t4_framer_out(wc, unit, FRMR_SIC1, 0xc2);	/* SIC1: 8.192 Mhz clock/bus, double buffer receive / transmit, byte interleaved */
+	t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1)); /* SIC2: No FFS, no center receive eliastic buffer, phase */
+	t4_framer_out(wc, unit, FRMR_SIC3, 0x04);	/* SIC3: Edges for capture */
+	t4_framer_out(wc, unit, FRMR_CMR2, 0x00);	/* CMR2: We provide sync and clock for tx and rx. */
 	if (!wc->t1e1) { /* T1 mode */
-		t4_framer_out(wc, unit, 0x22, 0x03);	/* XC0: Normal operation of Sa-bits */
-		t4_framer_out(wc, unit, 0x23, 0x84);	/* XC1: 0 offset */
+		t4_framer_out(wc, unit, FRMR_XC0, 0x03);	/* XC0: Normal operation of Sa-bits */
+		t4_framer_out(wc, unit, FRMR_XC1, 0x84);	/* XC1: 0 offset */
 		if (wc->tspans[unit]->spantype == TYPE_J1)
-			t4_framer_out(wc, unit, 0x24, 0x83);	/* RC0: Just shy of 1023 */
+			t4_framer_out(wc, unit, FRMR_RC0, 0x83);	/* RC0: Just shy of 1023 */
 		else
-			t4_framer_out(wc, unit, 0x24, 0x03);	/* RC0: Just shy of 1023 */
-		t4_framer_out(wc, unit, 0x25, 0x84);	/* RC1: The rest of RC0 */
+			t4_framer_out(wc, unit, FRMR_RC0, 0x03);	/* RC0: Just shy of 1023 */
+		t4_framer_out(wc, unit, FRMR_RC1, 0x84);	/* RC1: The rest of RC0 */
 	} else { /* E1 mode */
-		t4_framer_out(wc, unit, 0x22, 0x00);	/* XC0: Normal operation of Sa-bits */
-		t4_framer_out(wc, unit, 0x23, 0x04);	/* XC1: 0 offset */
-		t4_framer_out(wc, unit, 0x24, 0x04);	/* RC0: Just shy of 1023 */
-		t4_framer_out(wc, unit, 0x25, 0x04);	/* RC1: The rest of RC0 */
+		t4_framer_out(wc, unit, FRMR_XC0, 0x00);	/* XC0: Normal operation of Sa-bits */
+		t4_framer_out(wc, unit, FRMR_XC1, 0x04);	/* XC1: 0 offset */
+		t4_framer_out(wc, unit, FRMR_RC0, 0x04);	/* RC0: Just shy of 1023 */
+		t4_framer_out(wc, unit, FRMR_RC1, 0x04);	/* RC1: The rest of RC0 */
 	}
 	
 	/* Configure ports */
@@ -1434,6 +1644,16 @@
 			__t4_check_alarms(wc, span->offset);
 			__t4_check_sigbits(wc, span->offset);
 		}
+		/* Startup HDLC controller too */
+		if (ts->sigchan) {
+			printk("Starting HDLC controller for channel %d span %d\n", ts->sigchan->channo, ts->sigchan->span->offset);
+			if (__hdlc_start(wc, ts->sigchan->span->offset, ts->sigchan, ts->sigmode)) {
+				printk("Error initializing signalling controller\n");
+				/* XXX Should de-initialize span XXX */
+				spin_unlock_irqrestore(&wc->reglock, flags);
+				return -1;
+			}
+		}
 	}
 
 	spin_unlock_irqrestore(&wc->reglock, flags);
@@ -1960,6 +2180,8 @@
 #endif
 }
 
+static inline void __t4_framer_interrupt(struct t4 *wc, int span);
+
 #ifdef SUPPORT_GEN1
 #ifdef LINUX26
 static irqreturn_t t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -1972,9 +2194,7 @@
 	int x;
 	
 	unsigned int status;
-#if 0
 	unsigned int status2;
-#endif
 
 #if 0
 	if (wc->intcount < 20)
@@ -1986,6 +2206,17 @@
 	status = t4_pci_in(wc, WC_INTR);
 	t4_pci_out(wc, WC_INTR, 0);
 
+	/* Process framer interrupts */
+	status2 = t4_framer_in(wc, 0, FRMR_CIS);
+	if (status2 & 0x0f) {
+		spin_lock_irqsave(&wc->reglock, flags);
+		for (x = 0; x < wc->numspans; ++x) {
+			if (status2 & (1 << x))
+				__t4_framer_interrupt(wc, x);
+		}
+		spin_unlock_irqrestore(&wc->reglock, flags);
+	}
+
 	/* Ignore if it's not for us */
 	if (!status)
 #ifdef LINUX26
@@ -2016,10 +2247,10 @@
 	
 #if 0
 	if ((wc->intcount < 10) || !(wc->intcount % 1000)) {
-		status2 = t4_framer_in(wc, 0, 0x6f);
+		status2 = t4_framer_in(wc, 0, FRMR_CIS);
 		printk("Status2: %04x\n", status2);
 		for (x = 0;x<4;x++) {
-			status2 = t4_framer_in(wc, x, 0x4c);
+			status2 = t4_framer_in(wc, x, FRMR_FRS0);
 			printk("FRS0/%d: %04x\n", x, status2);
 		}
 	}
@@ -2058,64 +2289,135 @@
 static inline void __t4_framer_interrupt(struct t4 *wc, int span)
 {
 	/* Check interrupts for a given span */
-	unsigned char gis, isr0=0, isr1=0, isr2=0, isr3=0, isr4;
-	struct t4_span *ts;
+	unsigned char gis, isr0, isr1, isr2, isr3, isr4;
+	int readsize = -1;
+	struct t4_span *ts = wc->tspans[span];
 
 	if (debug & DEBUG_FRAMER)	
 		printk("framer interrupt span %d:%d!\n", wc->num, span + 1);
-	ts = wc->tspans[span];
 
-	gis = __t4_framer_in(wc, span, 0x6e);
-	
-	if (ts->spantype == TYPE_E1) {
-		/* E1 checks */
-		if (gis & 0x1)
-			isr0 = __t4_framer_in(wc, span, 0x68);
-		if (gis & 0x2)
-			isr1 = __t4_framer_in(wc, span, 0x69);
-		if (gis & 0x4)
-			isr2 = __t4_framer_in(wc, span, 0x6a);
-		if (gis & 0x8)
-			isr3 = __t4_framer_in(wc, span, 0x6b);
+	/* 1st gen cards isn't used interrupts */
+	gis = __t4_framer_in(wc, span, FRMR_GIS);
+	isr0 = (gis & FRMR_GIS_ISR0) ? __t4_framer_in(wc, span, FRMR_ISR0) : 0;
+	isr1 = (gis & FRMR_GIS_ISR1) ? __t4_framer_in(wc, span, FRMR_ISR1) : 0;
+	isr2 = (gis & FRMR_GIS_ISR2) ? __t4_framer_in(wc, span, FRMR_ISR2) : 0;
+	isr3 = (gis & FRMR_GIS_ISR3) ? __t4_framer_in(wc, span, FRMR_ISR3) : 0;
+	isr4 = (gis & FRMR_GIS_ISR4) ? __t4_framer_in(wc, span, FRMR_ISR4) : 0;
 
+	if (debug & DEBUG_FRAMER)
+		printk("gis: %02x, isr0: %02x, isr1: %02x, isr2: %02x, isr3: %02x, isr4: %02x\n", gis, isr0, isr1, isr2, isr3, isr4);
 
-		if (isr0)  
-			__t4_check_sigbits(wc, span);
-		
+	if (isr0)
+		__t4_check_sigbits(wc, span);
+
+	if (ts->spantype == TYPE_E1) {
+		/* E1 checks */
 		if ((isr3 & 0x38) || isr2 || isr1)
 			__t4_check_alarms(wc, span);
-		if (debug & DEBUG_FRAMER)
-			printk("gis: %02x, isr0: %02x, isr1: %02x, isr2: %02x, isr3: %02x\n", gis, isr0, isr1, isr2, isr3);
 	} else {
 		/* T1 checks */
-		if (gis & 0x1)
-			isr0 = __t4_framer_in(wc, span, 0x68);
-		if (gis & 0x4)
-			isr2 = __t4_framer_in(wc, span, 0x6a);
-		if (gis & 0x8)
-			isr3 = __t4_framer_in(wc, span, 0x6b);
-
-		if (isr0)
-			__t4_check_sigbits(wc, span);
 		if (isr2 || (isr3 & 0x08)) 
 			__t4_check_alarms(wc, span);		
-		if (debug & DEBUG_FRAMER)
-			printk("gis: %02x, isr0: %02x, isr1: %02x, irs2: %02x, isr3: %02x\n", gis, isr0, isr1, isr2, isr3);	
 	}
 	if (debugslips && !ts->span.alarms) {
 		if (isr3 & 0x02)
 			printk("TE%d10P: RECEIVE slip NEGATIVE on span %d\n", wc->numspans, span + 1);
 		if (isr3 & 0x01)
 			printk("TE%d10P: RECEIVE slip POSITIVE on span %d\n", wc->numspans, span + 1);
-		if (gis & 0x10)
-			isr4 = __t4_framer_in(wc, span, 0x6c);
-		else
-			isr4 = 0;
 		if (isr4 & 0x80)
 			printk("TE%dXXP: TRANSMIT slip POSITIVE on span %d\n", wc->numspans, span + 1);
 		if (isr4 & 0x40)
 			printk("TE%d10P: TRANSMIT slip NEGATIVE on span %d\n", wc->numspans, span + 1);
 	}
+
+	/* HDLC controller checks - receive side */
+	if (!wc->tspans[span]->sigchan)
+		return;
+
+	if (isr0 & FRMR_ISR0_RME) {
+		readsize = (__t4_framer_in(wc, span, FRMR_RBCH) << 8) | __t4_framer_in(wc, span, FRMR_RBCL);
+		if (debug & DEBUG_FRAMER) printk("Received data length is %d (%d)\n", readsize, readsize & FRMR_RBCL_MAX_SIZE);
+		/* RPF isn't set on last part of frame */
+		if ((readsize > 0) && ((readsize &= FRMR_RBCL_MAX_SIZE) == 0))
+			readsize = 32;
+	} else if (isr0 & FRMR_ISR0_RPF)
+		readsize = 32;
+
+	if (readsize > 0) {
+		struct zt_chan *sigchan = ts->sigchan;
+		int i;
+		unsigned char readbuf[FRMR_RBCL_MAX_SIZE];
+
+		if (debug & DEBUG_FRAMER) printk("Framer %d: Got RPF/RME! readsize is %d\n", sigchan->span->offset, readsize);
+
+		for (i = 0; i < readsize; i++)
+			readbuf[i] = __t4_framer_in(wc, span, FRMR_RXFIFO);
+
+		/* Tell the framer to clear the RFIFO */
+		__t4_framer_cmd_wait(wc, span, FRMR_CMDR_RMC);
+
+		if (debug & DEBUG_FRAMER) {
+			printk("RX(");
+			for (i = 0; i < readsize; i++)
+				printk((i ? " %02x" : "%02x"), readbuf[i]);
+			printk(")\n");
+		}
+
+		if (isr0 & FRMR_ISR0_RME) {
+			/* Do checks for HDLC problems */
+			unsigned char rsis = readbuf[readsize-1];
+			unsigned int olddebug = debug;
+			unsigned char rsis_reg = __t4_framer_in(wc, span, FRMR_RSIS);
+
+#if 0
+			if ((rsis != 0xA2) || (rsis != rsis_reg))
+				debug |= DEBUG_FRAMER;
+#endif
+
+			++ts->frames_in;
+			if ((debug & DEBUG_FRAMER) && !(ts->frames_in & 0x0f))
+				printk("Received %d frames on span %d\n", ts->frames_in, span);
+			if (debug & DEBUG_FRAMER) printk("Received HDLC frame %d.  RSIS = 0x%x (%x)\n", ts->frames_in, rsis, rsis_reg);
+			if (!(rsis & FRMR_RSIS_CRC16)) {
+				if (debug & DEBUG_FRAMER) printk("CRC check failed %d\n", span);
+				zt_hdlc_abort(sigchan, ZT_EVENT_BADFCS);
+			} else if (rsis & FRMR_RSIS_RAB) {
+				if (debug & DEBUG_FRAMER) printk("ABORT of current frame due to overflow %d\n", span);
+				zt_hdlc_abort(sigchan, ZT_EVENT_ABORT);
+			} else if (rsis & FRMR_RSIS_RDO) {
+				if (debug & DEBUG_FRAMER) printk("HDLC overflow occured %d\n", span);
+				zt_hdlc_abort(sigchan, ZT_EVENT_OVERRUN);
+			} else if (!(rsis & FRMR_RSIS_VFR)) {
+				if (debug & DEBUG_FRAMER) printk("Valid Frame check failed on span %d\n", span);
+				zt_hdlc_abort(sigchan, ZT_EVENT_ABORT);
+			} else {
+				zt_hdlc_putbuf(sigchan, readbuf, readsize - 1);
+				zt_hdlc_finish(sigchan);
+				if (debug & DEBUG_FRAMER) printk("Received valid HDLC frame on span %d\n", span);
+			}
+			debug = olddebug;
+		} else if (isr0 & FRMR_ISR0_RPF)
+			zt_hdlc_putbuf(sigchan, readbuf, readsize);
+	}
+
+	/* Transmit side */
+	if (isr1 & FRMR_ISR1_XDU) {
+		if (debug & DEBUG_FRAMER) printk("XDU: Resetting signal controler!\n");
+		__t4_framer_cmd_wait(wc, span, FRMR_CMDR_SRES);
+	} else if (isr1 & FRMR_ISR1_XPR) {
+		struct zt_chan *sigchan = ts->sigchan;
+
+		if (debug & DEBUG_FRAMER)
+			printk("Sigchan %d is %p\n", sigchan->chanpos, sigchan);
+
+		if (debug & DEBUG_FRAMER) printk("Framer %d: Got XPR!\n", sigchan->span->offset);
+		__t4_hdlc_xmit_fifo(wc, span, ts);
+	}
+
+	if (isr1 & FRMR_ISR1_ALLS) {
+		if (debug & DEBUG_FRAMER) printk("ALLS received\n");
+	}
+
 }
 
 #ifdef LINUX26
@@ -2166,7 +2468,7 @@
 	wc->intcount++;
 #if 1
 	if (wc->intcount < 20)
-		printk("2G: Got interrupt, status = %08x, GIS = %04x\n", status, __t4_framer_in(wc, 0, 0x6f));
+		printk("2G: Got interrupt, status = %08x, CIS = %04x\n", status, __t4_framer_in(wc, 0, FRMR_CIS));
 #endif		
 
 	if (status & 0x2) {
@@ -2218,14 +2520,14 @@
 			break;
 		}
 	} else if (status & 0x1) {
-		cis = __t4_framer_in(wc, 0, 0x6f);
-		if (cis & 0x1)
+		cis = __t4_framer_in(wc, 0, FRMR_CIS);
+		if (cis & FRMR_CIS_GIS1)
 			__t4_framer_interrupt(wc, 0);
-		if (cis & 0x2)
+		if (cis & FRMR_CIS_GIS2)
 			__t4_framer_interrupt(wc, 1);
-		if (cis & 0x4)
+		if (cis & FRMR_CIS_GIS3)
 			__t4_framer_interrupt(wc, 2);
-		if (cis & 0x8)
+		if (cis & FRMR_CIS_GIS4)
 			__t4_framer_interrupt(wc, 3);
 	}
 #ifdef VPM_SUPPORT
@@ -2962,6 +3264,7 @@
 module_param(t1e1override, int, 0600);
 module_param(alarmdebounce, int, 0600);
 module_param(j1mode, int, 0600);
+module_param(sigmode, int, 0600);
 #ifdef VPM_SUPPORT
 module_param(vpmsupport, int, 0600);
 module_param(vpmdtmfsupport, int, 0600);
@@ -2978,6 +3281,7 @@
 MODULE_PARM(t1e1override, "i");
 MODULE_PARM(alarmdebounce, "i");
 MODULE_PARM(j1mode, "i");
+MODULE_PARM(sigmode, "i");
 #ifdef VPM_SUPPORT
 MODULE_PARM(vpmsupport, "i");
 MODULE_PARM(vpmdtmfsupport, "i");
Index: wct4xxp.h
===================================================================
RCS file: /usr/cvsroot/zaptel/wct4xxp.h,v
retrieving revision 1.1
diff -u -r1.1 wct4xxp.h
--- wct4xxp.h	9 Jul 2003 21:48:21 -0000	1.1
+++ wct4xxp.h	4 Oct 2005 16:49:11 -0000
@@ -25,6 +25,78 @@
 
 #include <linux/ioctl.h>
 
+#define FRMR_TTR_BASE 0x10
+#define FRMR_RTR_BASE 0x0c
+#define FRMR_TSEO 0xa0
+#define FRMR_TSBS1 0xa1
+#define FRMR_CCR1 0x09
+#define FRMR_CCR1_ITF 0x08
+#define FRMR_CCR1_EITS 0x10
+#define FRMR_CCR2 0x0a
+#define FRMR_CCR2_RCRC 0x04
+#define FRMR_CCR2_RADD 0x10
+#define FRMR_MODE 0x03
+#define FRMR_MODE_NO_ADDR_CMP 0x80
+#define FRMR_MODE_SS7 0x20
+#define FRMR_MODE_HRAC 0x08
+#define FRMR_IMR0 0x14
+#define FRMR_IMR0_RME 0x80
+#define FRMR_IMR0_RPF 0x01
+#define FRMR_IMR1 0x15
+#define FRMR_IMR1_ALLS 0x20
+#define FRMR_IMR1_XDU 0x10
+#define FRMR_IMR1_XPR 0x01
+#define FRMR_XC0 0x22
+#define FRMR_XC1 0x23
+#define FRMR_RC0 0x24
+#define FRMR_RC1 0x25
+#define FRMR_SIC1 0x3e
+#define FRMR_SIC2 0x3f
+#define FRMR_SIC3 0x40
+#define FRMR_CMR1 0x44
+#define FRMR_CMR2 0x45
+#define FRMR_GCR 0x46
+#define FRMR_ISR0 0x68
+#define FRMR_ISR0_RME 0x80
+#define FRMR_ISR0_RPF 0x01
+#define FRMR_ISR1 0x69
+#define FRMR_ISR1_ALLS 0x20
+#define FRMR_ISR1_XDU 0x10
+#define FRMR_ISR1_XPR 0x01
+#define FRMR_ISR2 0x6a
+#define FRMR_ISR3 0x6b
+#define FRMR_ISR4 0x6c
+#define FRMR_GIS  0x6e
+#define FRMR_GIS_ISR0 0x01
+#define FRMR_GIS_ISR1 0x02
+#define FRMR_GIS_ISR2 0x04
+#define FRMR_GIS_ISR3 0x08
+#define FRMR_GIS_ISR4 0x10
+#define FRMR_CIS 0x6f
+#define FRMR_CIS_GIS1 0x01
+#define FRMR_CIS_GIS2 0x02
+#define FRMR_CIS_GIS3 0x04
+#define FRMR_CIS_GIS4 0x08
+#define FRMR_CMDR 0x02
+#define FRMR_CMDR_SRES 0x01
+#define FRMR_CMDR_XRES 0x10
+#define FRMR_CMDR_RMC 0x80
+#define FRMR_CMDR_XTF 0x04
+#define FRMR_CMDR_XHF 0x08
+#define FRMR_CMDR_XME 0x02
+#define FRMR_RSIS 0x65
+#define FRMR_RSIS_VFR 0x80
+#define FRMR_RSIS_RDO 0x40
+#define FRMR_RSIS_CRC16 0x20
+#define FRMR_RSIS_RAB 0x10
+#define FRMR_RBCL 0x66
+#define FRMR_RBCL_MAX_SIZE 0x1f
+#define FRMR_RBCH 0x67
+#define FRMR_RXFIFO 0x00
+#define FRMR_SIS 0x64
+#define FRMR_SIS_XFW 0x40
+#define FRMR_TXFIFO 0x00
+
 #define NUM_REGS 0xa9
 #define NUM_PCI 12
 
Index: zaptel.c
===================================================================
RCS file: /usr/cvsroot/zaptel/zaptel.c,v
retrieving revision 1.123
diff -u -r1.123 zaptel.c
--- zaptel.c	30 Sep 2005 20:41:21 -0000	1.123
+++ zaptel.c	4 Oct 2005 16:49:12 -0000
@@ -141,6 +141,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]; 
@@ -455,6 +459,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:
@@ -926,7 +932,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;
@@ -1624,7 +1632,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)
@@ -1637,6 +1645,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;
@@ -1733,10 +1755,21 @@
 	}
 
 #if CONFIG_ZAPATA_DEBUG
+#if 0
 	printk("zt_chan_write(unit: %d, inwritebuf: %d, outwritebuf: %d amnt: %d\n", 
 		unit, chan->inwritebuf, chan->outwritebuf, amnt);
 #endif
+#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) {
 			/* There seems to be a max stack size, so we have
@@ -1780,6 +1813,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;
 }
@@ -1954,7 +1990,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;
@@ -2104,11 +2140,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;
@@ -2750,10 +2786,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;
@@ -2891,30 +2928,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];
+			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;
@@ -3215,6 +3261,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 && 
@@ -5712,7 +5764,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 */
@@ -5729,8 +5782,6 @@
 	int res;
 	int left, x;
 
-	int bytes = ZT_CHUNKSIZE;
-
 	while(bytes) {
 #if defined(CONFIG_ZAPATA_NET)  || defined(CONFIG_ZAPATA_PPP)
 		skb = NULL;
@@ -5796,6 +5847,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. */
@@ -5980,6 +6035,176 @@
 	}
 }
 
+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;
+
+	//printk("zt_hdlc_putbuf: %d\n", bytes);
+	spin_lock_irqsave(&ss->lock, flags);
+#if 1
+	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
+#if 1
+		zt_hdlc_abort(ss, ZT_EVENT_OVERRUN);
+#else
+		ss->readidx[ss->inreadbuf] = 0;
+		if ((ss->flags & ZT_FLAG_OPEN) && !ss->span->alarms)
+			__qevent(ss->master, ZT_EVENT_OVERRUN);
+#endif
+	}
+	res = left;
+#else
+	__putbuf_chunk(ss, rxb, bytes);
+	res = bytes;
+#endif
+	spin_unlock_irqrestore(&ss->lock, flags);
+}
+
+extern void zt_hdlc_abort(struct zt_chan *ss, int event)
+{
+	//printk("zt_hdlc_abort\n");
+	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;
+
+	//printk("zt_hdlc_finish\n");
+	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;
@@ -6192,6 +6417,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;
@@ -6273,7 +6502,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;
@@ -6281,7 +6511,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;
Index: zaptel.h
===================================================================
RCS file: /usr/cvsroot/zaptel/zaptel.h,v
retrieving revision 1.49
diff -u -r1.49 zaptel.h
--- zaptel.h	30 Sep 2005 20:41:21 -0000	1.49
+++ zaptel.h	4 Oct 2005 16:49:12 -0000
@@ -109,6 +109,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 */
@@ -1357,6 +1362,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
    we should have preference in being the master device */
Index: zaptel.init
===================================================================
RCS file: /usr/cvsroot/zaptel/zaptel.init,v
retrieving revision 1.12
diff -u -r1.12 zaptel.init
--- zaptel.init	4 Apr 2005 23:50:25 -0000	1.12
+++ zaptel.init	4 Oct 2005 16:49:12 -0000
@@ -81,7 +81,8 @@
 	echo "OK"
 	echo -n "Loading zaptel hardware modules:"
 	for x in $MODULES; do 
-		if modprobe ${x} ${ARGS} >& /dev/null; then
+		eval localARGS="\$${x}_ARGS"
+		if modprobe ${x} ${ARGS} ${localARGS} >& /dev/null; then
 			echo -n " $x"
 		fi
 	done
Index: zaptel.sysconfig
===================================================================
RCS file: /usr/cvsroot/zaptel/zaptel.sysconfig,v
retrieving revision 1.2
diff -u -r1.2 zaptel.sysconfig
--- zaptel.sysconfig	21 Jan 2005 22:49:26 -0000	1.2
+++ zaptel.sysconfig	4 Oct 2005 16:49:12 -0000
@@ -8,6 +8,7 @@
 
 MODULES="$MODULES wct4xxp"	# TE405P - Quad Span T1/E1 Card (5v version)
 				# TE410P - Quad Span T1/E1 Card (3.3v version)
+#wct4xxp_ARGS="t1e1override=15"	# Additional parameters for TE4xxP driver
 
 MODULES="$MODULES wct1xxp"	# T100P - Single Span T1 Card
 				# E100P - Single Span E1 Card
Index: ztcfg.c
===================================================================
RCS file: /usr/cvsroot/zaptel/ztcfg.c,v
retrieving revision 1.24
diff -u -r1.24 ztcfg.c
--- ztcfg.c	29 Sep 2005 03:51:31 -0000	1.24
+++ ztcfg.c	4 Oct 2005 16:49:12 -0000
@@ -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);
 			}
@@ -1084,6 +1087,7 @@
 	{ "rawhdlc", chanconfig },
 	{ "nethdlc", chanconfig },
 	{ "fcshdlc", chanconfig },
+	{ "hardhdlc", chanconfig },
 	{ "dchan", chanconfig },
 	{ "bchan", chanconfig },
 	{ "indclear", chanconfig },
