summaryrefslogtreecommitdiff
path: root/wct4xxp.c
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-02-21 06:40:48 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-02-21 06:40:48 +0000
commitf032f3b22194bf0d88108ff0a2c09d1a07d7de4e (patch)
treef4da6948e3bc7f0471cdd357a93e60259986f9e2 /wct4xxp.c
parente1d0fe894863b44be36d0fe1bef5dcd53b9eb7e5 (diff)
Add support for timing cable
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@964 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'wct4xxp.c')
-rw-r--r--wct4xxp.c138
1 files changed, 120 insertions, 18 deletions
diff --git a/wct4xxp.c b/wct4xxp.c
index a928146..d98da65 100644
--- a/wct4xxp.c
+++ b/wct4xxp.c
@@ -168,7 +168,7 @@ static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct
#endif
static int debug=0;
-static int timingcable;
+static int timingcable = 0;
static int highestorder;
static int t1e1override = -1;
static int j1mode = 0;
@@ -350,7 +350,7 @@ 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);
@@ -1149,7 +1149,7 @@ static int t4_shutdown(struct zt_span *span)
__t4_pci_out(wc, WC_DMACTRL, 0x00000000);
/* Acknowledge any pending interrupts */
__t4_pci_out(wc, WC_INTR, 0x00000000);
- __t4_set_timing_source(wc,4);
+ __t4_set_timing_source(wc, 4, 0, 0);
} else wc->checktiming = 1;
spin_unlock_irqrestore(&wc->reglock, flags);
if (debug & DEBUG_MAIN)
@@ -1386,7 +1386,16 @@ static void t4_serial_setup(struct t4 *wc, int unit)
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;
@@ -1397,20 +1406,30 @@ static void __t4_set_timing_source(struct t4 *wc, int unit)
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);
@@ -1420,21 +1439,104 @@ static void __t4_set_timing_source(struct t4 *wc, int unit)
#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 < 4; 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 < 4; 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;
+ 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);
}
- __t4_set_timing_source(wc, 4);
}
static void __t4_configure_t1(struct t4 *wc, int unit, int lineconfig, int txlevel)
@@ -3006,7 +3108,7 @@ static int __devinit t4_launch(struct t4 *wc)
}
wc->checktiming = 1;
spin_lock_irqsave(&wc->reglock, flags);
- __t4_set_timing_source(wc,4);
+ __t4_set_timing_source(wc,4, 0, 0);
spin_unlock_irqrestore(&wc->reglock, flags);
#ifdef ENABLE_TASKLETS
tasklet_init(&wc->t4_tlet, t4_tasklet, (unsigned long)wc);