[zaptel-commits] trunk - r888 /trunk/wct4xxp.c

zaptel-commits at lists.digium.com zaptel-commits at lists.digium.com
Tue Jan 10 16:08:11 CST 2006


Author: mattf
Date: Tue Jan 10 16:08:10 2006
New Revision: 888

URL: http://svn.digium.com/view/zaptel?rev=888&view=rev
Log:
Add experimental support for Hardware HDLC for D-channels (#5313)

Modified:
    trunk/wct4xxp.c

Modified: trunk/wct4xxp.c
URL: http://svn.digium.com/view/zaptel/trunk/wct4xxp.c?rev=888&r1=887&r2=888&view=diff
==============================================================================
--- trunk/wct4xxp.c (original)
+++ trunk/wct4xxp.c Tue Jan 10 16:08:10 2006
@@ -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
@@ -252,6 +255,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;
@@ -335,6 +346,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);
@@ -350,11 +362,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)
 
@@ -375,21 +388,22 @@
 #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)
@@ -431,9 +445,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;
 }
 
@@ -455,15 +469,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);
 	} }
@@ -643,6 +655,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)
 {
@@ -825,6 +943,58 @@
 		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 (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)
@@ -958,6 +1128,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)) &&
@@ -1014,6 +1189,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);
@@ -1026,17 +1210,36 @@
 	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);
+
+	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;
 }
@@ -1085,6 +1288,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;
@@ -1096,6 +1305,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;
@@ -1111,7 +1321,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;
@@ -1144,26 +1354,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 */
@@ -1470,6 +1680,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);
@@ -1996,6 +2216,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)
@@ -2008,9 +2230,7 @@
 	int x;
 	
 	unsigned int status;
-#if 0
 	unsigned int status2;
-#endif
 
 #if 0
 	if (wc->intcount < 20)
@@ -2021,6 +2241,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)
@@ -2052,10 +2283,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);
 		}
 	}
@@ -2094,64 +2325,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);
-	
+
+	/* 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 (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)
-			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
@@ -2202,7 +2504,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) {
@@ -2254,14 +2556,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
@@ -3024,6 +3326,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);
@@ -3040,6 +3343,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");



More information about the zaptel-commits mailing list