[zaptel-commits] kpfleming: trunk r1361 - in /trunk: ./ include/ wct4xxp/

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Sat Aug 26 19:18:51 MST 2006


Author: kpfleming
Date: Sat Aug 26 21:18:50 2006
New Revision: 1361

URL: http://svn.digium.com/view/zaptel?rev=1361&view=rev
Log:
Merged revisions 1359 via svnmerge from 
https://origsvn.digium.com/svn/zaptel/branches/1.2

........
r1359 | kpfleming | 2006-08-26 21:02:42 -0500 (Sat, 26 Aug 2006) | 2 lines

merge in new, cleaner Octasic API integration

........

Added:
    trunk/wct4xxp/   (props changed)
      - copied from r1359, branches/1.2/wct4xxp/
    trunk/wct4xxp/Kbuild
      - copied unchanged from r1359, branches/1.2/wct4xxp/Kbuild
    trunk/wct4xxp/Makefile
      - copied unchanged from r1359, branches/1.2/wct4xxp/Makefile
    trunk/wct4xxp/OCT6114-128D.ima
      - copied unchanged from r1359, branches/1.2/wct4xxp/OCT6114-128D.ima
    trunk/wct4xxp/base.c
      - copied, changed from r1359, branches/1.2/wct4xxp/base.c
    trunk/wct4xxp/fw2h.c
      - copied unchanged from r1359, branches/1.2/wct4xxp/fw2h.c
    trunk/wct4xxp/vpm450m.c
      - copied unchanged from r1359, branches/1.2/wct4xxp/vpm450m.c
    trunk/wct4xxp/vpm450m.h
      - copied unchanged from r1359, branches/1.2/wct4xxp/vpm450m.h
    trunk/wct4xxp/wct4xxp-diag.c
      - copied unchanged from r1359, branches/1.2/wct4xxp/wct4xxp-diag.c
    trunk/wct4xxp/wct4xxp.h
      - copied, changed from r1359, branches/1.2/wct4xxp/wct4xxp.h
Removed:
    trunk/OCT6114-128D.ima
    trunk/fw2h.c
    trunk/include/
    trunk/octapi_bt0_private.h
    trunk/octapi_llman_private.h
    trunk/octvpm.h
    trunk/vpm450m.c
    trunk/vpm450m.h
    trunk/wct4xxp-diag.c
    trunk/wct4xxp.h
    trunk/wct4xxp_base.c
Modified:
    trunk/   (props changed)
    trunk/Makefile
    trunk/wcte11xp.c

Propchange: trunk/
------------------------------------------------------------------------------
--- branch-1.2-merged (original)
+++ branch-1.2-merged Sat Aug 26 21:18:50 2006
@@ -1,1 +1,1 @@
-/branches/1.2:1-916,918-936,938-949,958,962,970,990,1004,1011,1017,1031,1033,1060,1062,1064-1066,1069,1071,1076,1079,1081,1097,1101,1151,1185,1187,1205,1233,1235-1236,1243,1248,1259,1262,1298,1300,1304,1306,1311,1313,1315,1317,1327
+/branches/1.2:1-916,918-936,938-949,958,962,970,990,1004,1011,1017,1031,1033,1060,1062,1064-1066,1069,1071,1076,1079,1081,1097,1101,1151,1185,1187,1205,1233,1235-1236,1243,1248,1259,1262,1298,1300,1304,1306,1311,1313,1315,1317,1327,1359

Propchange: trunk/
------------------------------------------------------------------------------
--- svn:externals (original)
+++ svn:externals Sat Aug 26 21:18:50 2006
@@ -1,1 +1,2 @@
 menuselect     http://svn.digium.com/svn/menuselect/branches/1.0
+oct612x	       http://svn.digium.com/svn/octasic_api/oct612x/tags/PR43-00/software

Modified: trunk/Makefile
URL: http://svn.digium.com/view/zaptel/trunk/Makefile?rev=1361&r1=1360&r2=1361&view=diff
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Sat Aug 26 21:18:50 2006
@@ -33,7 +33,7 @@
 KVERS_MAJ:=$(shell echo $(KVERS) | cut -d. -f1-2)
 KINCLUDES:=$(KSRC)/include
 
-CFLAGS+=-I. -Iinclude -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
+CFLAGS+=-I. -O4 -g -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
 ifneq (,$(findstring ppc,$(UNAME_M)))
 CFLAGS_PPC:=-fsigned-char
 endif
