diff options
author | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-12-04 04:19:41 +0000 |
---|---|---|
committer | markster <markster@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2004-12-04 04:19:41 +0000 |
commit | 842c921a5eb0928f6bdd31fcfb610849c2048c1a (patch) | |
tree | d2e3c36b3669df220cb0484348ff2aca885ba450 | |
parent | 1d4fed5eca5c005d697921844cae53db01910d37 (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-x | Makefile | 6 | ||||
-rwxr-xr-x | wctdm.c | 447 | ||||
-rwxr-xr-x | ztd-loc.c | 272 |
3 files changed, 498 insertions, 227 deletions
@@ -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 @@ -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 |