summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dahdi/dahdi-base.c354
-rw-r--r--drivers/dahdi/dahdi-sysfs.c240
-rw-r--r--drivers/dahdi/dahdi.h24
-rw-r--r--drivers/dahdi/wcte12xp/base.c2
-rw-r--r--drivers/dahdi/xpp/xbus-core.c2
-rw-r--r--include/dahdi/kernel.h16
6 files changed, 540 insertions, 98 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index c9089f0..6886195 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -507,17 +507,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;
@@ -1745,7 +1740,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();
@@ -1759,12 +1759,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);
}
@@ -2159,7 +2164,10 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
chan->file->private_data = NULL;
}
+ spin_lock_irqsave(&chan->lock, flags);
release_echocan(chan->ec_factory);
+ chan->ec_factory = NULL;
+ spin_unlock_irqrestore(&chan->lock, flags);
#ifdef CONFIG_DAHDI_NET
if (dahdi_have_netdev(chan)) {
@@ -3047,8 +3055,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.
*
@@ -3092,6 +3098,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,
@@ -6619,7 +6626,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) {
@@ -6631,89 +6638,224 @@ 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;
+ unsigned int next_channo;
+ unsigned int spanno = 1;
+ unsigned int basechan = 1;
- *spanno = 1;
- *channo = 1;
+ list_for_each_entry(pos, &span_list, 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;
+ }
+
+ set_spanno_and_basechan(span, spanno, basechan);
+ return 0;
+}
+
+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)
+ break;
+ }
+
+ spin_lock_irqsave(&chan_lock, flags);
+ list_add(&span->spans_node, pos->spans_node.prev);
+ 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) {
- bool skip_span;
- loc = &pos->spans_node;
next_channo = _get_next_channo(pos);
- skip_span = (pos->spanno == *spanno) ||
- ((next_channo > 1) &&
- ((*channo + span->channels) > next_channo));
+ if (pos->spanno <= spanno) {
+ if (basechan < next_channo + pos->channels) {
+ /* Requested basechan breaks channel sorting */
+ dev_info(span->parent->dev.parent,
+ "[%d] basechan (%d) is too low for wanted span %d\n",
+ local_spanno(span), basechan, spanno);
+ return -EINVAL;
+ }
+ continue;
+ }
- if (!skip_span)
+ if (next_channo == -1)
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_register_span() - Register a new DAHDI span
+ * __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_init_span - (Re)Initializes a dahdi span.
+ * @span: The span to initialize.
+ *
+ * Reinitializing a device span might be necessary if a span has been changed
+ * (channels added / removed) between when the dahdi_device it is on was first
+ * registered and when the spans are actually assigned.
+ *
+ */
+void dahdi_init_span(struct dahdi_span *span)
+{
+ mutex_lock(&registration_mutex);
+ __dahdi_init_span(span);
+ mutex_unlock(&registration_mutex);
+}
+EXPORT_SYMBOL(dahdi_init_span);
+
+/**
+ * _dahdi_assign_span() - Assign 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
- * will get the lowest available channel numbers.
+ * Assigns a span for usage with DAHDI. All the channel numbers in it will
+ * have their numbering started at basechan.
*
* If prefmaster is set to anything > 0, span will attempt to become the
* master DAHDI span at registration time. If 0: it will only become
* 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_assign_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 (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
+ dev_info(span->parent->dev.parent,
+ "local span %d is already assigned span %d "
+ "with base channel %d\n", local_spanno(span), span->spanno,
+ span->chans[0]->channo);
+ return -EINVAL;
+ }
+
if (span->ops->enable_hw_preechocan ||
span->ops->disable_hw_preechocan) {
if ((NULL == span->ops->enable_hw_preechocan) ||
@@ -6727,24 +6869,20 @@ static int _dahdi_register_span(struct dahdi_span *span, int prefmaster)
span->deflaw = DAHDI_LAW_MULAW;
}
- 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;
+ for (x = 0; x < span->channels; x++)
dahdi_chan_reg(span->chans[x]);
- }
#ifdef CONFIG_PROC_FS
{
@@ -6771,13 +6909,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->assigned)
+ span->ops->assigned(span);
+
__dahdi_find_master_span();
return 0;
@@ -6800,16 +6937,36 @@ cleanup:
return res;
}
+int dahdi_assign_span(struct dahdi_span *span, unsigned int spanno,
+ unsigned int basechan, int prefmaster)
+{
+ int ret;
+ mutex_lock(&registration_mutex);
+ ret = _dahdi_assign_span(span, spanno, basechan, prefmaster);
+ mutex_unlock(&registration_mutex);
+ return ret;
+}
+
+int dahdi_assign_device_spans(struct dahdi_device *ddev)
+{
+ struct dahdi_span *span;
+ mutex_lock(&registration_mutex);
+ list_for_each_entry(span, &ddev->spans, device_node)
+ _dahdi_assign_span(span, 0, 0, 1);
+ mutex_unlock(&registration_mutex);
+ return 0;
+}
+
+static int auto_assign_spans = 1;
static const char *UNKNOWN = "";
/**
- * _dahdi_register_device - Registers the spans of a DAHDI device.
+ * _dahdi_register_device - Registers a DAHDI device and assign its spans.
* @ddev: the DAHDI device
*
- * If pinned_spans is defined add the device to the device list and wait for
+ * If auto_assign_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.
*
@@ -6818,19 +6975,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_assign_spans)
+ return 0;
+
+ list_for_each_entry(s, &ddev->spans, device_node)
+ ret = _dahdi_assign_span(s, 0, 0, 1);
+
return ret;
}
@@ -6857,26 +7023,27 @@ int dahdi_register_device(struct dahdi_device *ddev, struct device *parent)
EXPORT_SYMBOL(dahdi_register_device);
/**
- * _dahdi_unregister_span() - unregister a DAHDI span
+ * _dahdi_unassign_span() - unassign a DAHDI span
* @span: the DAHDI span
*
- * Unregisters a span that has been previously registered with
- * dahdi_register_span().
+ * Unassigns a span that has been previously assigned with
+ * dahdi_assign_span().
*
* Must be called with the registration_mutex held.
*
*/
-static int _dahdi_unregister_span(struct dahdi_span *span)
+static int _dahdi_unassign_span(struct dahdi_span *span)
{
int x;
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;
+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
+ dev_info(span->parent->dev.parent,
+ "local span %d is already unassigned\n",
+ local_spanno(span));
+ return -EINVAL;
}
-
spin_lock_irqsave(&chan_lock, flags);
list_del_init(&span->spans_node);
spin_unlock_irqrestore(&chan_lock, flags);
@@ -6888,9 +7055,10 @@ static int _dahdi_unregister_span(struct dahdi_span *span)
span->ops->shutdown(span);
if (debug & DEBUG_MAIN)
- module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels);
+ module_printk(KERN_NOTICE, "Unassigning 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);
@@ -6920,6 +7088,17 @@ static int _dahdi_unregister_span(struct dahdi_span *span)
return 0;
}
+int dahdi_unassign_span(struct dahdi_span *span)
+{
+ int ret;
+
+ module_printk(KERN_NOTICE, "%s: %s\n", __func__, span->name);
+ mutex_lock(&registration_mutex);
+ ret = _dahdi_unassign_span(span);
+ mutex_unlock(&registration_mutex);
+ return ret;
+}
+
/**
* dahdi_unregister_device() - unregister a DAHDI device
* @span: the DAHDI span
@@ -6931,22 +7110,28 @@ static int _dahdi_unregister_span(struct dahdi_span *span)
void dahdi_unregister_device(struct dahdi_device *ddev)
{
struct dahdi_span *s;
+ struct dahdi_span *next;
WARN_ON(!ddev);
might_sleep();
if (unlikely(!ddev))
return;
mutex_lock(&registration_mutex);
- list_for_each_entry(s, &ddev->spans, device_node)
- _dahdi_unregister_span(s);
+ list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
+ _dahdi_unassign_span(s);
+ list_del_init(&s->device_node);
+ }
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);
@@ -9547,10 +9732,11 @@ MODULE_PARM_DESC(max_pseudo_channels, "Maximum number of pseudo channels.");
module_param(hwec_overrides_swec, int, 0644);
MODULE_PARM_DESC(hwec_overrides_swec, "When true, a hardware echo canceller is used instead of configured SWEC.");
-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_assign_spans, int, 0644);
+MODULE_PARM_DESC(auto_assign_spans,
+ "If 1 spans will automatically have their children span and "
+ "channel numbers assigned by the driver. If 0, user space "
+ "will need to assign them via /sys/bus/dahdi_devices.");
static const struct file_operations dahdi_fops = {
.owner = THIS_MODULE,
diff --git a/drivers/dahdi/dahdi-sysfs.c b/drivers/dahdi/dahdi-sysfs.c
index 4bc1cab..16d19ef 100644
--- a/drivers/dahdi/dahdi-sysfs.c
+++ b/drivers/dahdi/dahdi-sysfs.c
@@ -218,13 +218,20 @@ static BUS_ATTR_READER(field##_show, dev, buf) \
span_attr(name, "%s\n");
span_attr(desc, "%s\n");
span_attr(spantype, "%s\n");
-span_attr(offset, "%d\n");
span_attr(alarms, "0x%x\n");
span_attr(irq, "%d\n");
span_attr(irqmisses, "%d\n");
span_attr(lbo, "%d\n");
span_attr(syncsrc, "%d\n");
+static BUS_ATTR_READER(local_spanno_show, dev, buf)
+{
+ struct dahdi_span *span;
+
+ span = dev_to_span(dev);
+ return sprintf(buf, "%d\n", local_spanno(span));
+}
+
static BUS_ATTR_READER(is_digital_show, dev, buf)
{
struct dahdi_span *span;
@@ -245,7 +252,7 @@ static struct device_attribute span_dev_attrs[] = {
__ATTR_RO(name),
__ATTR_RO(desc),
__ATTR_RO(spantype),
- __ATTR_RO(offset),
+ __ATTR_RO(local_spanno),
__ATTR_RO(alarms),
__ATTR_RO(irq),
__ATTR_RO(irqmisses),
@@ -256,7 +263,6 @@ static struct device_attribute span_dev_attrs[] = {
__ATTR_NULL,
};
-
static struct driver_attribute dahdi_attrs[] = {
__ATTR_NULL,
};
@@ -335,7 +341,6 @@ static void span_release(struct device *dev)
dahdi_dbg(DEVICES, "%s: %s\n", __func__, dev_name(dev));
}
-
int dahdi_register_chardev(struct dahdi_chardev *dev)
{
static const char *DAHDI_STRING = "dahdi!";
@@ -370,10 +375,8 @@ void span_sysfs_remove(struct dahdi_span *span)
span_dbg(DEVICES, span, "\n");
span_device = span->span_device;
- if (!span_device) {
- WARN_ON(!span_device);
+ if (!span_device)
return;
- }
for (x = 0; x < span->channels; x++) {
struct dahdi_chan *chan = span->chans[x];
@@ -396,6 +399,9 @@ void span_sysfs_remove(struct dahdi_span *span)
dev_set_drvdata(span_device, NULL);
span_device->parent = NULL;
put_device(span_device);
+ memset(&span->span_device, 0, sizeof(span->span_device));
+ kfree(span->span_device);
+ span->span_device = NULL;
}
int span_sysfs_create(struct dahdi_span *span)
@@ -404,7 +410,10 @@ int span_sysfs_create(struct dahdi_span *span)
int res = 0;
int x;
- BUG_ON(span->span_device);
+ if (span->span_device) {
+ WARN_ON(1);
+ return -EEXIST;
+ }
span->span_device = kzalloc(sizeof(*span->span_device), GFP_KERNEL);
if (!span->span_device)
@@ -414,8 +423,8 @@ int span_sysfs_create(struct dahdi_span *span)
span_dbg(DEVICES, span, "\n");
span_device->bus = &spans_bus_type;
- span_device->parent = span->parent->dev.parent;
- dev_set_name(span_device, "span-%03d", span->spanno);
+ span_device->parent = &span->parent->dev;
+ dev_set_name(span_device, "span-%d", span->spanno);
dev_set_drvdata(span_device, span);
span_device->release = span_release;
res = device_register(span_device);
@@ -471,8 +480,170 @@ static struct {
unsigned int pseudo:1;
unsigned int sysfs_driver_registered:1;
unsigned int sysfs_spans_bus_type:1;
+ unsigned int dahdi_device_bus_registered:1;
} dummy_dev;
+static inline struct dahdi_device *to_ddev(struct device *dev)
+{
+ return container_of(dev, struct dahdi_device, dev);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t dahdi_device_manufacturer_show(struct device *dev, char *buf)
+#else
+static ssize_t
+dahdi_device_manufacturer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+#endif
+{
+ struct dahdi_device *ddev = to_ddev(dev);
+ return sprintf(buf, "%s\n", ddev->manufacturer);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t dahdi_device_type_show(struct device *dev, char *buf)
+#else
+static ssize_t
+dahdi_device_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+#endif
+{
+ struct dahdi_device *ddev = to_ddev(dev);
+ return sprintf(buf, "%s\n", ddev->devicetype);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t dahdi_device_span_count_show(struct device *dev, char *buf)
+#else
+static ssize_t
+dahdi_device_span_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+#endif
+{
+ struct dahdi_device *ddev = to_ddev(dev);
+ unsigned int count = 0;
+ struct list_head *pos;
+
+ list_for_each(pos, &ddev->spans)
+ ++count;
+
+ return sprintf(buf, "%d\n", count);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t dahdi_device_hardware_id_show(struct device *dev, char *buf)
+#else
+static ssize_t
+dahdi_device_hardware_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+#endif
+{
+ struct dahdi_device *ddev = to_ddev(dev);
+
+ return sprintf(buf, "%s\n",
+ (ddev->hardware_id) ? ddev->hardware_id : "");
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t
+dahdi_device_auto_assign(struct device *dev, const char *buf, size_t count)
+#else
+static ssize_t
+dahdi_device_auto_assign(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+#endif
+{
+ struct dahdi_device *ddev = to_ddev(dev);
+ dahdi_assign_device_spans(ddev);
+ return count;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t
+dahdi_device_assign_span(struct device *dev, const char *buf, size_t count)
+#else
+static ssize_t
+dahdi_device_assign_span(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+#endif
+{
+ int ret;
+ struct dahdi_span *span;
+ unsigned int local_span_number;
+ unsigned int desired_spanno;
+ unsigned int desired_basechanno;
+ struct dahdi_device *const ddev = to_ddev(dev);
+
+ ret = sscanf(buf, "%u:%u:%u", &local_span_number, &desired_spanno,
+ &desired_basechanno);
+ if (ret != 3)
+ return -EINVAL;
+
+ if (desired_spanno && !desired_basechanno) {
+ dev_notice(dev, "Must set span number AND base chan number\n");
+ return -EINVAL;
+ }
+
+ list_for_each_entry(span, &ddev->spans, device_node) {
+ if (local_span_number == local_spanno(span)) {
+ ret = dahdi_assign_span(span, desired_spanno,
+ desired_basechanno, 1);
+ return (ret) ? ret : count;
+ }
+ }
+ dev_notice(dev, "no match for local span number %d\n", local_span_number);
+ return -EINVAL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
+static ssize_t
+dahdi_device_unassign_span(struct device *dev, const char *buf, size_t count)
+#else
+static ssize_t
+dahdi_device_unassign_span(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+#endif
+{
+ int ret;
+ unsigned int local_span_number;
+ struct dahdi_span *span;
+ struct dahdi_device *const ddev = to_ddev(dev);
+
+ ret = sscanf(buf, "%u", &local_span_number);
+ if (ret != 1)
+ return -EINVAL;
+
+ ret = -ENODEV;
+ list_for_each_entry(span, &ddev->spans, device_node) {
+ if (local_span_number == local_spanno(span))
+ ret = dahdi_unassign_span(span);
+ }
+ if (-ENODEV == ret) {
+ if (printk_ratelimit()) {
+ dev_info(dev, "'%d' is an invalid local span number.\n",
+ local_span_number);
+ }
+ return -EINVAL;
+ }
+ return (ret < 0) ? ret : count;
+}
+
+static struct device_attribute dahdi_device_attrs[] = {
+ __ATTR(manufacturer, S_IRUGO, dahdi_device_manufacturer_show, NULL),
+ __ATTR(type, S_IRUGO, dahdi_device_type_show, NULL),
+ __ATTR(span_count, S_IRUGO, dahdi_device_span_count_show, NULL),
+ __ATTR(hardware_id, S_IRUGO, dahdi_device_hardware_id_show, NULL),
+ __ATTR(auto_assign, S_IWUSR, NULL, dahdi_device_auto_assign),
+ __ATTR(assign_span, S_IWUSR, NULL, dahdi_device_assign_span),
+ __ATTR(unassign_span, S_IWUSR, NULL, dahdi_device_unassign_span),
+ __ATTR_NULL,
+};
+
+static struct bus_type dahdi_device_bus = {
+ .name = "dahdi_devices",
+ .dev_attrs = dahdi_device_attrs,
+};
+
void dahdi_sysfs_exit(void)
{
dahdi_dbg(DEVICES, "SYSFS\n");
@@ -512,6 +683,49 @@ void dahdi_sysfs_exit(void)
dummy_dev.sysfs_spans_bus_type = 0;
}
unregister_chrdev(DAHDI_MAJOR, "dahdi");
+
+ if (dummy_dev.dahdi_device_bus_registered) {
+ bus_unregister(&dahdi_device_bus);
+ dummy_dev.dahdi_device_bus_registered = 0;
+ }
+}
+
+static void dahdi_device_release(struct device *dev)
+{
+ struct dahdi_device *ddev = container_of(dev, struct dahdi_device, dev);
+ kfree(ddev);
+}
+
+/**
+ * dahdi_sysfs_add_device - Add the dahdi_device into the sysfs hierarchy.
+ * @ddev: The device to add.
+ * @parent: The physical device that is implementing this device.
+ *
+ * By adding the dahdi_device to the sysfs hierarchy user space can control
+ * how spans are numbered.
+ *
+ */
+int dahdi_sysfs_add_device(struct dahdi_device *ddev, struct device *parent)
+{
+ int ret;
+ struct device *const dev = &ddev->dev;
+
+ dev->parent = parent;
+ dev->bus = &dahdi_device_bus;
+ dev_set_name(dev, "%s:%s", parent->bus->name, dev_name(parent));
+ ret = device_add(dev);
+ return ret;
+}
+
+void dahdi_sysfs_init_device(struct dahdi_device *ddev)
+{
+ device_initialize(&ddev->dev);
+ ddev->dev.release = dahdi_device_release;
+}
+
+void dahdi_sysfs_unregister_device(struct dahdi_device *ddev)
+{
+ device_del(&ddev->dev);
}
int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops)
@@ -519,6 +733,12 @@ int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops)
int res = 0;
void *dev;
+ res = bus_register(&dahdi_device_bus);
+ if (res)
+ return res;
+
+ dummy_dev.dahdi_device_bus_registered = 1;
+
res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops);
if (res) {
module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR);
diff --git a/drivers/dahdi/dahdi.h b/drivers/dahdi/dahdi.h
index 92ddbdc..5baebc1 100644
--- a/drivers/dahdi/dahdi.h
+++ b/drivers/dahdi/dahdi.h
@@ -34,4 +34,28 @@ void span_sysfs_remove(struct dahdi_span *span);
int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops);
void dahdi_sysfs_exit(void);
+void dahdi_sysfs_init_device(struct dahdi_device *ddev);
+int dahdi_sysfs_add_device(struct dahdi_device *ddev, struct device *parent);
+void dahdi_sysfs_unregister_device(struct dahdi_device *ddev);
+
+int dahdi_assign_span(struct dahdi_span *span, unsigned int spanno,
+ unsigned int basechan, int prefmaster);
+int dahdi_unassign_span(struct dahdi_span *span);
+int dahdi_assign_device_spans(struct dahdi_device *ddev);
+
+static inline int get_span(struct dahdi_span *span)
+{
+ return try_module_get(span->ops->owner);
+}
+
+static inline void put_span(struct dahdi_span *span)
+{
+ module_put(span->ops->owner);
+}
+
+static inline int local_spanno(struct dahdi_span *span)
+{
+ return span->offset + 1;
+}
+
#endif /* _DAHDI_H */
diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c
index f6b2a48..bfd6190 100644
--- a/drivers/dahdi/wcte12xp/base.c
+++ b/drivers/dahdi/wcte12xp/base.c
@@ -1874,7 +1874,7 @@ static int t1_software_init(struct t1 *wc, enum linemode type)
return res;
}
- return 0;
+ return res;
}
#if 0
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
index 39fe67c..7fe0493 100644
--- a/drivers/dahdi/xpp/xbus-core.c
+++ b/drivers/dahdi/xpp/xbus-core.c
@@ -904,6 +904,7 @@ static int xbus_register_dahdi_device(xbus_t *xbus)
* So let's also export it via the newfangled "location" field.
*/
xbus->ddev->location = xbus->connector;
+ xbus->ddev->hardware_id = xbus->label;
/*
* Prepare the span list
@@ -943,6 +944,7 @@ static void xbus_unregister_dahdi_device(xbus_t *xbus)
kfree(xbus->ddev->devicetype);
xbus->ddev->devicetype = NULL;
xbus->ddev->location = NULL;
+ xbus->ddev->hardware_id = NULL;
dahdi_free_device(xbus->ddev);
xbus->ddev = NULL;
for(i = 0; i < MAX_XPDS; i++) {
diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
index 12e8ff2..bb32126 100644
--- a/include/dahdi/kernel.h
+++ b/include/dahdi/kernel.h
@@ -896,16 +896,21 @@ struct dahdi_span_ops {
/**
* dahdi_device - Represents a device that can contain one or more spans.
*
- * @spans: List of child spans.
+ * @spans: List of child spans.
* @manufacturer: Device manufacturer.
- * @location: The location of this device
- * @devicetype: What type of device this is.
+ * @location: The location of this device. This should not change if
+ * the device is replaced (e.g: in the same PCI slot)
+ * @hardware_id: The hardware_id of this device (NULL for devices without
+ * a hardware_id). This should not change if the device is
+ * relocated to a different location (e.g: different PCI slot)
+ * @devicetype: What type of device this is.
*
*/
struct dahdi_device {
struct list_head spans;
const char *manufacturer;
const char *location;
+ const char *hardware_id;
const char *devicetype;
struct device dev;
};
@@ -1164,6 +1169,7 @@ struct dahdi_device *dahdi_create_device(void);
int dahdi_register_device(struct dahdi_device *ddev, struct device *parent);
void dahdi_unregister_device(struct dahdi_device *ddev);
void dahdi_free_device(struct dahdi_device *ddev);
+void dahdi_init_span(struct dahdi_span *span);
/*! Allocate / free memory for a transcoder */
struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans);
@@ -1451,6 +1457,10 @@ typedef u32 __bitwise pm_message_t;
#endif /* 2.6.26 */
#endif /* 2.6.31 */
+#ifndef CONFIG_TRACING
+#define trace_printk printk
+#endif
+
#ifndef DEFINE_SPINLOCK
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#endif