@@ -135,7 +135,7 @@
 ifeq ($(findstring xpp_usb,$(MENUSELECT_MODULES)),)
   BUILD_XPP:=yes
 endif
-MODULES:=pciradio tor2 torisa wcfxo wct1xxp wct4xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode
+MODULES:=pciradio tor2 torisa wcfxo wct1xxp wctdm wctdm24xxp wcte11xp wcusb zaptel ztd-eth ztd-loc ztdummy ztdynamic zttranscode
 MODULES:=$(filter-out $(MENUSELECT_MODULES),$(MODULES))
 
 MODULESO:=$(MODULES:%=%.o)
@@ -154,9 +154,10 @@
 
 MOD_DESTDIR:=zaptel
 
-EXTRA_CFLAGS:=-I$(SUBDIRS)/include  -I$(SUBDIRS)/include/oct6100api
 obj-m:=$(MODULESO)
-wct4xxp-objs:=wct4xxp_base.o vpm450m.o
+ifeq ($(findstring wct4xxp,$(MENUSELECT_MODULES)),)
+obj-m+=wct4xxp/
+endif
 
 # Set this to override hotplug firmware loading and revert to classic header
 #HOTPLUG_FIRMWARE=no
@@ -191,17 +192,13 @@
 
 modules: $(BUILDVER)
 
-linux24: prereq vpm450m_fw.h $(MODULESO)
+linux24: prereq vpm450m_fw.h $(MODULESO) wct4xxp/wct4xxp.o
 
 linux26: prereq vpm450m_fw.h
 	@if [ -z "$(KSRC)" -o ! -d "$(KSRC)" ]; then echo "You do not appear to have the sources for the $(KVERS) kernel installed."; exit 1 ; fi
-	$(KMAKE) modules
+	$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules
 
 xpp: linux26
-
-#ifneq ($(TOPDIR),)
-#include $(TOPDIR)/Rules.make
-#endif
 
 version.h:
 	@ZAPTELVERSION="${ZAPTELVERSION}" build_tools/make_version_h > $@.tmp
@@ -210,6 +207,9 @@
 	fi
 	@rm -f $@.tmp
 
+wct4xxp/wct4xxp.o:
+	$(MAKE) -C wct4xxp KFLAGS="$(KFLAGS) -I.." CFLAGS="$(CFLAGS) -I.."
+
 devel: tor2ee 
 
 tests: patgen pattest patlooptest hdlcstress hdlctest hdlcgen hdlcverify timertest
@@ -230,14 +230,8 @@
 
 ztdummy.o: ztdummy.h
 
-$(filter-out wct4xxp.o,$(MODULESO)) wct4xxp_base.o: %.o: %.c zaptel.h
+$(MODULESO): %.o: %.c zaptel.h
 	$(CC) $(KFLAGS) -o $@ -c $<
-
-vpm450m.o: vpm450m.c zaptel.h
-	$(CC) $(KFLAGS) -I$(PWD)/include -I$(PWD)/include/oct6100api -I$(SUBDIRS)/include -I$(SUBDIRS)/include/oct6100api -o $@ -c $<
-
-wct4xxp.o: wct4xxp_base.o vpm450m.o
-	$(LD) -r -o $@ wct4xxp_base.o vpm450m.o
 
 tor2ee.o: tor2-hw.h
 
@@ -265,11 +259,6 @@
 
 gendigits: LDLIBS+=-lm
 gendigits: CFLAGS=
-
-fw2h: CFLAGS=
-
-vpm450m_fw.h: OCT6114-128D.ima fw2h
-	./fw2h $< $@
 
 zaptel.c: tones.h 
 
@@ -501,7 +490,9 @@
 	rm -f *.o ztcfg tzdriver sethdlc sethdlc-new
 	rm -f $(LTZ_SO) $(LTZ_A) *.lo
 ifeq ($(BUILDVER),linux26)
-	$(KMAKE) clean
+	$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) clean
+else
+	$(MAKE) -C wct4xxp clean
 	$(MAKE) -C datamods clean
 endif
 	rm -f xpp/*.ko xpp/*.mod.c xpp/.*o.cmd
@@ -515,7 +506,6 @@
 	rm -f ztcfg-shared fxstest
 	rm -rf misdn*
 	rm -rf mISDNuser*
-	rm -f fw2h vpm450m_fw.h
 
 distclean: dist-clean
 

Propchange: trunk/wct4xxp/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sat Aug 26 21:18:50 2006
@@ -1,0 +1,5 @@
+*.mod.c
+*.cmd
+*.ko
+vpm450m_fw.h
+fw2h

Copied: trunk/wct4xxp/base.c (from r1359, branches/1.2/wct4xxp/base.c)
URL: http://svn.digium.com/view/zaptel/trunk/wct4xxp/base.c?p2=trunk/wct4xxp/base.c&p1=branches/1.2/wct4xxp/base.c&r1=1359&r2=1361&rev=1361&view=diff
==============================================================================
--- branches/1.2/wct4xxp/base.c (original)
+++ trunk/wct4xxp/base.c Sat Aug 26 21:18:50 2006
@@ -33,10 +33,12 @@
 #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
-#include <linux/zaptel.h>
+#include <zaptel/zaptel.h>
 #endif
 #ifdef LINUX26
 #include <linux/moduleparam.h>
@@ -176,10 +178,11 @@
 #endif
 
 static int debug=0;
-static int timingcable;
+static int timingcable = 0;
 static int highestorder;
-static int t1e1override = -1;
+static int t1e1override = -1; //0xFF; // -1 = jumper; 0xFF = E1
 static int j1mode = 0;
+static int sigmode = FRMR_MODE_NO_ADDR_CMP;
 static int loopback = 0;
 static int alarmdebounce = 0;
 #ifdef VPM_SUPPORT
@@ -268,6 +271,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;
@@ -356,10 +367,11 @@
 #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);
-static void __t4_set_timing_source(struct t4 *wc, int unit);
+static void __t4_set_timing_source(struct t4 *wc, int unit, int master, int slave);
 static void __t4_check_alarms(struct t4 *wc, int span);
 static void __t4_check_sigbits(struct t4 *wc, int span);
 
@@ -371,14 +383,15 @@
 /* #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_LCS		(1 << 11)
 #define WC_LCS2		(1 << 12)
-#define WC_LALE		(1 << 13)
+#define WC_LALE			(1 << 13)
+#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)
 
@@ -399,24 +412,32 @@
 #define MAX_TDM_CHAN 32
 #define MAX_DTMF_DET 16
 
+#define HDLC_IMR0_MASK (FRMR_IMR0_RME | FRMR_IMR0_RPF)
+#if 0
+#define HDLC_IMR1_MASK (FRMR_IMR1_ALLS | FRMR_IMR1_XDU | FRMR_IMR1_XPR)
+#else
+#define HDLC_IMR1_MASK	(FRMR_IMR1_XDU | FRMR_IMR1_XPR)
+#endif
+
+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);
-	tmp = le32_to_cpu(wc->membase[WC_VERSION]);
+	tmp = __t4_pci_in(wc, WC_VERSION);
 	if ((tmp & 0xffff0000) != 0xc01a0000)
 		printk("TE4XXP: Version Synchronization Error!\n");
 #if 0
-	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_gpio_set(struct t4 *wc, unsigned bits, unsigned int val)
@@ -496,10 +517,10 @@
 	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);
 	__t4_pci_out(wc, WC_VERSION, 0);
 	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;
 }
 
@@ -521,15 +542,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);
 	} }
@@ -566,7 +585,7 @@
 static inline void __t4_raw_oct_out(struct t4 *wc, const unsigned int addr, const unsigned int value)
 {
 	int octopt = wc->tspans[0]->spanflags & FLAG_OCTOPT;
-	if (!octopt)
+	if (!octopt) 
 		__t4_gpio_set(wc, 0xff, (addr >> 8));
 	__t4_pci_out(wc, WC_LDATA, 0x10000 | (addr & 0xffff));
 	if (!octopt)
@@ -717,14 +736,17 @@
 	while(vpm450m_getdtmf(wc->vpm450m, &channel, &tone, &start)) {
 		span = channel & 0x3;
 		channel >>= 2;
-		if (!wc->t1e1)channel -= 5;
+		if (!wc->t1e1)
+			channel -= 5;
 		else
 			channel -= 1;
 		if (debug)
-			printk("Got tone %s of '%c' on channel %d of span %d\n",(start ? "START" : "STOP"), tone, channel, span + 1);
+			printk("Got tone %s of '%c' on channel %d of span %d\n",
+				(start ? "START" : "STOP"), tone, channel, span + 1);
 		if ((wc->tspans[span]->dtmfmask & (1 << channel)) && (tone != 'u')) {
 			if (start) {
-				/* The octasic is supposed to mute us, but...  Yah, you guessed it.  */
+				/* The octasic is supposed to mute us, but...  Yah, you
+				   guessed it.  */
 				if (wc->tspans[span]->dtmfmutemask & (1 << channel)) {
 					unsigned long flags;
 					struct zt_chan *chan = &wc->tspans[span]->span.chans[channel];
@@ -848,6 +870,107 @@
 }
 #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;
