summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-12-04 04:19:41 +0000
committermarkster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2004-12-04 04:19:41 +0000
commit842c921a5eb0928f6bdd31fcfb610849c2048c1a (patch)
treed2e3c36b3669df220cb0484348ff2aca885ba450
parent1d4fed5eca5c005d697921844cae53db01910d37 (diff)
Add ztd-loc, restruct wctdm for GCC 3.4 (bug #2021)
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@505 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rwxr-xr-xMakefile6
-rwxr-xr-xwctdm.c447
-rwxr-xr-xztd-loc.c272
3 files changed, 498 insertions, 227 deletions
diff --git a/Makefile b/Makefile
index 83e399c..5487373 100755
--- a/Makefile
+++ b/Makefile
@@ -54,7 +54,8 @@ endif
TZOBJS=zonedata.lo tonezone.lo
LIBTONEZONE=libtonezone.so.1.0
MODULES=zaptel tor2 torisa wcusb wcfxo wctdm \
- ztdynamic ztd-eth wct1xxp wct4xxp wcte11xp pciradio # ztdummy
+ ztdynamic ztd-eth wct1xxp wct4xxp wcte11xp pciradio \
+ ztd-loc # ztdummy
#MODULES+=wcfxsusb
MODULESO=$(shell for x in $(MODULES); do echo "$$x.o "; done )
@@ -114,6 +115,9 @@ wct1xxp.o:wct1xxp.c zaptel.h
wcte11xp.o:wcte11xp.c zaptel.h
$(HOSTCC) $(KFLAGS) -c wcte11xp.c
+ztd-loc.o:ztd-loc.c zaptel.h
+ $(HOSTCC) $(KFLAGS) -c ztd-loc.c
+
wct4xxp.o:wct4xxp.c zaptel.h
$(HOSTCC) $(KFLAGS) -c wct4xxp.c
diff --git a/wctdm.c b/wctdm.c
index 1101b92..7b74437 100755
--- a/wctdm.c
+++ b/wctdm.c
@@ -471,10 +471,6 @@ static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char ints)
zt_receive(&wc->span);
}
-static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card);
-static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card);
-static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card);
-
static void wctdm_stop_dma(struct wctdm *wc);
static void wctdm_reset_tdm(struct wctdm *wc);
static void wctdm_restart_dma(struct wctdm *wc);
@@ -741,6 +737,227 @@ static int wctdm_proslic_verify_indirect_regs(struct wctdm *wc, int card)
return 0;
}
+static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
+{
+ int res;
+ /* Check loopback */
+ res = wctdm_getreg(wc, card, 8);
+ if (res) {
+ printk("Ouch, part reset, quickly restoring reality (%d)\n", card);
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ } else {
+ res = wctdm_getreg(wc, card, 64);
+ if (!res && (res != wc->mod.fxs.lasttxhook[card])) {
+ if (wc->mod.fxs.palarms[card]++ < MAX_ALARMS) {
+ printk("Power alarm on module %d, resetting!\n", card + 1);
+ if (wc->mod.fxs.lasttxhook[card] == 4)
+ wc->mod.fxs.lasttxhook[card] = 1;
+ wctdm_setreg(wc, card, 64, wc->mod.fxs.lasttxhook[card]);
+ } else {
+ if (wc->mod.fxs.palarms[card] == MAX_ALARMS)
+ printk("Too many power alarms on card %d, NOT resetting!\n", card + 1);
+ }
+ }
+ }
+}
+
+static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
+{
+#ifndef AUDIO_RINGCHECK
+ unsigned char res;
+#endif
+ signed char b;
+ int poopy = 0;
+ /* Try to track issues that plague slot one FXO's */
+ b = wctdm_getreg(wc, card, 5);
+ if ((b & 0x2) || !(b & 0x8)) {
+ /* Not good -- don't look at anything else */
+ if (debug)
+ printk("Poopy (%02x) on card %d!\n", b, card + 1);
+ poopy++;
+ }
+ b &= 0x9b;
+ if (wc->mod.fxo.offhook[card]) {
+ if (b != 0x9)
+ wctdm_setreg(wc, card, 5, 0x9);
+ } else {
+ if (b != 0x8)
+ wctdm_setreg(wc, card, 5, 0x8);
+ }
+ if (poopy)
+ return;
+#ifndef AUDIO_RINGCHECK
+ if (!wc->mod.fxo.offhook[card]) {
+ res = wctdm_getreg(wc, card, 5);
+ if ((res & 0x60) && wc->mod.fxo.battery[card]) {
+ wc->mod.fxo.ringdebounce[card] += (ZT_CHUNKSIZE * 4);
+ if (wc->mod.fxo.ringdebounce[card] >= ZT_CHUNKSIZE * 64) {
+ if (!wc->mod.fxo.wasringing[card]) {
+ wc->mod.fxo.wasringing[card] = 1;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
+ if (debug)
+ printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ wc->mod.fxo.ringdebounce[card] = ZT_CHUNKSIZE * 64;
+ }
+ } else {
+ wc->mod.fxo.ringdebounce[card] -= ZT_CHUNKSIZE;
+ if (wc->mod.fxo.ringdebounce[card] <= 0) {
+ if (wc->mod.fxo.wasringing[card]) {
+ wc->mod.fxo.wasringing[card] =0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
+ }
+ wc->mod.fxo.ringdebounce[card] = 0;
+ }
+
+ }
+ }
+#endif
+ b = wctdm_getreg(wc, card, 29);
+#if 0
+ {
+ static int count = 0;
+ if (!(count++ % 100)) {
+ printk("Card %d: Voltage: %d Debounce %d\n", card + 1,
+ b, wc->mod.fxo.battdebounce[card]);
+ }
+ }
+#endif
+ if (abs(b) < battthresh) {
+ wc->mod.fxo.nobatttimer[card]++;
+#if 0
+ if (wc->mod.fxo.battery[card])
+ printk("Battery loss: %d (%d debounce)\n", b, wc->mod.fxo.battdebounce[card]);
+#endif
+ if (wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) {
+ if (debug)
+ printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
+ wc->mod.fxo.battery[card] = 0;
+#ifdef JAPAN
+ if ((!wc->ohdebounce) && wc->offhook) {
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ if (debug)
+ printk("Signalled On Hook\n");
+#ifdef ZERO_BATT_RING
+ wc->onhook++;
+#endif
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+#endif
+ wc->mod.fxo.battdebounce[card] = battdebounce;
+ } else if (!wc->mod.fxo.battery[card])
+ wc->mod.fxo.battdebounce[card] = battdebounce;
+ } else if (abs(b) > battthresh) {
+ if (!wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) {
+ if (debug)
+ printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
+ (b < 0) ? "-" : "+");
+#ifdef ZERO_BATT_RING
+ if (wc->onhook) {
+ wc->onhook = 0;
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (debug)
+ printk("Signalled Off Hook\n");
+ }
+#else
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+#endif
+ wc->mod.fxo.battery[card] = 1;
+ wc->mod.fxo.nobatttimer[card] = 0;
+ wc->mod.fxo.battdebounce[card] = battdebounce;
+ } else if (wc->mod.fxo.battery[card])
+ wc->mod.fxo.battdebounce[card] = battdebounce;
+
+ if (wc->mod.fxo.lastpol[card] >= 0) {
+ if (b < 0) {
+ wc->mod.fxo.lastpol[card] = -1;
+ wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE;
+ }
+ }
+ if (wc->mod.fxo.lastpol[card] <= 0) {
+ if (b > 0) {
+ wc->mod.fxo.lastpol[card] = 1;
+ wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE;
+ }
+ }
+ } else {
+ /* It's something else... */
+ wc->mod.fxo.battdebounce[card] = battdebounce;
+ }
+ if (wc->mod.fxo.battdebounce[card])
+ wc->mod.fxo.battdebounce[card]--;
+ if (wc->mod.fxo.polaritydebounce[card]) {
+ wc->mod.fxo.polaritydebounce[card]--;
+ if (wc->mod.fxo.polaritydebounce[card] < 1) {
+ if (wc->mod.fxo.lastpol[card] != wc->mod.fxo.polarity[card]) {
+ if (debug)
+ printk("%lu Polarity reversed (%d -> %d)\n", jiffies,
+ wc->mod.fxo.polarity[card],
+ wc->mod.fxo.lastpol[card]);
+ if (wc->mod.fxo.polarity[card])
+ zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
+ wc->mod.fxo.polarity[card] = wc->mod.fxo.lastpol[card];
+ }
+ }
+ }
+}
+
+static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
+{
+ char res;
+ int hook;
+
+ /* For some reason we have to debounce the
+ hook detector. */
+
+ res = wctdm_getreg(wc, card, 68);
+ hook = (res & 1);
+ if (hook != wc->mod.fxs.lastrxhook[card]) {
+ /* Reset the debounce (must be multiple of 4ms) */
+ wc->mod.fxs.debounce[card] = 8 * (4 * 8);
+#if 0
+ printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod.fxs.debounce[card]);
+#endif
+ } else {
+ if (wc->mod.fxs.debounce[card] > 0) {
+ wc->mod.fxs.debounce[card]-= 4 * ZT_CHUNKSIZE;
+#if 0
+ printk("Sustaining hook %d, %d\n", hook, wc->mod.fxs.debounce[card]);
+#endif
+ if (!wc->mod.fxs.debounce[card]) {
+#if 0
+ printk("Counted down debounce, newhook: %d...\n", hook);
+#endif
+ wc->mod.fxs.debouncehook[card] = hook;
+ }
+ if (!wc->mod.fxs.oldrxhook[card] && wc->mod.fxs.debouncehook[card]) {
+ /* Off hook */
+#if 1
+ if (debug)
+#endif
+ printk("wctdm: Card %d Going off hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
+ if (robust)
+ wctdm_init_proslic(wc, card, 1, 0, 1);
+ wc->mod.fxs.oldrxhook[card] = 1;
+
+ } else if (wc->mod.fxs.oldrxhook[card] && !wc->mod.fxs.debouncehook[card]) {
+ /* On hook */
+#if 1
+ if (debug)
+#endif
+ printk("wctdm: Card %d Going on hook\n", card);
+ zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
+ wc->mod.fxs.oldrxhook[card] = 0;
+ }
+ }
+ }
+ wc->mod.fxs.lastrxhook[card] = hook;
+}
+
#ifdef LINUX26
static irqreturn_t wctdm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
@@ -1358,228 +1575,6 @@ static int wctdm_init_proslic(struct wctdm *wc, int card, int fast, int manual,
return 0;
}
-static inline void wctdm_proslic_recheck_sanity(struct wctdm *wc, int card)
-{
- int res;
- /* Check loopback */
- res = wctdm_getreg(wc, card, 8);
- if (res) {
- printk("Ouch, part reset, quickly restoring reality (%d)\n", card);
- wctdm_init_proslic(wc, card, 1, 0, 1);
- } else {
- res = wctdm_getreg(wc, card, 64);
- if (!res && (res != wc->mod.fxs.lasttxhook[card])) {
- if (wc->mod.fxs.palarms[card]++ < MAX_ALARMS) {
- printk("Power alarm on module %d, resetting!\n", card + 1);
- if (wc->mod.fxs.lasttxhook[card] == 4)
- wc->mod.fxs.lasttxhook[card] = 1;
- wctdm_setreg(wc, card, 64, wc->mod.fxs.lasttxhook[card]);
- } else {
- if (wc->mod.fxs.palarms[card] == MAX_ALARMS)
- printk("Too many power alarms on card %d, NOT resetting!\n", card + 1);
- }
- }
- }
-}
-
-static inline void wctdm_voicedaa_check_hook(struct wctdm *wc, int card)
-{
-#ifndef AUDIO_RINGCHECK
- unsigned char res;
-#endif
- signed char b;
- int poopy = 0;
- /* Try to track issues that plague slot one FXO's */
- b = wctdm_getreg(wc, card, 5);
- if ((b & 0x2) || !(b & 0x8)) {
- /* Not good -- don't look at anything else */
- if (debug)
- printk("Poopy (%02x) on card %d!\n", b, card + 1);
- poopy++;
- }
- b &= 0x9b;
- if (wc->mod.fxo.offhook[card]) {
- if (b != 0x9)
- wctdm_setreg(wc, card, 5, 0x9);
- } else {
- if (b != 0x8)
- wctdm_setreg(wc, card, 5, 0x8);
- }
- if (poopy)
- return;
-#ifndef AUDIO_RINGCHECK
- if (!wc->mod.fxo.offhook[card]) {
- res = wctdm_getreg(wc, card, 5);
- if ((res & 0x60) && wc->mod.fxo.battery[card]) {
- wc->mod.fxo.ringdebounce[card] += (ZT_CHUNKSIZE * 4);
- if (wc->mod.fxo.ringdebounce[card] >= ZT_CHUNKSIZE * 64) {
- if (!wc->mod.fxo.wasringing[card]) {
- wc->mod.fxo.wasringing[card] = 1;
- zt_hooksig(&wc->chans[card], ZT_RXSIG_RING);
- if (debug)
- printk("RING on %d/%d!\n", wc->span.spanno, card + 1);
- }
- wc->mod.fxo.ringdebounce[card] = ZT_CHUNKSIZE * 64;
- }
- } else {
- wc->mod.fxo.ringdebounce[card] -= ZT_CHUNKSIZE;
- if (wc->mod.fxo.ringdebounce[card] <= 0) {
- if (wc->mod.fxo.wasringing[card]) {
- wc->mod.fxo.wasringing[card] =0;
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
- if (debug)
- printk("NO RING on %d/%d!\n", wc->span.spanno, card + 1);
- }
- wc->mod.fxo.ringdebounce[card] = 0;
- }
-
- }
- }
-#endif
- b = wctdm_getreg(wc, card, 29);
-#if 0
- {
- static int count = 0;
- if (!(count++ % 100)) {
- printk("Card %d: Voltage: %d Debounce %d\n", card + 1,
- b, wc->mod.fxo.battdebounce[card]);
- }
- }
-#endif
- if (abs(b) < battthresh) {
- wc->mod.fxo.nobatttimer[card]++;
-#if 0
- if (wc->mod.fxo.battery[card])
- printk("Battery loss: %d (%d debounce)\n", b, wc->mod.fxo.battdebounce[card]);
-#endif
- if (wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) {
- if (debug)
- printk("NO BATTERY on %d/%d!\n", wc->span.spanno, card + 1);
- wc->mod.fxo.battery[card] = 0;
-#ifdef JAPAN
- if ((!wc->ohdebounce) && wc->offhook) {
- zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
- if (debug)
- printk("Signalled On Hook\n");
-#ifdef ZERO_BATT_RING
- wc->onhook++;
-#endif
- }
-#else
- zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
-#endif
- wc->mod.fxo.battdebounce[card] = battdebounce;
- } else if (!wc->mod.fxo.battery[card])
- wc->mod.fxo.battdebounce[card] = battdebounce;
- } else if (abs(b) > battthresh) {
- if (!wc->mod.fxo.battery[card] && !wc->mod.fxo.battdebounce[card]) {
- if (debug)
- printk("BATTERY on %d/%d (%s)!\n", wc->span.spanno, card + 1,
- (b < 0) ? "-" : "+");
-#ifdef ZERO_BATT_RING
- if (wc->onhook) {
- wc->onhook = 0;
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
- if (debug)
- printk("Signalled Off Hook\n");
- }
-#else
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
-#endif
- wc->mod.fxo.battery[card] = 1;
- wc->mod.fxo.nobatttimer[card] = 0;
- wc->mod.fxo.battdebounce[card] = battdebounce;
- } else if (wc->mod.fxo.battery[card])
- wc->mod.fxo.battdebounce[card] = battdebounce;
-
- if (wc->mod.fxo.lastpol[card] >= 0) {
- if (b < 0) {
- wc->mod.fxo.lastpol[card] = -1;
- wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE;
- }
- }
- if (wc->mod.fxo.lastpol[card] <= 0) {
- if (b > 0) {
- wc->mod.fxo.lastpol[card] = 1;
- wc->mod.fxo.polaritydebounce[card] = POLARITY_DEBOUNCE;
- }
- }
- } else {
- /* It's something else... */
- wc->mod.fxo.battdebounce[card] = battdebounce;
- }
- if (wc->mod.fxo.battdebounce[card])
- wc->mod.fxo.battdebounce[card]--;
- if (wc->mod.fxo.polaritydebounce[card]) {
- wc->mod.fxo.polaritydebounce[card]--;
- if (wc->mod.fxo.polaritydebounce[card] < 1) {
- if (wc->mod.fxo.lastpol[card] != wc->mod.fxo.polarity[card]) {
- if (debug)
- printk("%lu Polarity reversed (%d -> %d)\n", jiffies,
- wc->mod.fxo.polarity[card],
- wc->mod.fxo.lastpol[card]);
- if (wc->mod.fxo.polarity[card])
- zt_qevent_lock(&wc->chans[card], ZT_EVENT_POLARITY);
- wc->mod.fxo.polarity[card] = wc->mod.fxo.lastpol[card];
- }
- }
- }
-}
-
-static inline void wctdm_proslic_check_hook(struct wctdm *wc, int card)
-{
- char res;
- int hook;
-
- /* For some reason we have to debounce the
- hook detector. */
-
- res = wctdm_getreg(wc, card, 68);
- hook = (res & 1);
- if (hook != wc->mod.fxs.lastrxhook[card]) {
- /* Reset the debounce (must be multiple of 4ms) */
- wc->mod.fxs.debounce[card] = 8 * (4 * 8);
-#if 0
- printk("Resetting debounce card %d hook %d, %d\n", card, hook, wc->mod.fxs.debounce[card]);
-#endif
- } else {
- if (wc->mod.fxs.debounce[card] > 0) {
- wc->mod.fxs.debounce[card]-= 4 * ZT_CHUNKSIZE;
-#if 0
- printk("Sustaining hook %d, %d\n", hook, wc->mod.fxs.debounce[card]);
-#endif
- if (!wc->mod.fxs.debounce[card]) {
-#if 0
- printk("Counted down debounce, newhook: %d...\n", hook);
-#endif
- wc->mod.fxs.debouncehook[card] = hook;
- }
- if (!wc->mod.fxs.oldrxhook[card] && wc->mod.fxs.debouncehook[card]) {
- /* Off hook */
-#if 1
- if (debug)
-#endif
- printk("wctdm: Card %d Going off hook\n", card);
- zt_hooksig(&wc->chans[card], ZT_RXSIG_OFFHOOK);
- if (robust)
- wctdm_init_proslic(wc, card, 1, 0, 1);
- wc->mod.fxs.oldrxhook[card] = 1;
-
- } else if (wc->mod.fxs.oldrxhook[card] && !wc->mod.fxs.debouncehook[card]) {
- /* On hook */
-#if 1
- if (debug)
-#endif
- printk("wctdm: Card %d Going on hook\n", card);
- zt_hooksig(&wc->chans[card], ZT_RXSIG_ONHOOK);
- wc->mod.fxs.oldrxhook[card] = 0;
- }
- }
- }
- wc->mod.fxs.lastrxhook[card] = hook;
-
-
-}
static int wctdm_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
{
diff --git a/ztd-loc.c b/ztd-loc.c
new file mode 100755
index 0000000..da9ab6c
--- /dev/null
+++ b/ztd-loc.c
@@ -0,0 +1,272 @@
+/*
+ * Dynamic Span Interface for Zaptel (Local Interface)
+ *
+ * Written by Nicolas Bougues <nbougues@axialys.net>
+ *
+ * Copyright (C) 2004, Axialys Interactive
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Note : a zaptel source must exist prior to loading this driver
+ *
+ * Address syntax :
+ * <key>:<id>[:<monitor id>]
+ *
+ * As of now, keys and ids are single digit only
+ *
+ * One span may have up to one "normal" peer, and one "monitor" peer
+ *
+ * Example :
+ *
+ * Say you have two spans cross connected, a thrid one monitoring RX on the
+ * first one, a fourth one monitoring RX on the second one
+ *
+ * 1:0
+ * 1:1
+ * 1:2:0
+ * 1:3:1
+ *
+ * Contrary to TDMoE, no frame loss can occur.
+ *
+ * See bug #2021 for more details
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#ifdef STANDALONE_ZAPATA
+#include "zaptel.h"
+#else
+#include <linux/zaptel.h>
+#endif
+
+static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
+
+static struct ztdlocal {
+ unsigned short key;
+ unsigned short id;
+ struct ztdlocal *monitor_rx_peer; /* Indicates the peer span that monitors this span */
+ struct ztdlocal *peer; /* Indicates the rw peer for this span */
+ struct zt_span *span;
+ struct ztdlocal *next;
+} *zdevs = NULL;
+
+/*static*/ int ztdlocal_transmit(void *pvt, unsigned char *msg, int msglen)
+{
+ struct ztdlocal *z;
+ unsigned long flags;
+
+ spin_lock_irqsave(&zlock, flags);
+ z = pvt;
+ if (z->peer && z->peer->span) {
+ zt_dynamic_receive(z->peer->span, msg, msglen);
+ }
+ if (z->monitor_rx_peer && z->monitor_rx_peer->span) {
+ zt_dynamic_receive(z->monitor_rx_peer->span, msg, msglen);
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ return 0;
+}
+
+static int digit2int(char d)
+{
+ switch(d) {
+ case 'F':
+ case 'E':
+ case 'D':
+ case 'C':
+ case 'B':
+ case 'A':
+ return d - 'A' + 10;
+ case 'f':
+ case 'e':
+ case 'd':
+ case 'c':
+ case 'b':
+ case 'a':
+ return d - 'a' + 10;
+ case '9':
+ case '8':
+ case '7':
+ case '6':
+ case '5':
+ case '4':
+ case '3':
+ case '2':
+ case '1':
+ case '0':
+ return d - '0';
+ }
+ return -1;
+}
+
+/*static*/ void ztdlocal_destroy(void *pvt)
+{
+ struct ztdlocal *z = pvt;
+ unsigned long flags;
+ struct ztdlocal *prev=NULL, *cur;
+
+ spin_lock_irqsave(&zlock, flags);
+ cur = zdevs;
+ while(cur) {
+ if (cur->peer == z)
+ cur->peer = NULL;
+ if (cur->monitor_rx_peer == z)
+ cur->monitor_rx_peer = NULL;
+ cur = cur->next;
+ }
+ cur = zdevs;
+ while(cur) {
+ if (cur == z) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ zdevs = cur->next;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ spin_unlock_irqrestore(&zlock, flags);
+ if (cur == z) {
+ printk("TDMoL: Removed interface for %s, key %d id %d\n", z->span->name, z->key, z->id);
+#ifndef LINUX26
+ MOD_DEC_USE_COUNT;
+#endif
+ kfree(z);
+ }
+}
+
+/*static*/ void *ztdlocal_create(struct zt_span *span, char *address)
+{
+ struct ztdlocal *z, *l;
+ unsigned long flags;
+ int key = -1, id = -1, monitor = -1;
+
+ if (strlen(address) >= 3) {
+ if (address[1] != ':')
+ goto INVALID_ADDRESS;
+ key = digit2int(address[0]);
+ id = digit2int(address[2]);
+ }
+ if (strlen (address) == 5) {
+ if (address[3] != ':')
+ goto INVALID_ADDRESS;
+ monitor = digit2int(address[4]);
+ }
+
+ if (key == -1 || id == -1)
+ goto INVALID_ADDRESS;
+
+ z = kmalloc(sizeof(struct ztdlocal), GFP_KERNEL);
+ if (z) {
+ /* Zero it out */
+ memset(z, 0, sizeof(struct ztdlocal));
+
+ z->key = key;
+ z->id = id;
+ z->span = span;
+
+ spin_lock_irqsave(&zlock, flags);
+ /* Add this peer to any existing spans with same key
+ And add them as peers to this one */
+ for (l = zdevs; l; l = l->next)
+ if (l->key == z->key) {
+ if (l->id == z->id) {
+ printk ("TDMoL: Duplicate id (%d) for key %d\n", z->id, z->key);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ }
+ if (monitor == -1) {
+ if (l->peer) {
+ printk ("TDMoL: Span with key %d and id %d already has a R/W peer\n", z->key, z->id);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ } else {
+ l->peer = z;
+ z->peer = l;
+ }
+ }
+ if (monitor == l->id) {
+ if (l->monitor_rx_peer) {
+ printk ("TDMoL: Span with key %d and id %d already has a monitoring peer\n", z->key, z->id);
+ goto CLEAR_AND_DEL_FROM_PEERS;
+ } else {
+ l->monitor_rx_peer = z;
+ }
+ }
+ }
+ z->next = zdevs;
+ zdevs = z;
+ spin_unlock_irqrestore(&zlock, flags);
+#ifndef LINUX26
+ MOD_INC_USE_COUNT;
+#endif
+
+ printk("TDMoL: Added new interface for %s, key %d id %d\n", span->name, z->key, z->id);
+ }
+ return z;
+
+CLEAR_AND_DEL_FROM_PEERS:
+ for (l = zdevs; l; l = l->next) {
+ if (l->peer == z)
+ l->peer = NULL;
+ if (l->monitor_rx_peer == z)
+ l->monitor_rx_peer = NULL;
+ }
+ kfree (z);
+ return NULL;
+
+INVALID_ADDRESS:
+ printk ("TDMoL: Invalid address %s\n", address);
+ return NULL;
+}
+
+static struct zt_dynamic_driver ztd_local = {
+ "loc",
+ "Local",
+ ztdlocal_create,
+ ztdlocal_destroy,
+ ztdlocal_transmit
+};
+
+/*static*/ int __init ztdlocal_init(void)
+{
+ zt_dynamic_register(&ztd_local);
+ return 0;
+}
+
+/*static*/ void __exit ztdlocal_exit(void)
+{
+ zt_dynamic_unregister(&ztd_local);
+}
+
+module_init(ztdlocal_init);
+module_exit(ztdlocal_exit);
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif