diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-02-21 06:40:48 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-02-21 06:40:48 +0000 |
commit | f032f3b22194bf0d88108ff0a2c09d1a07d7de4e (patch) | |
tree | f4da6948e3bc7f0471cdd357a93e60259986f9e2 /wct4xxp.c | |
parent | e1d0fe894863b44be36d0fe1bef5dcd53b9eb7e5 (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.c | 138 |
1 files changed, 120 insertions, 18 deletions
@@ -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); |