+
+	if (debug & DEBUG_FRAMER) printk("Stopping HDLC controller on span %d\n", span+1);
+	
+	/* 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 |= HDLC_IMR0_MASK;
+	__t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+	imr1 |= HDLC_IMR1_MASK;
+	__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->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("Starting HDLC controller for channel %d span %d\n", offset, span+1);
+
+	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 &= ~HDLC_IMR0_MASK;
+	__t4_framer_out(wc, span, FRMR_IMR0, imr0);
+
+	imr1 &= ~HDLC_IMR1_MASK;
+	__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)
 {
@@ -883,12 +1006,12 @@
 	}
 	if (ts->notclear != oldnotclear) {
 		unsigned char reg;
-		reg = __t4_framer_in(wc, span, 0x14);
+		reg = __t4_framer_in(wc, span, FRMR_IMR0);
 		if (ts->notclear)
 			reg &= ~0x08;
 		else
 			reg |= 0x08;
-		__t4_framer_out(wc, span, 0x14, reg);
+		__t4_framer_out(wc, span, FRMR_IMR0, reg);
 	}
 }
 
@@ -972,7 +1095,7 @@
 	struct t4 *wc = chan->pvt;
 	int channel;
 	int unit;
-
+	
 	if (!wc->vpm)
 		return -ENODEV;
 
@@ -987,19 +1110,21 @@
 		channel = channel << 2;
 		channel |= chan->span->offset;
 		if(debug & DEBUG_ECHOCAN) 
-			printk("echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n", wc->num, chan->chanpos, chan->span->offset, channel, eclen);
+			printk("echocan: Card is %d, Channel is %d, Span is %d, offset is %d length %d\n", 
+				wc->num, chan->chanpos, chan->span->offset, channel, eclen);
 		vpm450m_setec(wc->vpm450m, channel, eclen);
-		// Mark		msleep(10);
-		// //		msleep(100); // longer test
-		} else {
-			unit = t4_vpm_unit(chan->span->offset, channel);
-			if(debug & DEBUG_ECHOCAN) 
-				printk("echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n", wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
-			if (eclen)
-				t4_vpm_out(wc,unit,channel,0x3e);
-			else
-				t4_vpm_out(wc,unit,channel,0x01);
-		}
+// Mark		msleep(10);
+//		msleep(100); // longer test
+	} else {
+		unit = t4_vpm_unit(chan->span->offset, channel);
+		if(debug & DEBUG_ECHOCAN) 
+			printk("echocan: Card is %d, Channel is %d, Span is %d, unit is %d, unit offset is %d length %d\n", 
+				wc->num, chan->chanpos, chan->span->offset, unit, channel, eclen);
+		if (eclen)
+			t4_vpm_out(wc,unit,channel,0x3e);
+		else
+			t4_vpm_out(wc,unit,channel,0x01);
+	}
 	return 0;
 }
 #endif
@@ -1062,6 +1187,63 @@
 		return -ENOTTY;
 	}
 	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 (!ts->sigchan) {
+		printk("t4_hdlc_hard_xmit: Invalid (NULL) signalling channel\n");
+		spin_unlock_irqrestore(&wc->reglock, flags);
+		return;
+	}
+	if (debug & DEBUG_FRAMER) printk("t4_hdlc_hard_xmit on channel %s (sigchan %s), sigactive=%d\n", chan->name, ts->sigchan->name, 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)
@@ -1189,12 +1371,19 @@
 		return -1;
 	}
 
+	if (debug & DEBUG_MAIN) printk("Shutting down span %d (%s)\n", span->spanno, span->name);
+	
 	spin_lock_irqsave(&wc->reglock, flags);
 	wasrunning = span->flags & ZT_FLAG_RUNNING;
 
 	span->flags &= ~ZT_FLAG_RUNNING;
 	if (wasrunning)
 		wc->spansstarted--;
+
+	/* Stop HDLC controller if runned */
+	if (ts->sigchan)
+		__hdlc_stop(wc, span->offset);
+
 	__t4_set_led(wc, span->offset, WC_OFF);
 	if (((wc->numspans == 4) && 
 	    (!(wc->tspans[0]->span.flags & ZT_FLAG_RUNNING)) &&
@@ -1247,6 +1436,7 @@
 		wc->tspans[lc->sync - 1]->psync = span->offset + 1;
 	}
 	wc->checktiming = 1;
+	
 	/* If we're already running, then go ahead and apply the changes */
 	if (span->flags & ZT_FLAG_RUNNING)
 		return t4_startup(span);
@@ -1259,17 +1449,44 @@
 	int alreadyrunning;
 	unsigned long flags;
 	struct t4 *wc = chan->pvt;
-
-	alreadyrunning = wc->tspans[chan->span->offset]->span.flags & ZT_FLAG_RUNNING;
+	struct t4_span *ts = wc->tspans[chan->span->offset];
+
+	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);
+
+	/* (re)configure signalling channel */
+	if ((sigtype == ZT_SIG_HARDHDLC) || (ts->sigchan == chan)) {
+		if (debug & DEBUG_FRAMER)
+				printk("%sonfiguring hardware HDLC on %s\n", ((sigtype == ZT_SIG_HARDHDLC) ? "C" : "Unc"), chan->name);
+		if (alreadyrunning) {
+			if (ts->sigchan)
+				__hdlc_stop(wc, ts->sigchan->span->offset);
+			if (sigtype == ZT_SIG_HARDHDLC) {
+				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 = NULL;
+		
+		}
+		else {
+			ts->sigchan = (sigtype == ZT_SIG_HARDHDLC) ? chan : NULL;
+			ts->sigactive = 0;
+		}
+	}
 	spin_unlock_irqrestore(&wc->reglock, flags);	
 	return 0;
 }
