summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c297
1 files changed, 218 insertions, 79 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index afd8797..a70deb3 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -531,17 +531,12 @@ static struct dahdi_span *span_find_and_get(int spanno)
mutex_lock(&registration_mutex);
found = _find_span(spanno);
- if (found && !try_module_get(found->ops->owner))
+ if (found && !get_span(found))
found = NULL;
mutex_unlock(&registration_mutex);
return found;
}
-static void put_span(struct dahdi_span *span)
-{
- module_put(span->ops->owner);
-}
-
static unsigned int span_count(void)
{
unsigned int count = 0;
@@ -1663,7 +1658,12 @@ static void dahdi_set_law(struct dahdi_chan *chan, int law)
}
}
-static void dahdi_chan_reg(struct dahdi_chan *chan)
+/**
+ * __dahdi_init_chan - Initialize the channel data structures.
+ * @chan: The channel to initialize
+ *
+ */
+static void __dahdi_init_chan(struct dahdi_chan *chan)
{
might_sleep();
@@ -1677,12 +1677,17 @@ static void dahdi_chan_reg(struct dahdi_chan *chan)
chan->writechunk = chan->swritechunk;
chan->rxgain = NULL;
chan->txgain = NULL;
- dahdi_set_law(chan, 0);
- dahdi_set_law(chan, DAHDI_LAW_DEFAULT);
close_channel(chan);
+}
- /* set this AFTER running close_channel() so that
- HDLC channels wont cause hangage */
+/**
+ * dahdi_chan_reg - Mark the channel registered.
+ *
+ * This must be called after close channel during registration, normally
+ * covered by the call to __dahdi_init_chan, to avoid "HDLC hangage"
+ */
+static inline void dahdi_chan_reg(struct dahdi_chan *chan)
+{
set_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags);
}
@@ -2922,8 +2927,6 @@ static int can_open_timer(void)
static unsigned int max_pseudo_channels = 512;
static unsigned int num_pseudo_channels;
-static int pinned_spans = 1;
-
/**
* dahdi_alloc_pseudo() - Returns a new pseudo channel.
*
@@ -2969,6 +2972,7 @@ static struct dahdi_chan *dahdi_alloc_pseudo(struct file *file)
pseudo->chan.channo = channo;
pseudo->chan.chanpos = channo - FIRST_PSEUDO_CHANNEL + 1;
+ __dahdi_init_chan(&pseudo->chan);
dahdi_chan_reg(&pseudo->chan);
snprintf(pseudo->chan.name, sizeof(pseudo->chan.name)-1,
@@ -6416,7 +6420,7 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd,
* Must be callled with registration_mutex held.
*
*/
-static int _get_next_channo(const struct dahdi_span *span)
+static unsigned int _get_next_channo(const struct dahdi_span *span)
{
const struct list_head *pos = &span->spans_node;
while (pos != &span_list) {
@@ -6428,64 +6432,173 @@ static int _get_next_channo(const struct dahdi_span *span)
return -1;
}
+static void
+set_spanno_and_basechan(struct dahdi_span *span, u32 spanno, u32 basechan)
+{
+ int i;
+ span->spanno = spanno;
+ for (i = 0; i < span->channels; ++i)
+ span->chans[i]->channo = basechan + i;
+}
+
/**
- * _find_spanno_and_channo - Find the next available span and channel number.
+ * _assign_spanno_and_basechan - Assign next available span and channel numbers.
+ *
+ * This function will set span->spanno and channo for all the member channels.
+ * It will assign the first available location.
*
* 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)
+static int _assign_spanno_and_basechan(struct dahdi_span *span)
{
struct dahdi_span *pos;
- int next_channo;
-
- *spanno = 1;
- *channo = 1;
+ unsigned int next_channo;
+ unsigned int spanno = 1;
+ unsigned int basechan = 1;
list_for_each_entry(pos, &span_list, spans_node) {
- bool skip_span;
- loc = &pos->spans_node;
+ if (pos->spanno <= spanno) {
+ spanno = pos->spanno + 1;
+ basechan = pos->chans[0]->channo + pos->channels;
+ continue;
+ }
+
next_channo = _get_next_channo(pos);
+ if ((basechan + span->channels) >= next_channo)
+ break;
+
+ /* We can't fit here, let's look at the next location. */
+ spanno = pos->spanno + 1;
+ if (pos->channels)
+ basechan = pos->chans[0]->channo + pos->channels;
+ }
- skip_span = (pos->spanno == *spanno) ||
- ((next_channo > 1) &&
- ((*channo + span->channels) > next_channo));
+ set_spanno_and_basechan(span, spanno, basechan);
+ trace_printk("%s: spanno: %d basechan: %d span->spanno: %d\n",
+ dev_name(&span->parent->dev), spanno, basechan,
+ span->spanno);
+ return 0;
+}
- if (!skip_span)
+static inline struct dahdi_span *span_from_node(struct list_head *node)
+{
+ return container_of(node, struct dahdi_span, spans_node);
+}
+
+/*
+ * Call with registration_mutex held. Make sure all the spans are on the list
+ * ordered by span.
+ *
+ */
+static void _dahdi_add_span_to_span_list(struct dahdi_span *span)
+{
+ unsigned long flags;
+ struct dahdi_span *pos;
+
+ if (list_empty(&span_list)) {
+ list_add_tail(&span->spans_node, &span_list);
+ return;
+ }
+
+ list_for_each_entry(pos, &span_list, spans_node) {
+ WARN_ON(0 == pos->spanno);
+ if (pos->spanno <= span->spanno)
+ continue;
+ }
+
+ trace_printk("%s: pos->spanno=%d span->spanno: %d\n",
+ dev_name(&span->parent->dev), pos->spanno, span->spanno);
+
+ spin_lock_irqsave(&chan_lock, flags);
+ list_add_tail(&span->spans_node, &pos->spans_node);
+ spin_unlock_irqrestore(&chan_lock, flags);
+}
+
+/**
+ * _check_spanno_and_basechan - Check if we can fit the new span in the requested location.
+ *
+ * Must be called with registration_mutex held.
+ *
+ */
+static int
+_check_spanno_and_basechan(struct dahdi_span *span, u32 spanno, u32 basechan)
+{
+ struct dahdi_span *pos;
+ unsigned int next_channo;
+
+ list_for_each_entry(pos, &span_list, spans_node) {
+
+ if (pos->spanno <= spanno)
+ continue;
+
+ next_channo = _get_next_channo(pos);
+ if (!next_channo)
break;
- *spanno = pos->spanno + 1;
- if (pos->channels)
- *channo = next_channo + pos->channels;
+ if ((basechan + span->channels) >= next_channo)
+ break;
+ /* Cannot fit the span into the requested location. Abort. */
+ return -EINVAL;
}
- return loc;
+ set_spanno_and_basechan(span, spanno, basechan);
+ return 0;
}
+
struct dahdi_device *dahdi_create_device(void)
{
struct dahdi_device *ddev;
ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
if (!ddev)
return NULL;
- device_initialize(&ddev->dev);
+ INIT_LIST_HEAD(&ddev->spans);
+ dahdi_sysfs_init_device(ddev);
return ddev;
}
EXPORT_SYMBOL(dahdi_create_device);
void dahdi_free_device(struct dahdi_device *ddev)
{
- kfree(ddev);
+ put_device(&ddev->dev);
}
EXPORT_SYMBOL(dahdi_free_device);
/**
+ * __dahdi_init_span - Setup all the data structures for the span.
+ * @span: The span of interest.
+ *
+ */
+static void __dahdi_init_span(struct dahdi_span *span)
+{
+ int x;
+
+ INIT_LIST_HEAD(&span->spans_node);
+ spin_lock_init(&span->lock);
+ clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
+
+ if (!span->deflaw) {
+ module_printk(KERN_NOTICE, "Span %s didn't specify default "
+ "law. Assuming mulaw, please fix driver!\n",
+ span->name);
+ span->deflaw = DAHDI_LAW_MULAW;
+ }
+
+ for (x = 0; x < span->channels; ++x) {
+ span->chans[x]->span = span;
+ __dahdi_init_chan(span->chans[x]);
+ }
+}
+
+/**
* _dahdi_register_span() - Register a new DAHDI span
* @span: the DAHDI span
+ * @spanno: The span number we would like assigned. If 0, the first
+ * available spanno/basechan will be used.
+ * @basechan: The base channel number we would like. Ignored if spanno is 0.
* @prefmaster: will the new span be preferred as a master?
*
* Registers a span for usage with DAHDI. All the channel numbers in it
@@ -6496,45 +6609,43 @@ EXPORT_SYMBOL(dahdi_free_device);
* master if no other span is currently the master (i.e.: it is the
* first one).
*
- * Must be called with registration_mutex held.
+ * Must be called with registration_mutex held, and the span must have already
+ * been initialized ith the __dahdi_init_span call.
*
*/
-static int _dahdi_register_span(struct dahdi_span *span, int prefmaster)
+static int _dahdi_register_span(struct dahdi_span *span, unsigned int spanno,
+ unsigned int basechan, int prefmaster)
{
- unsigned int spanno;
- unsigned int x;
- struct list_head *loc = &span_list;
- unsigned long flags;
- unsigned int channo;
int res = 0;
+ unsigned int x;
if (!span || !span->ops || !span->ops->owner)
return -EINVAL;
- if (!span->deflaw) {
- module_printk(KERN_NOTICE, "Span %s didn't specify default law. "
- "Assuming mulaw, please fix driver!\n", span->name);
- span->deflaw = DAHDI_LAW_MULAW;
+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
+ dev_info(span->parent->dev.parent,
+ "local span %d is already registered as span %d "
+ "with base channel %d\n", span->offset, span->spanno,
+ span->chans[0]->channo);
+ return -EINVAL;
}
- INIT_LIST_HEAD(&span->spans_node);
- spin_lock_init(&span->lock);
-
/* 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. */
- loc = _find_spanno_and_channo(span, &spanno, &channo, loc);
+ if (0 == spanno)
+ res = _assign_spanno_and_basechan(span);
+ else
+ res = _check_spanno_and_basechan(span, spanno, basechan);
- if (unlikely(channo >= FIRST_PSEUDO_CHANNEL))
- return -EINVAL;
+ if (res)
+ return res;
- span->spanno = spanno;
- for (x = 0; x < span->channels; x++) {
- span->chans[x]->span = span;
- span->chans[x]->channo = channo + x;
+ trace_printk("span->spanno: %d\n", span->spanno);
+
+ for (x = 0; x < span->channels; x++)
dahdi_chan_reg(span->chans[x]);
- }
#ifdef CONFIG_PROC_FS
{
@@ -6561,13 +6672,12 @@ static int _dahdi_register_span(struct dahdi_span *span, int prefmaster)
"%d channels\n", span->spanno, span->name, span->channels);
}
- spin_lock_irqsave(&chan_lock, flags);
- if (loc == &span_list)
- list_add_tail(&span->spans_node, &span_list);
- else
- list_add(&span->spans_node, loc);
- spin_unlock_irqrestore(&chan_lock, flags);
+ _dahdi_add_span_to_span_list(span);
+
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
+ if (span->ops->registered)
+ span->ops->registered(span);
+
__dahdi_find_master_span();
return 0;
@@ -6590,16 +6700,36 @@ cleanup:
return res;
}
+int dahdi_register_span(struct dahdi_span *span, unsigned int spanno,
+ unsigned int basechan, int prefmaster)
+{
+ int ret;
+ mutex_lock(&registration_mutex);
+ ret = _dahdi_register_span(span, spanno, basechan, prefmaster);
+ mutex_unlock(&registration_mutex);
+ return ret;
+}
+
+int dahdi_register_device_spans(struct dahdi_device *ddev)
+{
+ struct dahdi_span *span;
+ mutex_lock(&registration_mutex);
+ list_for_each_entry(span, &ddev->spans, device_node)
+ _dahdi_register_span(span, 0, 0, 1);
+ mutex_unlock(&registration_mutex);
+ return 0;
+}
+
+static int auto_register_spans = 1;
static const char *UNKNOWN = "";
/**
* _dahdi_register_device - Registers the spans of a DAHDI device.
* @ddev: the DAHDI device
*
- * If pinned_spans is defined add the device to the device list and wait for
+ * If auto_register_spans is 0, add the device to the device list and wait for
* userspace to finish registration. Otherwise, go ahead and register the
- * spans in order as was done historically since the beginning of the zaptel
- * days.
+ * spans in order as was done historically.
*
* Must hold registration_mutex when this function is called.
*
@@ -6608,19 +6738,28 @@ static int _dahdi_register_device(struct dahdi_device *ddev,
struct device *parent)
{
struct dahdi_span *s;
- int ret = 0;
+ int ret;
ddev->manufacturer = (ddev->manufacturer) ?: UNKNOWN;
ddev->location = (ddev->location) ?: UNKNOWN;
ddev->devicetype = (ddev->devicetype) ?: UNKNOWN;
- ddev->dev.parent = parent;
-
list_for_each_entry(s, &ddev->spans, device_node) {
s->parent = ddev;
- ret = _dahdi_register_span(s, 1);
+ s->spanno = 0;
+ __dahdi_init_span(s);
}
+ ret = dahdi_sysfs_add_device(ddev, parent);
+ if (ret)
+ return ret;
+
+ if (!auto_register_spans)
+ return 0;
+
+ list_for_each_entry(s, &ddev->spans, device_node)
+ ret = _dahdi_register_span(s, 0, 0, 1);
+
return ret;
}
@@ -6671,11 +6810,6 @@ static int dahdi_unregister_span(struct dahdi_span *span)
struct dahdi_span *new_master, *s;
unsigned long flags;
- if (span != _find_span(span->spanno)) {
- module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name);
- return -1;
- }
-
spin_lock_irqsave(&chan_lock, flags);
list_del_init(&span->spans_node);
spin_unlock_irqrestore(&chan_lock, flags);
@@ -6689,7 +6823,8 @@ static int dahdi_unregister_span(struct dahdi_span *span)
if (debug & DEBUG_MAIN)
module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels);
#ifdef CONFIG_PROC_FS
- remove_proc_entry(span->proc_entry->name, root_proc_entry);
+ if (span->proc_entry)
+ remove_proc_entry(span->proc_entry->name, root_proc_entry);
#endif /* CONFIG_PROC_FS */
span_sysfs_remove(span);
@@ -6740,12 +6875,15 @@ void dahdi_unregister_device(struct dahdi_device *ddev)
dahdi_unregister_span(s);
mutex_unlock(&registration_mutex);
+ dahdi_sysfs_unregister_device(ddev);
+
if (UNKNOWN == ddev->location)
ddev->location = NULL;
if (UNKNOWN == ddev->manufacturer)
ddev->manufacturer = NULL;
if (UNKNOWN == ddev->devicetype)
ddev->devicetype = NULL;
+
}
EXPORT_SYMBOL(dahdi_unregister_device);
@@ -9340,10 +9478,11 @@ module_param(deftaps, int, 0644);
module_param(max_pseudo_channels, int, 0644);
MODULE_PARM_DESC(max_pseudo_channels, "Maximum number of pseudo channels.");
-module_param(pinned_spans, int, 0644);
-MODULE_PARM_DESC(pinned_spans, "If 1, span/channel numbers can be statically "
- "defined. If 0, spans/channels are numbered in first come "
- "first serve order. Default 1");
+module_param(auto_register_spans, int, 0644);
+MODULE_PARM_DESC(auto_register_spans,
+ "If 1 spans will automatically have their children span and "
+ "channel numbers assigned by the driver. If 0, user space "
+ "will need to register them via /sys/bus/dahdi_devices.");
static const struct file_operations dahdi_fops = {
.owner = THIS_MODULE,