diff options
author | Shaun Ruffell <sruffell@digium.com> | 2011-01-03 18:28:06 +0000 |
---|---|---|
committer | Shaun Ruffell <sruffell@digium.com> | 2011-01-03 18:28:06 +0000 |
commit | 889ab7e2ab312aeeb481c460504314b1a95769d0 (patch) | |
tree | 206e993d9eac512b95ad793a36cceb9e104f8038 /drivers | |
parent | 31effc77bf36289ea97159ceba6d2e1d47aeb571 (diff) |
dahdi: Drop 'chans' reference in chan_from_num.
Part of getting rid of global chans array. We need to search the list
of spans and the list of pseudo channels. While this is slower than a
direct index into a 'chans' array, the places where this function is
called are not in the 'hot' path but instead part of channel
configuration and conferencing setup.
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Kinsey Moore <kmoore@digium.com>
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9607 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dahdi/dahdi-base.c | 49 |
1 files changed, 47 insertions, 2 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 50116fb..608da1b 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -476,9 +476,54 @@ static LIST_HEAD(span_list); static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS]; -static inline struct dahdi_chan *chan_from_num(unsigned int channo) +static struct dahdi_chan *chan_from_num(unsigned int channo) { - return valid_channo(channo) ? chans[channo] : NULL; + struct dahdi_span *s; + struct pseudo_chan *pseudo; + + if (!unlikely(valid_channo(channo))) + return NULL; + + mutex_lock(®istration_mutex); + + /* When searching for the channel amongst the spans, we can use the + * fact that channels on a span must be numbered consecutively to skip + * checking each individual channel. */ + list_for_each_entry(s, &span_list, node) { + unsigned int basechan; + struct dahdi_chan *chan; + + if (unlikely(!s->channels)) + continue; + + basechan = s->chans[0]->channo; + if (channo >= (basechan + s->channels)) + continue; + + if (unlikely(channo < basechan)) { + /* Looks like they are asking for a channel that has + * already been removed. */ + mutex_unlock(®istration_mutex); + return NULL; + } + + chan = s->chans[channo - basechan]; + WARN_ON(chan->channo != channo); + mutex_unlock(®istration_mutex); + return chan; + } + + /* If we didn't find the channel on the list of real channels, then + * it's most likely a pseudo channel. */ + list_for_each_entry(pseudo, &pseudo_chans, node) { + if (pseudo->chan.channo == channo) { + mutex_unlock(®istration_mutex); + return &pseudo->chan; + } + } + + mutex_unlock(®istration_mutex); + return NULL; } static inline struct dahdi_chan *chan_from_file(struct file *file) |