summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dahdi/dahdi-base.c161
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");