diff options
-rw-r--r-- | drivers/dahdi/dahdi-base.c | 161 |
1 files changed, 103 insertions, 58 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 608da1b..a03f4a9 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -476,6 +476,33 @@ static LIST_HEAD(span_list); static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS]; +static unsigned long +__for_each_channel(unsigned long (*func)(struct dahdi_chan *chan, + unsigned long data), + unsigned long data) +{ + int res; + struct dahdi_span *s; + struct pseudo_chan *pseudo; + + list_for_each_entry(s, &span_list, node) { + unsigned long x; + for (x = 0; x < s->channels; x++) { + struct dahdi_chan *const chan = s->chans[x]; + res = func(chan, data); + if (res) + return res; + } + } + + list_for_each_entry(pseudo, &pseudo_chans, node) { + res = func(&pseudo->chan, data); + if (res) + return res; + } + return 0; +} + static struct dahdi_chan *chan_from_num(unsigned int channo) { struct dahdi_span *s; @@ -1046,9 +1073,21 @@ static int dahdi_get_conf_alias(int x) return a; } +static unsigned long _chan_in_conf(struct dahdi_chan *chan, unsigned long x) +{ + const int confmode = chan->confmode & DAHDI_CONF_MODE_MASK; + return (chan && (chan->confna == x) && + (confmode == DAHDI_CONF_CONF || + confmode == DAHDI_CONF_CONFANN || + confmode == DAHDI_CONF_CONFMON || + confmode == DAHDI_CONF_CONFANNMON || + confmode == DAHDI_CONF_REALANDPSEUDO)) ? 1 : 0; +} + static void dahdi_check_conf(int x) { - int y; + unsigned long res; + unsigned long flags; /* return if no valid conf number */ if (x <= 0) @@ -1058,21 +1097,11 @@ static void dahdi_check_conf(int x) if (!confalias[x]) return; - for (y = 0; y < maxchans; y++) { - struct dahdi_chan *const chan = chan_from_num(y); - int confmode; - if (!chan) - continue; - confmode = chan->confmode & DAHDI_CONF_MODE_MASK; - if ((chan->confna == x) && - (confmode == DAHDI_CONF_CONF || - confmode == DAHDI_CONF_CONFANN || - confmode == DAHDI_CONF_CONFMON || - confmode == DAHDI_CONF_CONFANNMON || - confmode == DAHDI_CONF_REALANDPSEUDO)) { - return; - } - } + spin_lock_irqsave(&chan_lock, flags); + res = __for_each_channel(_chan_in_conf, x); + spin_unlock_irqrestore(&chan_lock, flags); + if (res) + return; /* If we get here, nobody is in the conference anymore. Clear it out both forward and reverse */ @@ -2100,10 +2129,41 @@ static bool is_monitor_mode(int confmode) } } +static unsigned long _chan_cleanup(struct dahdi_chan *pos, unsigned long data) +{ + unsigned long flags; + struct dahdi_chan *const chan = (struct dahdi_chan *)data; + + ++maxchans; + + /* Remove anyone pointing to us as master + and make them their own thing */ + if (pos->master == chan) + pos->master = pos; + + if (((pos->confna == chan->channo) && + is_monitor_mode(pos->confmode)) || + (pos->dacs_chan == chan)) { + /* Take them out of conference with us */ + /* release conference resource if any */ + if (pos->confna) + dahdi_check_conf(pos->confna); + + dahdi_disable_dacs(pos); + spin_lock_irqsave(&pos->lock, flags); + pos->confna = 0; + pos->_confn = 0; + pos->confmode = 0; + pos->conf_chan = NULL; + pos->dacs_chan = NULL; + spin_unlock_irqrestore(&pos->lock, flags); + } + + return 0; +} static void dahdi_chan_unreg(struct dahdi_chan *chan) { - int x; unsigned long flags; might_sleep(); @@ -2137,36 +2197,10 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan) module_printk(KERN_NOTICE, "HUH??? PPP still attached??\n"); } #endif - maxchans = 0; - for (x = 1; x < DAHDI_MAX_CHANNELS; x++) { - struct dahdi_chan *const pos = chan_from_num(x); - if (!pos) - continue; - maxchans = x + 1; - /* Remove anyone pointing to us as master - and make them their own thing */ - if (pos->master == chan) - pos->master = pos; - - if ((pos->confna == chan->channo) && - (is_monitor_mode(pos->confmode) || - ((pos->confmode & DAHDI_CONF_MODE_MASK) == - DAHDI_CONF_DIGITALMON))) { - /* Take them out of conference with us */ - /* release conference resource if any */ - if (pos->confna) - dahdi_check_conf(pos->confna); - - dahdi_disable_dacs(pos); - pos->confna = 0; - pos->_confn = 0; - pos->confmode = 0; - pos->dacs_chan = NULL; - pos->conf_chan = NULL; - } - } - chan->channo = -1; + __for_each_channel(_chan_cleanup, (unsigned long)chan); spin_unlock_irqrestore(&chan_lock, flags); + + chan->channo = -1; } static ssize_t dahdi_chan_read(struct file *file, char __user *usrbuf, @@ -5127,11 +5161,11 @@ static int dahdi_ioctl_setconf(struct file *file, unsigned long data) static int dahdi_ioctl_confdiag(struct file *file, unsigned long data) { struct dahdi_chan *chan; + unsigned long flags; int rv; int i; int j; int c; - int k; chan = chan_from_file(file); if (!chan) @@ -5144,23 +5178,34 @@ static int dahdi_ioctl_confdiag(struct file *file, unsigned long data) /* loop thru the interesting ones */ for (i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++) { + struct dahdi_span *s; + struct pseudo_chan *pseudo; c = 0; - for (k = 1; k < DAHDI_MAX_CHANNELS; k++) { - struct dahdi_chan *const pos = chan_from_num(k); - /* skip if no pointer */ - if (!pos) - continue; + spin_lock_irqsave(&chan_lock, flags); + list_for_each_entry(s, &span_list, node) { + int k; + for (k = 0; k < s->channels; k++) { + chan = s->chans[k]; + if (chan->confna != i) + continue; + if (!c) + module_printk(KERN_NOTICE, "Conf #%d:\n", i); + c = 1; + module_printk(KERN_NOTICE, "chan %d, mode %x\n", + chan->channo, chan->confmode); + } + } + list_for_each_entry(pseudo, &pseudo_chans, node) { /* skip if not in this conf */ - if (pos->confna != i) + if (pseudo->chan.confna != i) continue; - if (!c) { - module_printk(KERN_NOTICE, - "Conf #%d:\n", i); - } + if (!c) + module_printk(KERN_NOTICE, "Conf #%d:\n", i); c = 1; module_printk(KERN_NOTICE, "chan %d, mode %x\n", - k, pos->confmode); + pseudo->chan.channo, pseudo->chan.confmode); } + spin_unlock_irqrestore(&chan_lock, flags); rv = 0; if (c) module_printk(KERN_NOTICE, "\n"); |