@@ -1318,6 +1535,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;
@@ -1329,6 +1552,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;
@@ -1344,7 +1568,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;
@@ -1377,26 +1601,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 */
@@ -1409,7 +1633,16 @@
 		printk("Successfully initialized serial bus for unit %d\n", unit);
 }
 
-static void __t4_set_timing_source(struct t4 *wc, int unit)
+static int syncsrc = 0;
+static int syncnum = 0 /* -1 */;
+static int syncspan = 0;
+#ifdef DEFINE_SPINLOCK
+static DEFINE_SPINLOCK(synclock);
+#else
+static spinlock_t synclock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static void __t4_set_timing_source(struct t4 *wc, int unit, int master, int slave)
 {
 	unsigned int timing;
 	int x;
@@ -1420,20 +1653,30 @@
 			for (x=0;x<wc->numspans;x++)  /* set all 4 receive reference clocks to unit */
 				__t4_framer_out(wc, x, 0x44, timing);
 			wc->dmactrl |= (1 << 29);
-			__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
 		} else {
 			for (x=0;x<wc->numspans;x++) /* set each receive reference clock to itself */
 				__t4_framer_out(wc, x, 0x44, timing | (x << 6));
 			wc->dmactrl &= ~(1 << 29);
-			__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
-		}
-		wc->syncsrc = unit;
+		}
+		if (slave)
+			wc->dmactrl |= (1 << 25);
+		else
+			wc->dmactrl &= ~(1 << 25);
+		if (master)
+			wc->dmactrl |= (1 << 24);
+		else
+			wc->dmactrl &= ~(1 << 24);
+		__t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
+		if (!master && !slave)
+			wc->syncsrc = unit;
 		if ((unit < 0) || (unit > 3))
 			unit = 0;
 		else
 			unit++;
-		for (x=0;x<wc->numspans;x++)
-			wc->tspans[x]->span.syncsrc = unit;
+		if (!master && !slave) {
+			for (x=0;x<wc->numspans;x++)
+				wc->tspans[x]->span.syncsrc = unit;
+		}
 	} else {
 		if (debug & DEBUG_MAIN)
 			printk("TE%dXXP: Timing source already set to %d\n", wc->numspans, unit);
@@ -1443,21 +1686,104 @@
 #endif
 }
 
