summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dahdi/dahdi-base.c99
1 files changed, 79 insertions, 20 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 1ff5089..8c32f7c 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -6442,17 +6442,89 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif
+/**
+ * _get_next_channo - Return the next taken channel number from the span list.
+ * @span: The span with which to start the search.
+ *
+ * Returns -1 if there aren't any channels on span or any of the following
+ * spans, otherwise, returns the channel number of the first channel.
+ *
+ * Must be callled with registration_mutex held.
+ *
+ */
+static int _get_next_channo(const struct dahdi_span *span)
+{
+ const struct list_head *pos = &span->node;
+ while (pos != &span_list) {
+ span = list_entry(pos, struct dahdi_span, node);
+ if (span->channels)
+ return span->chans[0]->channo;
+ pos = pos->next;
+ }
+ return -1;
+}
+
+/**
+ * _find_spanno_and_channo - Find the next available span and channel number.
+ *
+ * Must be called with registration_mutex held.
+ *
+ */
+static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span,
+ int *spanno, int *channo,
+ struct list_head *loc)
+{
+ struct dahdi_span *pos;
+ int next_channo;
+
+ *spanno = 1;
+ *channo = 1;
+
+ list_for_each_entry(pos, &span_list, node) {
+ bool skip_span;
+
+ loc = &pos->node;
+ next_channo = _get_next_channo(pos);
+
+ skip_span = (pos->spanno == *spanno) ||
+ ((next_channo > 1) &&
+ ((*channo + span->channels) > next_channo));
+
+ if (!skip_span)
+ break;
+
+ *spanno = pos->spanno + 1;
+ if (pos->channels)
+ *channo = next_channo + pos->channels;
+
+ }
+
+ return loc;
+}
+
+/**
+ * _dahdi_register - Register the span.
+ *
+ * NOTE: Must be called with the registration_mutex held.
+ *
+ */
static int _dahdi_register(struct dahdi_span *span, int prefmaster)
{
unsigned int spanno;
unsigned int x;
struct list_head *loc = &span_list;
unsigned long flags;
- unsigned int next_channo = 1;
+ unsigned int channo;
if (!span || !span->ops || !span->ops->owner)
return -EINVAL;
+ if (!list_empty(&pseudo_chans)) {
+ module_printk(KERN_ERR, "Cannot register spans while psuedo "
+ "chans are open.\n");
+ return -EINVAL;
+ }
+
if (!span->deflaw) {
module_printk(KERN_NOTICE, "Span %s didn't specify default law. "
"Assuming mulaw, please fix driver!\n", span->name);
@@ -6462,32 +6534,16 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
spin_lock_init(&span->lock);
- spanno = 1;
-
/* Look through the span list to find the first available span number.
* The spans are kept on this list in sorted order. We'll also save
* off the next available channel number to use. */
- if (!list_empty(&span_list)) {
- struct dahdi_span *pos;
- list_for_each_entry(pos, &span_list, node) {
- loc = &pos->node;
- if (pos->spanno == spanno) {
- ++spanno;
- if (pos->channels) {
- next_channo = pos->chans[0]->channo +
- pos->channels;
- }
- continue;
- }
- break;
- }
- }
+ loc = _find_spanno_and_channo(span, &spanno, &channo, loc);
span->spanno = spanno;
for (x = 0; x < span->channels; x++) {
span->chans[x]->span = span;
- span->chans[x]->channo = next_channo + x;
+ span->chans[x]->channo = channo + x;
dahdi_chan_reg(span->chans[x]);
}
@@ -6517,7 +6573,10 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
}
spin_lock_irqsave(&chan_lock, flags);
- list_add(&span->node, loc);
+ if (loc == &span_list)
+ list_add_tail(&span->node, &span_list);
+ else
+ list_add(&span->node, loc);
spin_unlock_irqrestore(&chan_lock, flags);
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
__dahdi_find_master_span();