dahdi: Expose dahdi devices in sysfs.

This exposes dahdi devices in sysfs and also exposes attributes that
will allow user space to control the registration order in spans. This
facilitates loading drivers out of order yet keeping consistent
span/channel numbering, which in turn will eventually allow the
blacklist for DAHDI drivers to be removed. The default behavior,
controlled with the auto_register module parameter on dahdi is to number
the spans / channels in order like is currently done. So this change
does not introduce any new behavior by default.

 * Writing (anything) to this attribute returns the span to its
   unassigned state
 * Fix dahdi_chan_unreg() echocan refcount
 * Add safeguard against duplicate unassignment to _dahdi_unregister_span()
 * Remove the span from device_node list, only in dahdi_unregister_device()
   and not in dahdi_unregister_span()
 * Free allocated span->span_device in span_sysfs_remove()
   [is it safe?, didn't cause problem so far...]

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Signed-off-by: Oron Peled <oron.peled@xorcom.com>
Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>

dahdi: Add "hardware_id" dahdi_device attribute.

- The "hardware_id" does not change with device location (e.g: when a PCI
  card is moved from one slot to another).
- Not all devices have this attribute. It is legal for it to be NULL (that
  is the default for all low-level drivers that do not set it explicitly).
- When "hardware_id" is NULL, the sysfs attribute value is "\n"

Signed-off-by: Oron Peled <oron.peled@xorcom.com>
Acked-by: Shaun Ruffell <sruffell@digium.com>

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10275 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Shaun Ruffell 2011-10-26 18:59:20 +00:00 committed by Tzafrir Cohen
parent 2794bb4937
commit a6824019fb
6 changed files with 543 additions and 101 deletions

View File

@ -507,17 +507,12 @@ static struct dahdi_span *span_find_and_get(int spanno)
mutex_lock(&registration_mutex); mutex_lock(&registration_mutex);
found = _find_span(spanno); found = _find_span(spanno);
if (found && !try_module_get(found->ops->owner)) if (found && !get_span(found))
found = NULL; found = NULL;
mutex_unlock(&registration_mutex); mutex_unlock(&registration_mutex);
return found; return found;
} }
static void put_span(struct dahdi_span *span)
{
module_put(span->ops->owner);
}
static unsigned int span_count(void) static unsigned int span_count(void)
{ {
unsigned int count = 0; 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(); might_sleep();
@ -1759,12 +1759,17 @@ static void dahdi_chan_reg(struct dahdi_chan *chan)
chan->writechunk = chan->swritechunk; chan->writechunk = chan->swritechunk;
chan->rxgain = NULL; chan->rxgain = NULL;
chan->txgain = NULL; chan->txgain = NULL;
dahdi_set_law(chan, 0);
dahdi_set_law(chan, DAHDI_LAW_DEFAULT);
close_channel(chan); 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); 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; chan->file->private_data = NULL;
} }
spin_lock_irqsave(&chan->lock, flags);
release_echocan(chan->ec_factory); release_echocan(chan->ec_factory);
chan->ec_factory = NULL;
spin_unlock_irqrestore(&chan->lock, flags);
#ifdef CONFIG_DAHDI_NET #ifdef CONFIG_DAHDI_NET
if (dahdi_have_netdev(chan)) { 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 max_pseudo_channels = 512;
static unsigned int num_pseudo_channels; static unsigned int num_pseudo_channels;
static int pinned_spans = 1;
/** /**
* dahdi_alloc_pseudo() - Returns a new pseudo channel. * 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.channo = channo;
pseudo->chan.chanpos = channo - FIRST_PSEUDO_CHANNEL + 1; pseudo->chan.chanpos = channo - FIRST_PSEUDO_CHANNEL + 1;
__dahdi_init_chan(&pseudo->chan);
dahdi_chan_reg(&pseudo->chan); dahdi_chan_reg(&pseudo->chan);
snprintf(pseudo->chan.name, sizeof(pseudo->chan.name)-1, 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. * 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; const struct list_head *pos = &span->spans_node;
while (pos != &span_list) { while (pos != &span_list) {
@ -6631,89 +6638,224 @@ static int _get_next_channo(const struct dahdi_span *span)
return -1; 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. * Must be called with registration_mutex held.
* *
*/ */
static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span, static int _assign_spanno_and_basechan(struct dahdi_span *span)
int *spanno, int *channo,
struct list_head *loc)
{ {
struct dahdi_span *pos; struct dahdi_span *pos;
int next_channo; unsigned int next_channo;
unsigned int spanno = 1;
*spanno = 1; unsigned int basechan = 1;
*channo = 1;
list_for_each_entry(pos, &span_list, spans_node) { 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); next_channo = _get_next_channo(pos);
if ((basechan + span->channels) >= next_channo)
skip_span = (pos->spanno == *spanno) ||
((next_channo > 1) &&
((*channo + span->channels) > next_channo));
if (!skip_span)
break; break;
*spanno = pos->spanno + 1; /* We can't fit here, let's look at the next location. */
spanno = pos->spanno + 1;
if (pos->channels) if (pos->channels)
*channo = next_channo + pos->channels; basechan = pos->chans[0]->channo + pos->channels;
} }
return loc; 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) {
next_channo = _get_next_channo(pos);
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 (next_channo == -1)
break;
if ((basechan + span->channels) < next_channo)
break;
/* Cannot fit the span into the requested location. Abort. */
return -EINVAL;
}
set_spanno_and_basechan(span, spanno, basechan);
return 0;
}
struct dahdi_device *dahdi_create_device(void) struct dahdi_device *dahdi_create_device(void)
{ {
struct dahdi_device *ddev; struct dahdi_device *ddev;
ddev = kzalloc(sizeof(*ddev), GFP_KERNEL); ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
if (!ddev) if (!ddev)
return NULL; return NULL;
device_initialize(&ddev->dev); INIT_LIST_HEAD(&ddev->spans);
dahdi_sysfs_init_device(ddev);
return ddev; return ddev;
} }
EXPORT_SYMBOL(dahdi_create_device); EXPORT_SYMBOL(dahdi_create_device);
void dahdi_free_device(struct dahdi_device *ddev) void dahdi_free_device(struct dahdi_device *ddev)
{ {
kfree(ddev); put_device(&ddev->dev);
} }
EXPORT_SYMBOL(dahdi_free_device); 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 * @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? * @prefmaster: will the new span be preferred as a master?
* *
* Registers a span for usage with DAHDI. All the channel numbers in it * Assigns a span for usage with DAHDI. All the channel numbers in it will
* will get the lowest available channel numbers. * have their numbering started at basechan.
* *
* If prefmaster is set to anything > 0, span will attempt to become the * 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 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 * master if no other span is currently the master (i.e.: it is the
* first one). * 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; int res = 0;
unsigned int x;
if (!span || !span->ops || !span->ops->owner) if (!span || !span->ops || !span->ops->owner)
return -EINVAL; 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 || if (span->ops->enable_hw_preechocan ||
span->ops->disable_hw_preechocan) { span->ops->disable_hw_preechocan) {
if ((NULL == span->ops->enable_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; 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. /* 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 * The spans are kept on this list in sorted order. We'll also save
* off the next available channel number to use. */ * 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)) if (res)
return -EINVAL; return res;
span->spanno = spanno; for (x = 0; x < span->channels; x++)
for (x = 0; x < span->channels; x++) {
span->chans[x]->span = span;
span->chans[x]->channo = channo + x;
dahdi_chan_reg(span->chans[x]); dahdi_chan_reg(span->chans[x]);
}
#ifdef CONFIG_PROC_FS #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); "%d channels\n", span->spanno, span->name, span->channels);
} }
spin_lock_irqsave(&chan_lock, flags); _dahdi_add_span_to_span_list(span);
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);
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
if (span->ops->assigned)
span->ops->assigned(span);
__dahdi_find_master_span(); __dahdi_find_master_span();
return 0; return 0;
@ -6800,16 +6937,36 @@ cleanup:
return res; 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 = ""; 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 * @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 * userspace to finish registration. Otherwise, go ahead and register the
* spans in order as was done historically since the beginning of the zaptel * spans in order as was done historically.
* days.
* *
* Must hold registration_mutex when this function is called. * 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 device *parent)
{ {
struct dahdi_span *s; struct dahdi_span *s;
int ret = 0; int ret;
ddev->manufacturer = (ddev->manufacturer) ?: UNKNOWN; ddev->manufacturer = (ddev->manufacturer) ?: UNKNOWN;
ddev->location = (ddev->location) ?: UNKNOWN; ddev->location = (ddev->location) ?: UNKNOWN;
ddev->devicetype = (ddev->devicetype) ?: UNKNOWN; ddev->devicetype = (ddev->devicetype) ?: UNKNOWN;
ddev->dev.parent = parent;
list_for_each_entry(s, &ddev->spans, device_node) { list_for_each_entry(s, &ddev->spans, device_node) {
s->parent = ddev; 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; return ret;
} }
@ -6857,26 +7023,27 @@ int dahdi_register_device(struct dahdi_device *ddev, struct device *parent)
EXPORT_SYMBOL(dahdi_register_device); EXPORT_SYMBOL(dahdi_register_device);
/** /**
* _dahdi_unregister_span() - unregister a DAHDI span * _dahdi_unassign_span() - unassign a DAHDI span
* @span: the DAHDI span * @span: the DAHDI span
* *
* Unregisters a span that has been previously registered with * Unassigns a span that has been previously assigned with
* dahdi_register_span(). * dahdi_assign_span().
* *
* Must be called with the registration_mutex held. * 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; int x;
struct dahdi_span *new_master, *s; struct dahdi_span *new_master, *s;
unsigned long flags; unsigned long flags;
if (span != _find_span(span->spanno)) { if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name); dev_info(span->parent->dev.parent,
return -1; "local span %d is already unassigned\n",
local_spanno(span));
return -EINVAL;
} }
spin_lock_irqsave(&chan_lock, flags); spin_lock_irqsave(&chan_lock, flags);
list_del_init(&span->spans_node); list_del_init(&span->spans_node);
spin_unlock_irqrestore(&chan_lock, flags); spin_unlock_irqrestore(&chan_lock, flags);
@ -6888,8 +7055,9 @@ static int _dahdi_unregister_span(struct dahdi_span *span)
span->ops->shutdown(span); span->ops->shutdown(span);
if (debug & DEBUG_MAIN) 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 #ifdef CONFIG_PROC_FS
if (span->proc_entry)
remove_proc_entry(span->proc_entry->name, root_proc_entry); remove_proc_entry(span->proc_entry->name, root_proc_entry);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
@ -6920,6 +7088,17 @@ static int _dahdi_unregister_span(struct dahdi_span *span)
return 0; 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 * dahdi_unregister_device() - unregister a DAHDI device
* @span: the DAHDI span * @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) void dahdi_unregister_device(struct dahdi_device *ddev)
{ {
struct dahdi_span *s; struct dahdi_span *s;
struct dahdi_span *next;
WARN_ON(!ddev); WARN_ON(!ddev);
might_sleep(); might_sleep();
if (unlikely(!ddev)) if (unlikely(!ddev))
return; return;
mutex_lock(&registration_mutex); mutex_lock(&registration_mutex);
list_for_each_entry(s, &ddev->spans, device_node) list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
_dahdi_unregister_span(s); _dahdi_unassign_span(s);
list_del_init(&s->device_node);
}
mutex_unlock(&registration_mutex); mutex_unlock(&registration_mutex);
dahdi_sysfs_unregister_device(ddev);
if (UNKNOWN == ddev->location) if (UNKNOWN == ddev->location)
ddev->location = NULL; ddev->location = NULL;
if (UNKNOWN == ddev->manufacturer) if (UNKNOWN == ddev->manufacturer)
ddev->manufacturer = NULL; ddev->manufacturer = NULL;
if (UNKNOWN == ddev->devicetype) if (UNKNOWN == ddev->devicetype)
ddev->devicetype = NULL; ddev->devicetype = NULL;
} }
EXPORT_SYMBOL(dahdi_unregister_device); 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_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_PARM_DESC(hwec_overrides_swec, "When true, a hardware echo canceller is used instead of configured SWEC.");
module_param(pinned_spans, int, 0644); module_param(auto_assign_spans, int, 0644);
MODULE_PARM_DESC(pinned_spans, "If 1, span/channel numbers can be statically " MODULE_PARM_DESC(auto_assign_spans,
"defined. If 0, spans/channels are numbered in first come " "If 1 spans will automatically have their children span and "
"first serve order. Default 1"); "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 = { static const struct file_operations dahdi_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -218,13 +218,20 @@ static BUS_ATTR_READER(field##_show, dev, buf) \
span_attr(name, "%s\n"); span_attr(name, "%s\n");
span_attr(desc, "%s\n"); span_attr(desc, "%s\n");
span_attr(spantype, "%s\n"); span_attr(spantype, "%s\n");
span_attr(offset, "%d\n");
span_attr(alarms, "0x%x\n"); span_attr(alarms, "0x%x\n");
span_attr(irq, "%d\n"); span_attr(irq, "%d\n");
span_attr(irqmisses, "%d\n"); span_attr(irqmisses, "%d\n");
span_attr(lbo, "%d\n"); span_attr(lbo, "%d\n");
span_attr(syncsrc, "%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) static BUS_ATTR_READER(is_digital_show, dev, buf)
{ {
struct dahdi_span *span; struct dahdi_span *span;
@ -245,7 +252,7 @@ static struct device_attribute span_dev_attrs[] = {
__ATTR_RO(name), __ATTR_RO(name),
__ATTR_RO(desc), __ATTR_RO(desc),
__ATTR_RO(spantype), __ATTR_RO(spantype),
__ATTR_RO(offset), __ATTR_RO(local_spanno),
__ATTR_RO(alarms), __ATTR_RO(alarms),
__ATTR_RO(irq), __ATTR_RO(irq),
__ATTR_RO(irqmisses), __ATTR_RO(irqmisses),
@ -256,7 +263,6 @@ static struct device_attribute span_dev_attrs[] = {
__ATTR_NULL, __ATTR_NULL,
}; };
static struct driver_attribute dahdi_attrs[] = { static struct driver_attribute dahdi_attrs[] = {
__ATTR_NULL, __ATTR_NULL,
}; };
@ -335,7 +341,6 @@ static void span_release(struct device *dev)
dahdi_dbg(DEVICES, "%s: %s\n", __func__, dev_name(dev)); dahdi_dbg(DEVICES, "%s: %s\n", __func__, dev_name(dev));
} }
int dahdi_register_chardev(struct dahdi_chardev *dev) int dahdi_register_chardev(struct dahdi_chardev *dev)
{ {
static const char *DAHDI_STRING = "dahdi!"; static const char *DAHDI_STRING = "dahdi!";
@ -370,10 +375,8 @@ void span_sysfs_remove(struct dahdi_span *span)
span_dbg(DEVICES, span, "\n"); span_dbg(DEVICES, span, "\n");
span_device = span->span_device; span_device = span->span_device;
if (!span_device) { if (!span_device)
WARN_ON(!span_device);
return; return;
}
for (x = 0; x < span->channels; x++) { for (x = 0; x < span->channels; x++) {
struct dahdi_chan *chan = span->chans[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); dev_set_drvdata(span_device, NULL);
span_device->parent = NULL; span_device->parent = NULL;
put_device(span_device); 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) int span_sysfs_create(struct dahdi_span *span)
@ -404,7 +410,10 @@ int span_sysfs_create(struct dahdi_span *span)
int res = 0; int res = 0;
int x; 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); span->span_device = kzalloc(sizeof(*span->span_device), GFP_KERNEL);
if (!span->span_device) if (!span->span_device)
@ -414,8 +423,8 @@ int span_sysfs_create(struct dahdi_span *span)
span_dbg(DEVICES, span, "\n"); span_dbg(DEVICES, span, "\n");
span_device->bus = &spans_bus_type; span_device->bus = &spans_bus_type;
span_device->parent = span->parent->dev.parent; span_device->parent = &span->parent->dev;
dev_set_name(span_device, "span-%03d", span->spanno); dev_set_name(span_device, "span-%d", span->spanno);
dev_set_drvdata(span_device, span); dev_set_drvdata(span_device, span);
span_device->release = span_release; span_device->release = span_release;
res = device_register(span_device); res = device_register(span_device);
@ -471,8 +480,170 @@ static struct {
unsigned int pseudo:1; unsigned int pseudo:1;
unsigned int sysfs_driver_registered:1; unsigned int sysfs_driver_registered:1;
unsigned int sysfs_spans_bus_type:1; unsigned int sysfs_spans_bus_type:1;
unsigned int dahdi_device_bus_registered:1;
} dummy_dev; } 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) void dahdi_sysfs_exit(void)
{ {
dahdi_dbg(DEVICES, "SYSFS\n"); dahdi_dbg(DEVICES, "SYSFS\n");
@ -512,6 +683,49 @@ void dahdi_sysfs_exit(void)
dummy_dev.sysfs_spans_bus_type = 0; dummy_dev.sysfs_spans_bus_type = 0;
} }
unregister_chrdev(DAHDI_MAJOR, "dahdi"); 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) 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; int res = 0;
void *dev; 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); res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops);
if (res) { if (res) {
module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR); module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR);

View File

@ -34,4 +34,28 @@ void span_sysfs_remove(struct dahdi_span *span);
int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops); int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops);
void dahdi_sysfs_exit(void); 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 */ #endif /* _DAHDI_H */

View File

@ -1874,7 +1874,7 @@ static int t1_software_init(struct t1 *wc, enum linemode type)
return res; return res;
} }
return 0; return res;
} }
#if 0 #if 0