+static inline void __t4_update_timing(struct t4 *wc)
+{
+	int i;
+	/* update sync src info */
+	if (wc->syncsrc != syncsrc) {
+		printk("Swapping card %d from %d to %d\n", wc->num, wc->syncsrc, syncsrc);
+		wc->syncsrc = syncsrc;
+		/* Update sync sources */
+		for (i = 0; i < wc->numspans; i++) {
+			wc->tspans[i]->span.syncsrc = wc->syncsrc;
+		}
+		if (syncnum == wc->num) {
+			__t4_set_timing_source(wc, syncspan-1, 1, 0);
+			if (debug) printk("Card %d, using sync span %d, master\n", wc->num, syncspan);
+		} else {
+			__t4_set_timing_source(wc, syncspan-1, 0, 1);
+			if (debug) printk("Card %d, using Timing Bus, NOT master\n", wc->num);	
+		}
+	}
+}
+
+static int __t4_findsync(struct t4 *wc)
+{
+	int i;
+	int x;
+	unsigned long flags;
+	int p;
+	int nonzero;
+	int newsyncsrc = 0;			/* Zaptel span number */
+	int newsyncnum = 0;			/* wct4xxp card number */
+	int newsyncspan = 0;		/* span on given wct4xxp card */
+	spin_lock_irqsave(&synclock, flags);
+#if 1
+	if (!wc->num) {
+		/* If we're the first card, go through all the motions, up to 8 levels
+		   of sync source */
+		p = 1;
+		while (p < 8) {
+			nonzero = 0;
+			for (x=0;cards[x];x++) {
+				for (i = 0; i < wc->numspans; i++) {
+					if (cards[x]->tspans[i]->syncpos) {
+						nonzero = 1;
+						if ((cards[x]->tspans[i]->syncpos == p) &&
+						    !(cards[x]->tspans[i]->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE | ZT_ALARM_LOOPBACK)) &&
+							(cards[x]->tspans[i]->span.flags & ZT_FLAG_RUNNING)) {
+								/* This makes a good sync source */
+								newsyncsrc = cards[x]->tspans[i]->span.spanno;
+								newsyncnum = x;
+								newsyncspan = i + 1;
+								/* Jump out */
+								goto found;
+						}
+					}
+				}		
+			}
+			if (nonzero)
+				p++;
+			else 
+				break;
+		}
+found:		
+		if ((syncnum != newsyncnum) || (syncsrc != newsyncsrc) || (newsyncspan != syncspan)) {
+			if (debug) printk("New syncnum: %d (was %d), syncsrc: %d (was %d), syncspan: %d (was %d)\n", newsyncnum, syncnum, newsyncsrc, syncsrc, newsyncspan, syncspan);
+			syncnum = newsyncnum;
+			syncsrc = newsyncsrc;
+			syncspan = newsyncspan;
+			for (x=0;cards[x];x++) {
+				__t4_update_timing(cards[x]);
+			}
+		}
+	} else
+		cards[0]->checktiming = 1;
+#endif	
+	spin_unlock_irqrestore(&synclock, flags);
+	return 0;
+}
+
 static void __t4_set_timing_source_auto(struct t4 *wc)
 {
 	int x;
+	printk("timing source auto card %d!\n", wc->num);
 	wc->checktiming = 0;
-	for (x=0;x<wc->numspans;x++) {
-		if (wc->tspans[x]->sync) {
-			if ((wc->tspans[wc->tspans[x]->psync - 1]->span.flags & ZT_FLAG_RUNNING) && 
-				!(wc->tspans[wc->tspans[x]->psync - 1]->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE) )) {
-					/* Valid timing source */
-					__t4_set_timing_source(wc, wc->tspans[x]->psync - 1);
-					return;
-			}
-		}
-	}
-	__t4_set_timing_source(wc, 4);
+	if (timingcable) {
+		__t4_findsync(wc);
+	} else {
+		for (x=0;x<wc->numspans;x++) {
+			if (wc->tspans[x]->sync) {
+				if ((wc->tspans[wc->tspans[x]->psync - 1]->span.flags & ZT_FLAG_RUNNING) && 
+					!(wc->tspans[wc->tspans[x]->psync - 1]->span.alarms & (ZT_ALARM_RED | ZT_ALARM_BLUE) )) {
+						/* Valid timing source */
+						__t4_set_timing_source(wc, wc->tspans[x]->psync - 1, 0, 0);
+						return;
+				}
+			}
+		}
+		__t4_set_timing_source(wc, 4, 0, 0);
+	}
 }
 
 static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlevel)
@@ -1533,8 +1859,9 @@
 		break;
 	}
 
