summaryrefslogtreecommitdiff
path: root/wct4xxp.c
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-01-10 22:08:10 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-01-10 22:08:10 +0000
commita75acc622c798c29b4f4a62ea200c248043b2d7a (patch)
tree2d1e2684e1e35d258477bb7e68d4b3fcd8e4f493 /wct4xxp.c
parent46962b1907b7c476a969e898f682e82405ef317e (diff)
Add experimental support for Hardware HDLC for D-channels (#5313)
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@888 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wct4xxp.c')
-rw-r--r--wct4xxp.c456
1 files changed, 380 insertions, 76 deletions
diff --git a/wct4xxp.c b/wct4xxp.c
index 7ce1e19..92e45c4 100644
--- a/wct4xxp.c
+++ b/wct4xxp.c
@@ -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 timingcable;
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 @@ struct t4_span {
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 @@ static int t4_maint(struct zt_span *span, int cmd);
#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 @@ static void __t4_check_sigbits(struct t4 *wc, int span);
/* #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,23 +388,24 @@ static struct t4 *cards[MAX_T4_CARDS];
#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;
@@ -431,9 +445,9 @@ static inline unsigned int __t4_framer_in(struct t4 *wc, int unit, const unsigne
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 @@ static inline void __t4_framer_out(struct t4 *wc, int unit, const unsigned int a
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 @@ static void __t4_check_vpm(struct t4 *wc, unsigned int newio)
}
#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)
{
@@ -827,6 +945,58 @@ static int t4_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
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;
@@ -958,6 +1128,11 @@ static int t4_shutdown(struct zt_span *span)
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 @@ static int t4_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
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 @@ static int t4_chanconfig(struct zt_chan *chan, int sigtype)
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;
}
@@ -1085,6 +1288,12 @@ static void init_spans(struct t4 *wc)
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 @@ static void init_spans(struct t4 *wc)
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 @@ static void init_spans(struct t4 *wc)
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 @@ static void t4_serial_setup(struct t4 *wc, int unit)
}
/* 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 @@ static int t4_startup(struct zt_span *span)
__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 @@ static inline void __handle_leds(struct t4 *wc)
#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 @@ static void t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int x;
unsigned int status;
-#if 0
unsigned int status2;
-#endif
#if 0
if (wc->intcount < 20)
@@ -2022,6 +2242,17 @@ static void t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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
@@ -2052,10 +2283,10 @@ static void t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#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 void t4_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
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 @@ static void t4_interrupt_gen2(int irq, void *dev_id, struct pt_regs *regs)
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(timingcable, int, 0600);
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(timingcable, "i");
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");