View File

@ -904,6 +904,7 @@ static int xbus_register_dahdi_device(xbus_t *xbus)
* So let's also export it via the newfangled "location" field. * So let's also export it via the newfangled "location" field.
*/ */
xbus->ddev->location = xbus->connector; xbus->ddev->location = xbus->connector;
xbus->ddev->hardware_id = xbus->label;
/* /*
* Prepare the span list * Prepare the span list
@ -943,6 +944,7 @@ static void xbus_unregister_dahdi_device(xbus_t *xbus)
kfree(xbus->ddev->devicetype); kfree(xbus->ddev->devicetype);
xbus->ddev->devicetype = NULL; xbus->ddev->devicetype = NULL;
xbus->ddev->location = NULL; xbus->ddev->location = NULL;
xbus->ddev->hardware_id = NULL;
dahdi_free_device(xbus->ddev); dahdi_free_device(xbus->ddev);
xbus->ddev = NULL; xbus->ddev = NULL;
for(i = 0; i < MAX_XPDS; i++) { for(i = 0; i < MAX_XPDS; i++) {

View File

@ -898,7 +898,11 @@ struct dahdi_span_ops {
* *
* @spans: List of child spans. * @spans: List of child spans.
* @manufacturer: Device manufacturer. * @manufacturer: Device manufacturer.
* @location: The location of this device * @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. * @devicetype: What type of device this is.
* *
*/ */
@ -906,6 +910,7 @@ struct dahdi_device {
struct list_head spans; struct list_head spans;
const char *manufacturer; const char *manufacturer;
const char *location; const char *location;
const char *hardware_id;
const char *devicetype; const char *devicetype;
struct device dev; 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); int dahdi_register_device(struct dahdi_device *ddev, struct device *parent);
void dahdi_unregister_device(struct dahdi_device *ddev); void dahdi_unregister_device(struct dahdi_device *ddev);
void dahdi_free_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 */ /*! Allocate / free memory for a transcoder */
struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans); 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.26 */
#endif /* 2.6.31 */ #endif /* 2.6.31 */
#ifndef CONFIG_TRACING
#define trace_printk printk
#endif
#ifndef DEFINE_SPINLOCK #ifndef DEFINE_SPINLOCK
#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED #define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
#endif #endif