-	__t4_framer_out(wc, unit, 0x14, 0xff);	/* IMR0: We care about CAS changes, etc */
-	__t4_framer_out(wc, unit, 0x15, 0xff);	/* IMR1: We care about nothing */
+	/* Don't mask framer interrupts if hardware HDLC is in use */
+	__t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0));	/* IMR0: We care about CAS changes, etc */
+	__t4_framer_out(wc, unit, FRMR_IMR1, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0));	/* IMR1: We care about nothing */
 	__t4_framer_out(wc, unit, 0x16, 0x00);	/* IMR2: We care about all the alarm stuff! */
 	if (debugslips) {
 		__t4_framer_out(wc, unit, 0x17, 0xf4);	/* IMR3: We care about AIS and friends */
@@ -1621,8 +1948,9 @@
 	__t4_framer_out(wc, unit, 0x27, 0x02);	/* XPM1 */
 	__t4_framer_out(wc, unit, 0x28, 0x00);	/* XPM2 */
 
-	__t4_framer_out(wc, unit, 0x14, 0xff);	/* IMR0: We care about CRC errors, CAS changes, etc */
-	__t4_framer_out(wc, unit, 0x15, 0x3f);	/* IMR1: We care about loopup / loopdown */
+	/* Don't mask framer interrupts if hardware HDLC is in use */
+	__t4_framer_out(wc, unit, FRMR_IMR0, 0xff & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR0_MASK : 0));	/* IMR0: We care about CRC errors, CAS changes, etc */
+	__t4_framer_out(wc, unit, FRMR_IMR1, 0x3f & ~((wc->tspans[unit]->sigchan) ? HDLC_IMR1_MASK : 0));	/* IMR1: We care about loopup / loopdown */
 	__t4_framer_out(wc, unit, 0x16, 0x00);	/* IMR2: We care about all the alarm stuff! */
 	if (debugslips) {
 		__t4_framer_out(wc, unit, 0x17, 0xc4 | imr3extra);	/* IMR3: We care about AIS and friends */
@@ -1702,6 +2030,15 @@
 		if (!polling) {
 			__t4_check_alarms(wc, span->offset);
 			__t4_check_sigbits(wc, span->offset);
+		}
+		/* Startup HDLC controller too */
+		if (ts->sigchan) {
+			if (__hdlc_start(wc, 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;
+			}
 		}
 	}
 
@@ -1847,10 +2184,11 @@
 	unsigned int merged;
 	merged = ts->dtmfactive & ts->dtmfmutemask;
 	if (merged) {
-	for (y=0;y<ts->span.channels;y++) {
+		for (y=0;y<ts->span.channels;y++) {
 			/* Mute any DTMFs which are supposed to be muted */
-			if (merged & (1 << y)) {
-				memset(ts->span.chans[y].readchunk, ZT_XLAW(0, (ts->span.chans + y)), ZT_CHUNKSIZE);			}
+			if (merged & (1 << y))  {
+				memset(ts->span.chans[y].readchunk, ZT_XLAW(0, (ts->span.chans + y)), ZT_CHUNKSIZE);
+			}
 		}
 	}
 #endif	
@@ -2240,6 +2578,140 @@
 #endif
 }
 
+static inline void __t4_framer_interrupt(struct t4 *wc, int span)
+{
+	/* Check interrupts for a given span */
+	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);
+
+	/* 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 (ts->spantype == TYPE_E1) {
+		/* E1 checks */
+		if ((isr3 & 0x38) || isr2 || isr1)
+			__t4_check_alarms(wc, span);
+	} else {
+		/* T1 checks */
+		if (isr2 || (isr3 & 0x08)) 
+			__t4_check_alarms(wc, span);		
+	}
+	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 (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 (!ts->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 SUPPORT_GEN1
 #ifdef LINUX26
 static irqreturn_t t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2252,9 +2724,7 @@
 	int x;
 	
 	unsigned int status;
-#if 0
 	unsigned int status2;
-#endif
 
 #if 0
 	if (wc->intcount < 20)
@@ -2265,6 +2735,17 @@
 	/* Make sure it's really for us */
 	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)
@@ -2296,10 +2777,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);
 		}
 	}
@@ -2335,68 +2816,6 @@
 }
 #endif
 
-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;
-
-	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);
-
-
-		if (isr0)  
-			__t4_check_sigbits(wc, span);
-		
-		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)

[... 307 lines stripped ...]


More information about the zaptel-commits mailing list