diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 80eea41..825d1c4 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -108,8 +108,6 @@ EXPORT_SYMBOL(dahdi_transcode_fops); EXPORT_SYMBOL(dahdi_init_tone_state); EXPORT_SYMBOL(dahdi_mf_tone); -EXPORT_SYMBOL(dahdi_register); -EXPORT_SYMBOL(dahdi_unregister); EXPORT_SYMBOL(__dahdi_mulaw); EXPORT_SYMBOL(__dahdi_alaw); #ifdef CONFIG_CALC_XLAW @@ -399,7 +397,7 @@ __for_each_channel(unsigned long (*func)(struct dahdi_chan *chan, struct dahdi_span *s; struct pseudo_chan *pseudo; - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { unsigned long x; for (x = 0; x < s->channels; x++) { struct dahdi_chan *const chan = s->chans[x]; @@ -439,7 +437,7 @@ static struct dahdi_chan *_chan_from_num(unsigned int channo) /* 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) { + list_for_each_entry(s, &span_list, spans_node) { unsigned int basechan; struct dahdi_chan *chan; @@ -488,7 +486,7 @@ static inline struct dahdi_chan *chan_from_file(struct file *file) static struct dahdi_span *_find_span(int spanno) { struct dahdi_span *s; - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { if (s->spanno == spanno) { return s; } @@ -526,7 +524,7 @@ static unsigned int span_count(void) struct dahdi_span *s; unsigned long flags; spin_lock_irqsave(&chan_lock, flags); - list_for_each_entry(s, &span_list, node) + list_for_each_entry(s, &span_list, spans_node) ++count; spin_unlock_irqrestore(&chan_lock, flags); return count; @@ -3043,6 +3041,16 @@ 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. + * + * Call with the registration_mutex held since this function will determine a + * channel number, and must be protected from additional registrations while + * that is happening. + * + */ static struct dahdi_chan *dahdi_alloc_pseudo(struct file *file) { struct pseudo_chan *pseudo; @@ -3068,8 +3076,6 @@ static struct dahdi_chan *dahdi_alloc_pseudo(struct file *file) pseudo->chan.flags = DAHDI_FLAG_AUDIO; pseudo->chan.span = NULL; /* No span == psuedo channel */ - mutex_lock(®istration_mutex); - channo = FIRST_PSEUDO_CHANNEL; list_for_each_entry(p, &pseudo_chans, node) { if (channo != p->chan.channo) @@ -3094,8 +3100,6 @@ static struct dahdi_chan *dahdi_alloc_pseudo(struct file *file) list_add(&pseudo->node, pos); spin_unlock_irqrestore(&chan_lock, flags); - mutex_unlock(®istration_mutex); - return &pseudo->chan; } @@ -3159,7 +3163,9 @@ static int dahdi_open(struct inode *inode, struct file *file) if (unit == DAHDI_CHANNEL) return dahdi_chan_open(file); if (unit == DAHDI_PSEUDO) { + mutex_lock(®istration_mutex); chan = dahdi_alloc_pseudo(file); + mutex_unlock(®istration_mutex); if (unlikely(!chan)) return -ENOMEM; return dahdi_specchan_open(file); @@ -3719,7 +3725,7 @@ static void __dahdi_find_master_span(void) spin_lock_irqsave(&chan_lock, flags); old_master = master; - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { if (s->alarms) continue; if (dahdi_is_digital_span(s) && @@ -4241,16 +4247,18 @@ static int dahdi_ioctl_spanstat(struct file *file, unsigned long data) spaninfo.linecompat = s->linecompat; strlcpy(spaninfo.lboname, dahdi_lboname(s->lbo), sizeof(spaninfo.lboname)); - if (s->manufacturer) { - strlcpy(spaninfo.manufacturer, s->manufacturer, - sizeof(spaninfo.manufacturer)); + if (s->parent->manufacturer) { + strlcpy(spaninfo.manufacturer, s->parent->manufacturer, + sizeof(spaninfo.manufacturer)); } - if (s->devicetype) { - strlcpy(spaninfo.devicetype, s->devicetype, - sizeof(spaninfo.devicetype)); + if (s->parent->devicetype) { + strlcpy(spaninfo.devicetype, s->parent->devicetype, + sizeof(spaninfo.devicetype)); + } + if (s->parent->location) { + strlcpy(spaninfo.location, s->parent->location, + sizeof(spaninfo.location)); } - strlcpy(spaninfo.location, s->location, - sizeof(spaninfo.location)); if (s->spantype) { strlcpy(spaninfo.spantype, s->spantype, sizeof(spaninfo.spantype)); @@ -4328,21 +4336,18 @@ static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data) dahdi_lboname(s->lbo), sizeof(spaninfo_v1.lboname)); - if (s->manufacturer) { - strlcpy(spaninfo_v1.manufacturer, - s->manufacturer, + if (s->parent->manufacturer) { + strlcpy(spaninfo_v1.manufacturer, s->parent->manufacturer, sizeof(spaninfo_v1.manufacturer)); } - if (s->devicetype) { - strlcpy(spaninfo_v1.devicetype, - s->devicetype, - sizeof(spaninfo_v1.devicetype)); + if (s->parent->devicetype) { + strlcpy(spaninfo_v1.devicetype, s->parent->devicetype, + sizeof(spaninfo_v1.devicetype)); } - strlcpy(spaninfo_v1.location, - s->location, - sizeof(spaninfo_v1.location)); + strlcpy(spaninfo_v1.location, s->parent->location, + sizeof(spaninfo_v1.location)); if (s->spantype) { strlcpy(spaninfo_v1.spantype, @@ -5399,7 +5404,7 @@ static int dahdi_ioctl_confdiag(struct file *file, unsigned long data) struct pseudo_chan *pseudo; c = 0; spin_lock_irqsave(&chan_lock, flags); - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { int k; for (k = 0; k < s->channels; k++) { chan = s->chans[k]; @@ -6610,9 +6615,9 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd, */ static int _get_next_channo(const struct dahdi_span *span) { - const struct list_head *pos = &span->node; + const struct list_head *pos = &span->spans_node; while (pos != &span_list) { - span = list_entry(pos, struct dahdi_span, node); + span = list_entry(pos, struct dahdi_span, spans_node); if (span->channels) return span->chans[0]->channo; pos = pos->next; @@ -6636,10 +6641,10 @@ static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span, *spanno = 1; *channo = 1; - list_for_each_entry(pos, &span_list, node) { + list_for_each_entry(pos, &span_list, spans_node) { bool skip_span; - loc = &pos->node; + loc = &pos->spans_node; next_channo = _get_next_channo(pos); skip_span = (pos->spanno == *spanno) || @@ -6658,13 +6663,39 @@ static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span, return loc; } +struct dahdi_device *dahdi_create_device(void) +{ + struct dahdi_device *ddev; + ddev = kzalloc(sizeof(*ddev), GFP_KERNEL); + if (!ddev) + return NULL; + return ddev; +} +EXPORT_SYMBOL(dahdi_create_device); + +void dahdi_free_device(struct dahdi_device *ddev) +{ + kfree(ddev); +} +EXPORT_SYMBOL(dahdi_free_device); + /** - * _dahdi_register - Register the span. + * _dahdi_register_span() - Register a new DAHDI span + * @span: the DAHDI span + * @prefmaster: will the new span be preferred as a master? * - * NOTE: Must be called with the registration_mutex held. + * Registers a span for usage with DAHDI. All the channel numbers in it + * will get the lowest available channel numbers. + * + * 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. * */ -static int _dahdi_register(struct dahdi_span *span, int prefmaster) +static int _dahdi_register_span(struct dahdi_span *span, int prefmaster) { unsigned int spanno; unsigned int x; @@ -6689,7 +6720,7 @@ static int _dahdi_register(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. @@ -6735,9 +6766,9 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster) spin_lock_irqsave(&chan_lock, flags); if (loc == &span_list) - list_add_tail(&span->node, &span_list); + list_add_tail(&span->spans_node, &span_list); else - list_add(&span->node, loc); + list_add(&span->spans_node, loc); spin_unlock_irqrestore(&chan_lock, flags); set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); __dahdi_find_master_span(); @@ -6762,30 +6793,71 @@ cleanup: return res; } +static const char *UNKNOWN = ""; + /** - * dahdi_register() - unregister a new DAHDI span - * @span: the DAHDI span - * @prefmaster: will the new span be preferred as a master? + * _dahdi_register_device - Registers the spans of a DAHDI device. + * @ddev: the DAHDI device * - * Registers a span for usage with DAHDI. All the channel numbers in it - * will get the lowest available channel numbers. + * If pinned_spans is defined 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. * - * 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 hold registration_mutex when this function is called. * */ -int dahdi_register(struct dahdi_span *span, int prefmaster) +static int _dahdi_register_device(struct dahdi_device *ddev, + struct device *parent) { - int ret; - mutex_lock(®istration_mutex); - ret = _dahdi_register(span, prefmaster); - mutex_unlock(®istration_mutex); + struct dahdi_span *s; + int ret = 0; + + ddev->manufacturer = (ddev->manufacturer) ?: UNKNOWN; + ddev->location = (ddev->location) ?: UNKNOWN; + ddev->devicetype = (ddev->devicetype) ?: UNKNOWN; + + list_for_each_entry(s, &ddev->spans, device_node) { + s->parent = ddev; + ret = _dahdi_register_span(s, 1); + } + return ret; } -static int _dahdi_unregister(struct dahdi_span *span) +/** + * dahdi_register_device() - unregister a new DAHDI device + * @ddev: the DAHDI device + * + * Registers a device for usage with DAHDI. + * + */ +int dahdi_register_device(struct dahdi_device *ddev, struct device *parent) +{ + int ret; + + if (!ddev) + return -EINVAL; + + mutex_lock(®istration_mutex); + ret = _dahdi_register_device(ddev, parent); + mutex_unlock(®istration_mutex); + + return ret; +} +EXPORT_SYMBOL(dahdi_register_device); + +/** + * _dahdi_unregister_span() - unregister a DAHDI span + * @span: the DAHDI span + * + * Unregisters a span that has been previously registered with + * dahdi_register_span(). + * + * Must be called with the registration_mutex held. + * + */ +static int _dahdi_unregister_span(struct dahdi_span *span) { int x; struct dahdi_span *new_master, *s; @@ -6797,7 +6869,7 @@ static int _dahdi_unregister(struct dahdi_span *span) } spin_lock_irqsave(&chan_lock, flags); - list_del_init(&span->node); + list_del_init(&span->spans_node); spin_unlock_irqrestore(&chan_lock, flags); span->spanno = 0; clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); @@ -6822,7 +6894,7 @@ static int _dahdi_unregister(struct dahdi_span *span) new_master = NULL; spin_lock_irqsave(&chan_lock, flags); - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { if ((s == new_master) || !can_provide_timing(s)) continue; new_master = s; @@ -6839,21 +6911,45 @@ static int _dahdi_unregister(struct dahdi_span *span) return 0; } +int dahdi_unregister_span(struct dahdi_span *span) +{ + module_printk(KERN_NOTICE, "%s: %s\n", __func__, span->name); + mutex_lock(®istration_mutex); + _dahdi_unregister_span(span); + list_del_init(&span->device_node); + mutex_unlock(®istration_mutex); + return 0; +} + /** - * dahdi_unregister() - unregister a DAHDI span + * dahdi_unregister_device() - unregister a DAHDI device * @span: the DAHDI span * - * Unregisters a span that has been previously registered with - * dahdi_register(). + * Unregisters a device that has been previously registered with + * dahdi_register_device(). + * */ -int dahdi_unregister(struct dahdi_span *span) +void dahdi_unregister_device(struct dahdi_device *ddev) { - int ret; + struct dahdi_span *s; + WARN_ON(!ddev); + might_sleep(); + if (unlikely(!ddev)) + return; + mutex_lock(®istration_mutex); - ret = _dahdi_unregister(span); + list_for_each_entry(s, &ddev->spans, device_node) + _dahdi_unregister_span(s); mutex_unlock(®istration_mutex); - return ret; + + 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); /* ** This routine converts from linear to ulaw @@ -9152,7 +9248,7 @@ static void _process_masterspan(void) /* Process any timers */ process_timers(); - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { for (x = 0; x < s->channels; ++x) { struct dahdi_chan *const chan = s->chans[x]; if (!chan->confmode) @@ -9181,7 +9277,7 @@ static void _process_masterspan(void) pseudo_rx_audio(&pseudo->chan); } - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { for (x = 0; x < s->channels; x++) { struct dahdi_chan *const chan = s->chans[x]; if (!chan->confmode) @@ -9452,6 +9548,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"); + static const struct file_operations dahdi_fops = { .owner = THIS_MODULE, .open = dahdi_open, @@ -9494,7 +9595,7 @@ static void watchdog_check(unsigned long ignored) struct dahdi_span *s; spin_lock_irqsave(&span_list_lock, flags); - list_for_each_entry(s, &span_list, node) { + list_for_each_entry(s, &span_list, spans_node) { if (s->flags & DAHDI_FLAG_RUNNING) { if (s->watchcounter == DAHDI_WATCHDOG_INIT) { /* Whoops, dead card */ diff --git a/drivers/dahdi/dahdi_dynamic.c b/drivers/dahdi/dahdi_dynamic.c index 20d7246..cbcdce7 100644 --- a/drivers/dahdi/dahdi_dynamic.c +++ b/drivers/dahdi/dahdi_dynamic.c @@ -400,6 +400,7 @@ static void dahdi_dynamic_release(struct kref *kref) for (x = 0; x < d->span.channels; x++) kfree(d->chans[x]); + dahdi_free_device(d->ddev); kfree(d); } @@ -469,7 +470,7 @@ static int _destroy_dynamic(struct dahdi_dynamic_span *dds) return -EBUSY; } - dahdi_unregister(&d->span); + dahdi_unregister_device(d->ddev); spin_lock_irqsave(&dspan_lock, flags); list_del_rcu(&d->list); @@ -578,8 +579,8 @@ static int _create_dynamic(struct dahdi_dynamic_span *dds) d = kzalloc(sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; - kref_init(&d->kref); + d->ddev = dahdi_create_device(); for (x = 0; x < dds->numchans; x++) { d->chans[x] = kzalloc(sizeof(*d->chans[x]), GFP_KERNEL); @@ -657,8 +658,9 @@ static int _create_dynamic(struct dahdi_dynamic_span *dds) return res; } + list_add_tail(&d->span.device_node, &d->ddev->spans); /* Whee! We're created. Now register the span */ - if (dahdi_register(&d->span, 0)) { + if (dahdi_register_device(d->ddev, d->dev)) { printk(KERN_NOTICE "Unable to register span '%s'\n", d->span.name); dynamic_put(d); @@ -769,7 +771,7 @@ void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *dri) WARN_ON(1); } } - dahdi_unregister(&d->span); + dahdi_unregister_device(d->ddev); spin_lock_irqsave(&dspan_lock, flags); list_del_rcu(&d->list); spin_unlock_irqrestore(&dspan_lock, flags); diff --git a/drivers/dahdi/pciradio.c b/drivers/dahdi/pciradio.c index e6ff52e..0384908 100644 --- a/drivers/dahdi/pciradio.c +++ b/drivers/dahdi/pciradio.c @@ -146,6 +146,7 @@ struct encdec struct pciradio { struct pci_dev *dev; + struct dahdi_device *ddev; struct dahdi_span span; unsigned char ios; int usecount; @@ -1488,7 +1489,7 @@ static int pciradio_initialize(struct pciradio *rad) rad->span.flags = DAHDI_FLAG_RBS; rad->span.ops = &pciradio_span_ops; - if (dahdi_register(&rad->span, 0)) { + if (dahdi_register_device(rad->ddev, &rad->dev->dev)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } @@ -1777,7 +1778,7 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de release_region(rad->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)rad->writechunk, rad->writedma); pci_set_drvdata(pdev, NULL); - dahdi_unregister(&rad->span); + dahdi_free_device(rad->ddev); kfree(rad); return -EIO; @@ -1810,7 +1811,7 @@ static int __devinit pciradio_init_one(struct pci_dev *pdev, const struct pci_de static void pciradio_release(struct pciradio *rad) { - dahdi_unregister(&rad->span); + dahdi_unregister_device(rad->ddev); if (rad->freeregion) release_region(rad->ioaddr, 0xff); kfree(rad); diff --git a/drivers/dahdi/tor2.c b/drivers/dahdi/tor2.c index 969f569..6fc8930 100644 --- a/drivers/dahdi/tor2.c +++ b/drivers/dahdi/tor2.c @@ -97,6 +97,7 @@ struct tor2 { unsigned long xilinx8_region; /* 8 bit Region allocated to Xilinx */ unsigned long xilinx8_len; /* Length of 8 bit Xilinx region */ __iomem volatile unsigned char *mem8; /* Virtual representation of 8 bit Xilinx memory area */ + struct dahdi_device *ddev; struct tor2_span tspans[SPANS_PER_CARD]; /* Span data */ struct dahdi_chan **chans[SPANS_PER_CARD]; /* Pointers to card channels */ struct tor2_chan tchans[32 * SPANS_PER_CARD]; /* Channel user data */ @@ -285,10 +286,6 @@ static void init_spans(struct tor2 *tor) snprintf(s->desc, sizeof(s->desc) - 1, "Tormenta 2 (PCI) Quad %s Card %d Span %d", (tor->cardtype == TYPE_T1) ? "T1" : "E1", tor->num, x + 1); - s->manufacturer = "Digium"; - strlcpy(s->devicetype, tor->type, sizeof(s->devicetype)); - snprintf(s->location, sizeof(s->location) - 1, - "PCI Bus %02d Slot %02d", tor->pci->bus->number, PCI_SLOT(tor->pci->devfn) + 1); if (tor->cardtype == TYPE_T1) { s->channels = 24; s->deflaw = DAHDI_LAW_MULAW; @@ -322,19 +319,31 @@ static void init_spans(struct tor2 *tor) static int __devinit tor2_launch(struct tor2 *tor) { + int res; struct dahdi_span *s; int i; if (test_bit(DAHDI_FLAGBIT_REGISTERED, &tor->tspans[0].dahdi_span.flags)) return 0; + tor->ddev = dahdi_create_device(); + tor->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + tor->pci->bus->number, + PCI_SLOT(tor->pci->devfn) + 1); + + if (!tor->ddev->location) + return -ENOMEM; + printk(KERN_INFO "Tor2: Launching card: %d\n", tor->order); for (i = 0; i < SPANS_PER_CARD; ++i) { s = &tor->tspans[i].dahdi_span; - if (dahdi_register(s, 0)) { - printk(KERN_ERR "Unable to register span %s\n", s->name); - goto error_exit; - } + list_add_tail(&s->device_node, &tor->ddev->spans); + } + + res = dahdi_register_device(tor->ddev, &tor->pci->dev); + if (res) { + dev_err(&tor->pci->dev, "Unable to register with DAHDI.\n"); + return res; } writew(PLX_INTENA, &tor->plx[INTCSR]); /* enable PLX interrupt */ @@ -342,14 +351,6 @@ static int __devinit tor2_launch(struct tor2 *tor) tasklet_init(&tor->tor2_tlet, tor2_tasklet, (unsigned long)tor); #endif return 0; - -error_exit: - for (i = 0; i < SPANS_PER_CARD; ++i) { - s = &tor->tspans[i].dahdi_span; - if (test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags)) - dahdi_unregister(s); - } - return -1; } static void free_tor(struct tor2 *tor) @@ -365,6 +366,8 @@ static void free_tor(struct tor2 *tor) if (tor->chans[x]) kfree(tor->chans[x]); } + kfree(tor->ddev->location); + dahdi_free_device(tor->ddev); kfree(tor); } @@ -631,7 +634,6 @@ static struct pci_driver tor2_driver; static void __devexit tor2_remove(struct pci_dev *pdev) { struct tor2 *tor; - int i; tor = pci_get_drvdata(pdev); if (!tor) @@ -641,11 +643,7 @@ static void __devexit tor2_remove(struct pci_dev *pdev) writeb(0, &tor->mem8[LEDREG]); writew(0, &tor->plx[INTCSR]); free_irq(tor->irq, tor); - for (i = 0; i < SPANS_PER_CARD; ++i) { - struct dahdi_span *s = &tor->tspans[i].dahdi_span; - if (test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags)) - dahdi_unregister(s); - } + dahdi_unregister_device(tor->ddev); release_mem_region(tor->plx_region, tor->plx_len); release_mem_region(tor->xilinx32_region, tor->xilinx32_len); release_mem_region(tor->xilinx8_region, tor->xilinx8_len); diff --git a/drivers/dahdi/voicebus/voicebus.c b/drivers/dahdi/voicebus/voicebus.c index d11559a..28b8e32 100644 --- a/drivers/dahdi/voicebus/voicebus.c +++ b/drivers/dahdi/voicebus/voicebus.c @@ -2030,7 +2030,7 @@ static int __init voicebus_module_init(void) * defined, but it will make sure that this module is a dependency of * dahdi.ko, so that when it is being unloded, this module will be * unloaded as well. */ - dahdi_register(NULL, 0); + dahdi_register_device(NULL, NULL); spin_lock_init(&loader_list_lock); return 0; } diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c index 3fb5647..72744f8 100644 --- a/drivers/dahdi/wcb4xxp/base.c +++ b/drivers/dahdi/wcb4xxp/base.c @@ -2494,11 +2494,6 @@ static void init_spans(struct b4xxp *b4) sprintf(bspan->span.name, "B4/%d/%d", b4->cardno, i+1); sprintf(bspan->span.desc, "B4XXP (PCI) Card %d Span %d", b4->cardno, i+1); - bspan->span.manufacturer = "Digium"; - strlcpy(bspan->span.devicetype, b4->variety, - sizeof(bspan->span.devicetype)); - sprintf(bspan->span.location, "PCI Bus %02d Slot %02d", - b4->pdev->bus->number, PCI_SLOT(b4->pdev->devfn) + 1); bspan->span.ops = &b4xxp_span_ops; /* HDLC stuff */ @@ -2930,14 +2925,27 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id hfc_init_all_st(b4); /* initialize the DAHDI structures, and let DAHDI know it has some new hardware to play with */ + b4->ddev = dahdi_create_device(); init_spans(b4); + for (x=0; x < b4->numspans; x++) { - if (dahdi_register(&b4->spans[x].span, 0)) { - dev_err(&b4->pdev->dev, - "Unable to register span %s\n", - b4->spans[x].span.name); - goto err_out_unreg_spans; - } + struct dahdi_span *const s = &b4->spans[x].span; + list_add_tail(&s->device_node, &b4->ddev->spans); + } + + b4->ddev->manufacturer = "Digium"; + b4->ddev->devicetype = b4->variety; + b4->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + b4->pdev->bus->number, + PCI_SLOT(b4->pdev->devfn) + 1); + if (!b4->ddev->location) { + ret = -ENOMEM; + goto err_out_del_from_card_array; + } + + if (dahdi_register_device(b4->ddev, &b4->pdev->dev)) { + dev_err(&b4->pdev->dev, "Unable to register device.\n"); + goto err_out_unreg_spans; } @@ -2973,10 +2981,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id /* 'x' will have the failing span #. (0-3). We need to unregister everything before it. */ err_out_unreg_spans: - while (x) { - dahdi_unregister(&b4->spans[x].span); - x--; - }; + dahdi_unregister_device(b4->ddev); b4xxp_init_stage1(b4); /* full reset, re-init to "no-irq" state */ free_irq(pdev->irq, b4); @@ -2997,6 +3002,8 @@ err_out_free_mem: pci_set_drvdata(pdev, NULL); pci_iounmap(pdev, b4->ioaddr); pci_iounmap(pdev, b4->addr); + kfree(b4->ddev->location); + dahdi_free_device(b4->ddev); kfree(b4); err_out_release_regions: @@ -3011,14 +3018,11 @@ err_out_disable_pdev: static void __devexit b4xxp_remove(struct pci_dev *pdev) { struct b4xxp *b4 = pci_get_drvdata(pdev); - int i; if (b4) { b4->shutdown = 1; - for (i=b4->numspans - 1; i >= 0; i--) { - dahdi_unregister(&b4->spans[i].span); - } + dahdi_unregister_device(b4->ddev); b4xxp_init_stage1(b4); remove_sysfs_files(b4); @@ -3033,6 +3037,8 @@ static void __devexit b4xxp_remove(struct pci_dev *pdev) tasklet_kill(&b4->b4xxp_tlet); + kfree(b4->ddev->location); + dahdi_free_device(b4->ddev); kfree(b4); } diff --git a/drivers/dahdi/wcb4xxp/wcb4xxp.h b/drivers/dahdi/wcb4xxp/wcb4xxp.h index 56dc93b..80a28fe 100644 --- a/drivers/dahdi/wcb4xxp/wcb4xxp.h +++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h @@ -474,6 +474,7 @@ struct b4xxp { /* Flags for our bottom half */ unsigned int shutdown; /* 1=bottom half doesn't process anything, just returns */ struct tasklet_struct b4xxp_tlet; + struct dahdi_device *ddev; }; /* CPLD access bits */ diff --git a/drivers/dahdi/wcfxo.c b/drivers/dahdi/wcfxo.c index d206512..948d299 100644 --- a/drivers/dahdi/wcfxo.c +++ b/drivers/dahdi/wcfxo.c @@ -135,6 +135,7 @@ static int wecareregs[] = struct wcfxo { struct pci_dev *dev; char *variety; + struct dahdi_device *ddev; struct dahdi_span span; struct dahdi_chan _chan; struct dahdi_chan *chan; @@ -647,14 +648,20 @@ static const struct dahdi_span_ops wcfxo_span_ops = { static int wcfxo_initialize(struct wcfxo *wc) { + wc->ddev = dahdi_create_device(); + /* DAHDI stuff */ sprintf(wc->span.name, "WCFXO/%d", wc->pos); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); sprintf(wc->chan->name, "WCFXO/%d/%d", wc->pos, 0); - snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); - wc->span.manufacturer = "Digium"; - strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); + wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + wc->dev->bus->number, + PCI_SLOT(wc->dev->devfn) + 1); + if (!wc->ddev->location) + return -ENOMEM; + + wc->ddev->manufacturer = "Digium"; + wc->ddev->devicetype = wc->variety; wc->chan->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF; wc->chan->chanpos = 1; wc->span.chans = &wc->chan; @@ -668,7 +675,8 @@ static int wcfxo_initialize(struct wcfxo *wc) wc->chan->pvt = wc; wc->span.ops = &wcfxo_span_ops; - if (dahdi_register(&wc->span, 0)) { + list_add_tail(&wc->span.device_node, &wc->ddev->spans); + if (dahdi_register_device(wc->ddev, &wc->dev->dev)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } @@ -976,7 +984,7 @@ static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_devic printk(KERN_NOTICE "Failed to initailize DAA, giving up...\n"); wcfxo_stop_dma(wc); wcfxo_disable_interrupts(wc); - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); free_irq(pdev->irq, wc); /* Reset PCI chip and registers */ @@ -984,6 +992,8 @@ static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_devic if (wc->freeregion) release_region(wc->ioaddr, 0xff); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); return -EIO; } @@ -995,9 +1005,11 @@ static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_devic static void wcfxo_release(struct wcfxo *wc) { - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); if (wc->freeregion) release_region(wc->ioaddr, 0xff); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } diff --git a/drivers/dahdi/wct1xxp.c b/drivers/dahdi/wct1xxp.c index fc8373e..686d0a7 100644 --- a/drivers/dahdi/wct1xxp.c +++ b/drivers/dahdi/wct1xxp.c @@ -159,6 +159,7 @@ struct t1xxp { unsigned char ec_chunk2[31][DAHDI_CHUNKSIZE]; unsigned char tempo[32]; struct dahdi_span span; /* Span */ + struct dahdi_device *ddev; struct dahdi_chan *chans[31]; /* Channels */ }; @@ -272,10 +273,11 @@ static void t1xxp_release(struct t1xxp *wc) { unsigned int x; - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); for (x = 0; x < (wc->ise1 ? 31 : 24); x++) { kfree(wc->chans[x]); } + dahdi_free_device(wc->ddev); kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } @@ -770,13 +772,20 @@ static int t1xxp_software_init(struct t1xxp *wc) } if (x >= WC_MAX_CARDS) return -1; + + wc->ddev = dahdi_create_device(); + wc->num = x; sprintf(wc->span.name, "WCT1/%d", wc->num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); - wc->span.manufacturer = "Digium"; - strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); - snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); + wc->ddev->manufacturer = "Digium"; + wc->ddev->devicetype = wc->variety; + wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + wc->dev->bus->number, + PCI_SLOT(wc->dev->devfn) + 1); + if (!wc->ddev->location) + return -ENOMEM; + wc->span.irq = wc->dev->irq; wc->span.chans = wc->chans; wc->span.flags = DAHDI_FLAG_RBS; @@ -801,7 +810,8 @@ static int t1xxp_software_init(struct t1xxp *wc) wc->chans[x]->chanpos = x + 1; } wc->span.ops = &t1xxp_span_ops; - if (dahdi_register(&wc->span, 0)) { + list_add_tail(&wc->span.device_node, &wc->ddev->spans); + if (dahdi_register_device(wc->ddev, &wc->dev->dev)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c index dab436c..4bdea1f 100644 --- a/drivers/dahdi/wct4xxp/base.c +++ b/drivers/dahdi/wct4xxp/base.c @@ -325,6 +325,7 @@ struct t4 { int num; /* Which card we are */ int t1e1; /* T1/E1 select pins */ int syncsrc; /* active sync source */ + struct dahdi_device *ddev; struct t4_span *tspans[4]; /* Individual spans */ int numspans; /* Number of spans on the card */ int blinktimer; @@ -1698,34 +1699,30 @@ static int t4_close(struct dahdi_chan *chan) return 0; } +static int set_span_devicetype(struct t4 *wc) +{ #ifdef VPM_SUPPORT -static void set_span_devicetype(struct t4 *wc) -{ - int x; + const char *vpmstring; + if (wc->vpm450m) { + if (wc->numspans > 2) + vpmstring = "OCT128"; + else + vpmstring = "OCT064"; - for (x = 0; x < wc->numspans; x++) { - struct t4_span *const ts = wc->tspans[x]; - strlcpy(ts->span.devicetype, wc->devtype->desc, - sizeof(ts->span.devicetype)); - - if (wc->vpm450m) { - strncat(ts->span.devicetype, (wc->numspans > 2) ? " (VPMOCT128)" : " (VPMOCT064)", - sizeof(ts->span.devicetype) - 1); - } + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s (VPM%s)", + wc->devtype->desc, vpmstring); + } else { + wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); } -} #else -static void set_span_devicetype(struct t4 *wc) -{ - int x; - for (x = 0; x < wc->numspans; x++) { - struct t4_span *const ts = wc->tspans[x]; - strlcpy(ts->span.devicetype, wc->devtype->desc, - sizeof(ts->span.devicetype)); - } -} + wc->ddev->devicetype = kasprintf(GFP_KERNEL, wc->devtype->desc); #endif + if (!wc->ddev->devicetype) + return -ENOMEM; + return 0; +} + /* The number of cards we have seen with each possible 'order' switch setting. */ @@ -1805,13 +1802,6 @@ static void init_spans(struct t4 *wc) sprintf(ts->span.name, "TE%d/%d/%d", wc->numspans, wc->num, x + 1); snprintf(ts->span.desc, sizeof(ts->span.desc) - 1, "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num, x+1); - ts->span.manufacturer = "Digium"; - if (!ignore_rotary && (1 == order_index[wc->order])) - snprintf(ts->span.location, sizeof(ts->span.location) - 1, "Board ID Switch %d", wc->order); - else - snprintf(ts->span.location, sizeof(ts->span.location) - 1, - "PCI%s Bus %02d Slot %02d", (ts->spanflags & FLAG_EXPRESS) ? " Express" : " ", - wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); switch (ts->linemode) { case T1: ts->span.spantype = "T1"; @@ -4043,7 +4033,10 @@ static int t4_hardware_init_2(struct t4 *wc) static int __devinit t4_launch(struct t4 *wc) { + int x; + int res; unsigned long flags; + if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags)) return 0; @@ -4055,35 +4048,33 @@ static int __devinit t4_launch(struct t4 *wc) t4_serial_setup(wc); - if (dahdi_register(&wc->tspans[0]->span, 0)) { - dev_err(&wc->dev->dev, "Unable to register span %s\n", - wc->tspans[0]->span.name); - return -1; - } - if (dahdi_register(&wc->tspans[1]->span, 0)) { - dev_err(&wc->dev->dev, "Unable to register span %s\n", - wc->tspans[1]->span.name); - dahdi_unregister(&wc->tspans[0]->span); - return -1; + wc->ddev->manufacturer = "Digium"; + if (!ignore_rotary && (1 == order_index[wc->order])) { + wc->ddev->location = kasprintf(GFP_KERNEL, + "Board ID Switch %d", wc->order); + } else { + bool express = ((wc->tspans[0]->spanflags & FLAG_EXPRESS) > 0); + wc->ddev->location = kasprintf(GFP_KERNEL, + "PCI%s Bus %02d Slot %02d", + (express) ? " Express" : "", + wc->dev->bus->number, + PCI_SLOT(wc->dev->devfn) + 1); } - if (wc->numspans == 4) { - if (dahdi_register(&wc->tspans[2]->span, 0)) { - dev_err(&wc->dev->dev, "Unable to register span %s\n", - wc->tspans[2]->span.name); - dahdi_unregister(&wc->tspans[0]->span); - dahdi_unregister(&wc->tspans[1]->span); - return -1; - } - if (dahdi_register(&wc->tspans[3]->span, 0)) { - dev_err(&wc->dev->dev, "Unable to register span %s\n", - wc->tspans[3]->span.name); - dahdi_unregister(&wc->tspans[0]->span); - dahdi_unregister(&wc->tspans[1]->span); - dahdi_unregister(&wc->tspans[2]->span); - return -1; - } + if (!wc->ddev->location) + return -ENOMEM; + + for (x = 0; x < wc->numspans; ++x) { + list_add_tail(&wc->tspans[x]->span.device_node, + &wc->ddev->spans); } + + res = dahdi_register_device(wc->ddev, &wc->dev->dev); + if (res) { + dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n"); + return res; + } + set_bit(T4_CHECK_TIMING, &wc->checkflag); spin_lock_irqsave(&wc->reglock, flags); __t4_set_sclk_src(wc, WC_SELF, 0, 0); @@ -4105,6 +4096,10 @@ static void free_wc(struct t4 *wc) } kfree(wc->tspans[x]); } + + kfree(wc->ddev->devicetype); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); } @@ -4146,11 +4141,16 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i return -EIO; } - if (!(wc = kmalloc(sizeof(*wc), GFP_KERNEL))) { + wc = kzalloc(sizeof(*wc), GFP_KERNEL); + if (!wc) + return -ENOMEM; + + wc->ddev = dahdi_create_device(); + if (!wc->ddev) { + kfree(wc); return -ENOMEM; } - memset(wc, 0x0, sizeof(*wc)); spin_lock_init(&wc->reglock); wc->devtype = (const struct devtype *)(ent->driver_data); @@ -4355,9 +4355,12 @@ static int t4_hardware_stop(struct t4 *wc) static void _t4_remove_one(struct t4 *wc) { - struct dahdi_span *span; int basesize; - int i; + + if (!wc) + return; + + dahdi_unregister_device(wc->ddev); remove_sysfs_files(wc); @@ -4376,11 +4379,6 @@ static void _t4_remove_one(struct t4 *wc) if (!(wc->tspans[0]->spanflags & FLAG_2NDGEN)) basesize = basesize * 2; - for (i = 0; i < wc->numspans; ++i) { - span = &wc->tspans[i]->span; - if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) - dahdi_unregister(span); - } #ifdef ENABLE_WORKQUEUES if (wc->workq) { flush_workqueue(wc->workq); diff --git a/drivers/dahdi/wctdm.c b/drivers/dahdi/wctdm.c index 0e81c84..5b13fee 100644 --- a/drivers/dahdi/wctdm.c +++ b/drivers/dahdi/wctdm.c @@ -205,6 +205,7 @@ struct wctdm { struct pci_dev *dev; char *variety; struct dahdi_span span; + struct dahdi_device *ddev; unsigned char ios; int usecount; unsigned int intcount; @@ -2362,13 +2363,26 @@ static int wctdm_initialize(struct wctdm *wc) { int x; + wc->ddev = dahdi_create_device(); + if (!wc->ddev) + return -ENOMEM; + /* DAHDI stuff */ sprintf(wc->span.name, "WCTDM/%d", wc->pos); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1); - snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); - wc->span.manufacturer = "Digium"; - strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); + wc->ddev->location = kasprintf(GFP_KERNEL, + "PCI Bus %02d Slot %02d", + wc->dev->bus->number, + PCI_SLOT(wc->dev->devfn) + 1); + if (!wc->ddev->location) { + dahdi_free_device(wc->ddev); + wc->ddev = NULL; + return -ENOMEM; + } + + wc->ddev->manufacturer = "Digium"; + wc->ddev->devicetype = wc->variety; + if (alawoverride) { printk(KERN_INFO "ALAW override parameter detected. Device will be operating in ALAW\n"); wc->span.deflaw = DAHDI_LAW_ALAW; @@ -2388,8 +2402,12 @@ static int wctdm_initialize(struct wctdm *wc) wc->span.flags = DAHDI_FLAG_RBS; wc->span.ops = &wctdm_span_ops; - if (dahdi_register(&wc->span, 0)) { + list_add_tail(&wc->span.device_node, &wc->ddev->spans); + if (dahdi_register_device(wc->ddev, &wc->dev->dev)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); + wc->ddev = NULL; return -1; } return 0; @@ -2677,7 +2695,9 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic release_region(wc->ioaddr, 0xff); pci_free_consistent(pdev, DAHDI_MAX_CHUNKSIZE * 2 * 2 * 2 * 4, (void *)wc->writechunk, wc->writedma); pci_set_drvdata(pdev, NULL); - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); return -EIO; @@ -2708,10 +2728,14 @@ static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_devic static void wctdm_release(struct wctdm *wc) { - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); if (wc->freeregion) release_region(wc->ioaddr, 0xff); + + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); + printk(KERN_INFO "Freed a Wildcard\n"); } diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c index 034a908..aabee02 100644 --- a/drivers/dahdi/wctdm24xxp/base.c +++ b/drivers/dahdi/wctdm24xxp/base.c @@ -4366,6 +4366,32 @@ wctdm_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype) return wctdm_wait_for_ready(wc); } +/* + * wctdm24xxp_assigned - Called when span is assigned. + * @span: The span that is now assigned. + * + * This function is called by the core of DAHDI after the span number and + * channel numbers have been assigned. + * + */ +static void wctdm24xxp_assigned(struct dahdi_span *span) +{ + struct dahdi_span *s; + struct dahdi_device *ddev = span->parent; + struct wctdm *wc = NULL; + + list_for_each_entry(s, &ddev->spans, device_node) { + wc = (container_of(s, struct wctdm_span, span))->wc; + if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags)) + return; + } + + if (wc) { + WARN_ON(0 == wc->not_ready); + --wc->not_ready; + } +} + static const struct dahdi_span_ops wctdm24xxp_analog_span_ops = { .owner = THIS_MODULE, .hooksig = wctdm_hooksig, @@ -4375,6 +4401,7 @@ static const struct dahdi_span_ops wctdm24xxp_analog_span_ops = { .watchdog = wctdm_watchdog, .chanconfig = wctdm_chanconfig, .dacs = wctdm_dacs, + .assigned = wctdm24xxp_assigned, #ifdef VPM_SUPPORT .enable_hw_preechocan = wctdm_enable_hw_preechocan, .disable_hw_preechocan = wctdm_disable_hw_preechocan, @@ -4393,6 +4420,7 @@ static const struct dahdi_span_ops wctdm24xxp_digital_span_ops = { .spanconfig = b400m_spanconfig, .chanconfig = b400m_chanconfig, .dacs = wctdm_dacs, + .assigned = wctdm24xxp_assigned, #ifdef VPM_SUPPORT .enable_hw_preechocan = wctdm_enable_hw_preechocan, .disable_hw_preechocan = wctdm_disable_hw_preechocan, @@ -4473,11 +4501,6 @@ wctdm_init_span(struct wctdm *wc, int spanno, int chanoffset, int chancount, sprintf(s->span.name, "WCTDM/%d", card_position); snprintf(s->span.desc, sizeof(s->span.desc) - 1, "%s", wc->desc->name); - snprintf(s->span.location, sizeof(s->span.location) - 1, - "PCI%s Bus %02d Slot %02d", - (wc->desc->flags & FLAG_EXPRESS) ? " Express" : "", - pdev->bus->number, PCI_SLOT(pdev->devfn) + 1); - s->span.manufacturer = "Digium"; if (wc->companding == DAHDI_LAW_DEFAULT) { if (wc->digi_mods || digital_span) @@ -4966,9 +4989,10 @@ static void wctdm_back_out_gracefully(struct wctdm *wc) kfree(frame); } - - kfree(wc->board_name); + kfree(wc->ddev->devicetype); + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); } @@ -5564,27 +5588,6 @@ static void wctdm_allocate_irq_commands(struct wctdm *wc, unsigned int count) spin_unlock_irqrestore(&wc->reglock, flags); } -static void set_span_devicetype_string(struct wctdm *wc) -{ - unsigned int x; - - for (x = 0; x < ARRAY_SIZE(wc->spans); x++) { - struct dahdi_span *const s = &wc->spans[x]->span; - if (!s) - continue; - - strlcpy(s->devicetype, wc->desc->name, sizeof(s->devicetype)); - - if (wc->vpmadt032) { - strlcat(s->devicetype, " (VPMADT032)", - sizeof(s->devicetype)); - } else if (wc->vpmoct) { - strlcat(s->devicetype, " (VPMOCT032)", - sizeof(s->devicetype)); - } - } -} - #ifdef USE_ASYNC_INIT struct async_data { struct pci_dev *pdev; @@ -5852,27 +5855,56 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) wc->avchannels = curchan; - set_span_devicetype_string(wc); - #ifdef USE_ASYNC_INIT async_synchronize_cookie(cookie); #endif + wc->ddev = dahdi_create_device(); + wc->ddev->manufacturer = "Digium"; + wc->ddev->location = kasprintf(GFP_KERNEL, "PCI%s Bus %02d Slot %02d", + (wc->desc->flags & FLAG_EXPRESS) ? + " Express" : "", + pdev->bus->number, + PCI_SLOT(pdev->devfn) + 1); + if (!wc->ddev->location) { + wctdm_back_out_gracefully(wc); + return -ENOMEM; + } + + if (wc->vpmadt032) { + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s (VPMADT032)", + wc->desc->name); + } else if (wc->vpmoct) { + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s (VPMOCT032)", + wc->desc->name); + } else { + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s", + wc->desc->name); + } + + if (!wc->ddev->devicetype) { + wctdm_back_out_gracefully(wc); + return -ENOMEM; + } + /* We should be ready for DAHDI to come in now. */ for (i = 0; i < MAX_SPANS; ++i) { + struct dahdi_span *span; + if (!wc->spans[i]) continue; - if (dahdi_register(&wc->spans[i]->span, 0)) { - dev_notice(&wc->vb.pdev->dev, "Unable to register span %d with DAHDI\n", i); - while (i) - dahdi_unregister(&wc->spans[i--]->span); - wctdm_back_out_gracefully(wc); - return -1; - } + span = &wc->spans[i]->span; + + list_add_tail(&span->device_node, &wc->ddev->spans); } wctdm_allocate_irq_commands(wc, anamods * latency * 4); - wc->not_ready--; + + if (dahdi_register_device(wc->ddev, &wc->vb.pdev->dev)) { + dev_notice(&wc->vb.pdev->dev, "Unable to register device with DAHDI\n"); + wctdm_back_out_gracefully(wc); + return -1; + } dev_info(&wc->vb.pdev->dev, "Found a %s: %s (%d BRI spans, %d analog %s)\n", @@ -5924,12 +5956,8 @@ static void wctdm_release(struct wctdm *wc) { int i; - if (is_initialized(wc)) { - for (i = 0; i < MAX_SPANS; i++) { - if (wc->spans[i]) - dahdi_unregister(&wc->spans[i]->span); - } - } + if (is_initialized(wc)) + dahdi_unregister_device(wc->ddev); down(&ifacelock); for (i = 0; i < WC_MAX_IFACES; i++) diff --git a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h index c9ae58b..78e555c 100644 --- a/drivers/dahdi/wctdm24xxp/wctdm24xxp.h +++ b/drivers/dahdi/wctdm24xxp/wctdm24xxp.h @@ -297,6 +297,7 @@ struct wctdm { int not_ready; /* 0 when the entire card is ready to go */ unsigned long checkflag; /* Internal state flags and task bits */ int companding; + struct dahdi_device *ddev; }; static inline bool is_initialized(struct wctdm *wc) diff --git a/drivers/dahdi/wcte11xp.c b/drivers/dahdi/wcte11xp.c index c8067c7..b2eab8d 100644 --- a/drivers/dahdi/wcte11xp.c +++ b/drivers/dahdi/wcte11xp.c @@ -174,6 +174,7 @@ struct t1 { unsigned char ec_chunk1[32][DAHDI_CHUNKSIZE]; unsigned char ec_chunk2[32][DAHDI_CHUNKSIZE]; unsigned char tempo[33]; + struct dahdi_device *ddev; struct dahdi_span span; /* Span */ struct dahdi_chan *chans[32]; /* Channels */ }; @@ -340,10 +341,12 @@ static void t1xxp_release(struct t1 *wc) { unsigned int x; - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { kfree(wc->chans[x]); } + kfree(wc->ddev->location); + dahdi_free_device(wc->ddev); kfree(wc); printk(KERN_INFO "Freed a Wildcard\n"); } @@ -976,14 +979,21 @@ static int t1xxp_software_init(struct t1 *wc) } if (x >= WC_MAX_CARDS) return -1; + + wc->ddev = dahdi_create_device(); + t4_serial_setup(wc); wc->num = x; sprintf(wc->span.name, "WCT1/%d", wc->num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, wc->num); - wc->span.manufacturer = "Digium"; - strlcpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype)); - snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1); + wc->ddev->manufacturer = "Digium"; + wc->ddev->devicetype = wc->variety; + wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + wc->dev->bus->number, + PCI_SLOT(wc->dev->devfn) + 1); + if (!wc->ddev->location) + return -ENOMEM; + wc->span.irq = wc->dev->irq; if (wc->spantype == TYPE_E1) { if (unchannelized) @@ -1011,7 +1021,8 @@ static int t1xxp_software_init(struct t1 *wc) wc->chans[x]->chanpos = x + 1; } wc->span.ops = &t1xxp_span_ops; - if (dahdi_register(&wc->span, 0)) { + list_add_tail(&wc->span.device_node, &wc->ddev->spans); + if (dahdi_register_device(wc->ddev, &wc->dev->dev)) { printk(KERN_NOTICE "Unable to register span with DAHDI\n"); return -1; } diff --git a/drivers/dahdi/wcte12xp/base.c b/drivers/dahdi/wcte12xp/base.c index 6a6bf24..f6b2a48 100644 --- a/drivers/dahdi/wcte12xp/base.c +++ b/drivers/dahdi/wcte12xp/base.c @@ -755,7 +755,7 @@ static void __t1xxp_set_clear(struct t1 *wc) /* Calculate all states on all 24 channels using the channel flags, then write all 3 clear channel registers at once */ - for (i = 0; i < 24; i++) { + for (i = 0; i < wc->span.channels; i++) { offset = i/8; if (wc->span.chans[i]->flags & DAHDI_FLAG_CLEAR) reg[offset] |= 1 << (7 - (i % 8)); @@ -783,7 +783,7 @@ static void free_wc(struct t1 *wc) struct command *cmd; LIST_HEAD(list); - for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { + for (x = 0; x < ARRAY_SIZE(wc->chans); x++) { kfree(wc->chans[x]); kfree(wc->ec[x]); } @@ -808,14 +808,14 @@ static void free_wc(struct t1 *wc) } #endif + kfree(wc->ddev->location); + kfree(wc->ddev->devicetype); + dahdi_free_device(wc->ddev); kfree(wc); } static void t4_serial_setup(struct t1 *wc) { - t1_info(wc, "Setting up global serial parameters for %s\n", - ((wc->spantype == TYPE_E1) ? "E1" : "T1")); - t1_setreg(wc, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */ t1_setreg(wc, 0x08, 0x05); /* IPC: Interrupt push/pull active low */ @@ -1009,12 +1009,12 @@ static void t1_configure_e1(struct t1 *wc, int lineconfig) t1_info(wc, "Span configured for %s/%s%s\n", framing, line, crc4); } -static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) +static void t1xxp_framer_start(struct t1 *wc) { - if (wc->spantype == TYPE_E1) { /* if this is an E1 card */ - t1_configure_e1(wc, span->lineconfig); + if (dahdi_is_e1_span(&wc->span)) { + t1_configure_e1(wc, wc->span.lineconfig); } else { /* is a T1 card */ - t1_configure_t1(wc, span->lineconfig, span->txlevel); + t1_configure_t1(wc, wc->span.lineconfig, wc->span.txlevel); __t1xxp_set_clear(wc); } @@ -1023,18 +1023,28 @@ static void t1xxp_framer_start(struct t1 *wc, struct dahdi_span *span) static void set_span_devicetype(struct t1 *wc) { - strncpy(wc->span.devicetype, wc->variety, - sizeof(wc->span.devicetype) - 1); + const char *olddevicetype; + olddevicetype = wc->ddev->devicetype; #if defined(VPM_SUPPORT) if (wc->vpmadt032) { - strncat(wc->span.devicetype, " (VPMADT032)", - sizeof(wc->span.devicetype) - 1); + wc->ddev->devicetype = kasprintf(GFP_KERNEL, + "%s (VPMADT032)", wc->variety); } else if (wc->vpmoct) { - strncat(wc->span.devicetype, " (VPMOCT032)", - sizeof(wc->span.devicetype) - 1); + wc->ddev->devicetype = kasprintf(GFP_KERNEL, + "%s (VPMOCT032)", wc->variety); + } else { + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s", wc->variety); } +#else + wc->ddev->devicetype = kasprintf(GFP_KERNEL, "%s", wc->variety); #endif + + /* On the off chance that we were able to allocate it previously. */ + if (!wc->ddev->devicetype) + wc->ddev->devicetype = olddevicetype; + else + kfree(olddevicetype); } static int t1xxp_startup(struct file *file, struct dahdi_span *span) @@ -1055,7 +1065,7 @@ static int t1xxp_startup(struct file *file, struct dahdi_span *span) #endif /* Reset framer with proper parameters and start */ - t1xxp_framer_start(wc, span); + t1xxp_framer_start(wc); debug_printk(wc, 1, "Calling startup (flags is %lu)\n", span->flags); return 0; @@ -1095,7 +1105,7 @@ static int t1xxp_chanconfig(struct file *file, } if (test_bit(DAHDI_FLAGBIT_RUNNING, &chan->span->flags) && - (wc->spantype != TYPE_E1)) { + dahdi_is_t1_span(&wc->span)) { __t1xxp_set_clear(wc); } return 0; @@ -1110,7 +1120,7 @@ static int t1xxp_rbsbits(struct dahdi_chan *chan, int bits) debug_printk(wc, 2, "Setting bits to %d on channel %s\n", bits, chan->name); - if (wc->spantype == TYPE_E1) { /* do it E1 way */ + if (dahdi_is_e1_span(&wc->span)) { /* do it E1 way */ if (chan->chanpos == 16) return 0; @@ -1163,7 +1173,7 @@ static inline void t1_check_sigbits(struct t1 *wc) if (!(test_bit(DAHDI_FLAGBIT_RUNNING, &wc->span.flags))) return; - if (wc->spantype == TYPE_E1) { + if (dahdi_is_e1_span(&wc->span)) { for (i = 0; i < 15; i++) { a = t1_getreg(wc, 0x71 + i); if (a > -1) { @@ -1258,7 +1268,7 @@ static void t1xxp_maint_work(struct work_struct *work) int reg = 0; int cmd = w->cmd; - if (wc->spantype == TYPE_E1) { + if (dahdi_is_e1_span(&wc->span)) { switch (cmd) { case DAHDI_MAINT_NONE: t1_info(wc, "Clearing all maint modes\n"); @@ -1330,7 +1340,7 @@ static int t1xxp_maint(struct dahdi_span *span, int cmd) struct maint_work_struct *work; struct t1 *wc = container_of(span, struct t1, span); - if (wc->spantype == TYPE_E1) { + if (dahdi_is_e1_span(&wc->span)) { switch (cmd) { case DAHDI_MAINT_NONE: case DAHDI_MAINT_LOCALLOOP: @@ -1625,7 +1635,7 @@ static void check_and_load_vpm(struct t1 *wc) options.vpmnlptype = vpmnlptype; options.vpmnlpthresh = vpmnlpthresh; options.vpmnlpmaxsupp = vpmnlpmaxsupp; - options.channels = (TYPE_T1 == wc->spantype) ? 24 : 32; + options.channels = dahdi_is_t1_span(&wc->span) ? 24 : 32; /* We do not want to check that the VPM is alive until after we're * done setting it up here, an hour should cover it... */ @@ -1685,7 +1695,7 @@ static void t1_chan_set_sigcap(struct dahdi_span *span, int x) struct dahdi_chan *chan = wc->chans[x]; chan->sigcap = DAHDI_SIG_CLEAR; /* E&M variant supported depends on span type */ - if (wc->spantype == TYPE_E1) { + if (dahdi_is_e1_span(&wc->span)) { /* E1 sigcap setup */ if (span->lineconfig & DAHDI_CONFIG_CCS) { /* CCS setup */ @@ -1784,9 +1794,19 @@ static const struct dahdi_span_ops t1_span_ops = { #endif }; -static int t1_software_init(struct t1 *wc) +/** + * t1_software_init - Initialize the board for the given type. + * @wc: The board to initialize. + * @type: The type of board we are, T1 / E1 + * + * This function is called at startup and when the type of the span is changed + * via the dahdi_device before the span is assigned a number. + * + */ +static int t1_software_init(struct t1 *wc, enum linemode type) { int x; + int res; int num; struct pci_dev *pdev = wc->vb.pdev; @@ -1801,21 +1821,23 @@ static int t1_software_init(struct t1 *wc) if (x == ARRAY_SIZE(ifaces)) return -1; - t4_serial_setup(wc); num = x; sprintf(wc->span.name, "WCT1/%d", num); snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Card %d", wc->variety, num); - wc->span.manufacturer = "Digium"; + wc->ddev->manufacturer = "Digium"; set_span_devicetype(wc); - snprintf(wc->span.location, sizeof(wc->span.location) - 1, - "PCI Bus %02d Slot %02d", pdev->bus->number, - PCI_SLOT(pdev->devfn) + 1); + wc->ddev->location = kasprintf(GFP_KERNEL, "PCI Bus %02d Slot %02d", + pdev->bus->number, + PCI_SLOT(pdev->devfn) + 1); + + if (!wc->ddev->location) + return -ENOMEM; wc->span.irq = pdev->irq; - if (wc->spantype == TYPE_E1) { + if (type == E1) { wc->span.channels = 31; wc->span.spantype = "E1"; wc->span.linecompat = DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3 | @@ -1828,6 +1850,11 @@ static int t1_software_init(struct t1 *wc) DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF; wc->span.deflaw = DAHDI_LAW_MULAW; } + + t1_info(wc, "Setting up global serial parameters for %s\n", + (dahdi_is_e1_span(&wc->span) ? "E1" : "T1")); + + t4_serial_setup(wc); wc->span.chans = wc->chans; set_bit(DAHDI_FLAGBIT_RBS, &wc->span.flags); for (x = 0; x < wc->span.channels; x++) { @@ -1840,9 +1867,11 @@ static int t1_software_init(struct t1 *wc) check_and_load_vpm(wc); wc->span.ops = &t1_span_ops; - if (dahdi_register(&wc->span, 0)) { - t1_info(wc, "Unable to register span with DAHDI\n"); - return -1; + list_add_tail(&wc->span.device_node, &wc->ddev->spans); + res = dahdi_register_device(wc->ddev, &wc->vb.pdev->dev); + if (res) { + t1_info(wc, "Unable to register with DAHDI\n"); + return res; } return 0; @@ -1864,7 +1893,7 @@ static inline unsigned char t1_vpm_out(struct t1 *wc, int unit, const unsigned i #endif #endif -static int t1_hardware_post_init(struct t1 *wc) +static int t1_hardware_post_init(struct t1 *wc, enum linemode *type) { int res; int reg; @@ -1872,22 +1901,22 @@ static int t1_hardware_post_init(struct t1 *wc) /* T1 or E1 */ if (-1 != t1e1override) { - pr_info("t1e1override is deprecated. Please use 'spantype'.\n"); - wc->spantype = (t1e1override) ? TYPE_E1 : TYPE_T1; + pr_info("t1e1override is deprecated. Please use 'default_linemode'.\n"); + *type = (t1e1override) ? E1 : T1; } else { if (!strcasecmp(default_linemode, "e1")) { - wc->spantype = TYPE_E1; + *type = E1; } else if (!strcasecmp(default_linemode, "t1")) { - wc->spantype = TYPE_T1; + *type = T1; } else { u8 pins; res = t1_getpins(wc, &pins); if (res) return res; - wc->spantype = (pins & 0x01) ? TYPE_T1 : TYPE_E1; + *type = (pins & 0x01) ? T1 : E1; } } - debug_printk(wc, 1, "linemode: %s\n", 1 == wc->spantype ? "T1" : "E1"); + debug_printk(wc, 1, "linemode: %s\n", (*type == T1) ? "T1" : "E1"); /* what version of the FALC are we using? */ reg = t1_setreg(wc, 0x4a, 0xaa); @@ -1938,7 +1967,7 @@ static inline void t1_check_alarms(struct t1 *wc) /* And consider only carrier alarms */ wc->span.alarms &= (DAHDI_ALARM_RED | DAHDI_ALARM_BLUE | DAHDI_ALARM_NOTOPEN); - if (wc->spantype == TYPE_E1) { + if (dahdi_is_e1_span(&wc->span)) { if (c & 0x04) { /* No multiframe found, force RAI high after 400ms only if we haven't found a multiframe since last loss @@ -2555,6 +2584,7 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi unsigned int x; int res; unsigned int index = -1; + enum linemode type; for (x = 0; x < ARRAY_SIZE(ifaces); x++) { if (!ifaces[x]) { @@ -2582,6 +2612,7 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi ifaces[index] = wc; wc->ledstate = -1; + wc->ddev = dahdi_create_device(); spin_lock_init(&wc->reglock); INIT_LIST_HEAD(&wc->active_cmds); INIT_LIST_HEAD(&wc->pending_cmds); @@ -2656,14 +2687,14 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi return -EIO; } - res = t1_hardware_post_init(wc); + res = t1_hardware_post_init(wc, &type); if (res) { voicebus_release(&wc->vb); free_wc(wc); return res; } - for (x = 0; x < (wc->spantype == TYPE_E1 ? 31 : 24); x++) { + for (x = 0; x < ((E1 == type) ? 31 : 24); x++) { wc->chans[x] = kzalloc(sizeof(*wc->chans[x]), GFP_KERNEL); if (!wc->chans[x]) { free_wc(wc); @@ -2679,7 +2710,7 @@ static int __devinit te12xp_init_one(struct pci_dev *pdev, const struct pci_devi } } - res = t1_software_init(wc); + res = t1_software_init(wc, type); if (res) { voicebus_release(&wc->vb); free_wc(wc); @@ -2710,7 +2741,7 @@ static void __devexit te12xp_remove_one(struct pci_dev *pdev) if (!wc) return; - dahdi_unregister(&wc->span); + dahdi_unregister_device(wc->ddev); remove_sysfs_files(wc); diff --git a/drivers/dahdi/wcte12xp/wcte12xp.h b/drivers/dahdi/wcte12xp/wcte12xp.h index 507a43e..8ef4753 100644 --- a/drivers/dahdi/wcte12xp/wcte12xp.h +++ b/drivers/dahdi/wcte12xp/wcte12xp.h @@ -74,8 +74,10 @@ #define CMD_BYTE(slot, a, is_vpm) (slot*6)+(a*2)+is_vpm /* only even slots */ //TODO: make a separate macro -#define TYPE_T1 1 -#define TYPE_E1 2 +enum linemode { + T1 = 1, + E1, +}; struct command { struct list_head node; @@ -94,7 +96,6 @@ struct t1 { unsigned char txident; unsigned char rxident; unsigned char statreg; /* bit 0 = vpmadt032 int */ - int spantype; struct { unsigned int nmf:1; unsigned int sendingyellow:1; @@ -116,6 +117,7 @@ struct t1 { unsigned long alarmtimer; unsigned char ledstate; unsigned char vpm_check_count; + struct dahdi_device *ddev; struct dahdi_span span; /* Span */ struct dahdi_chan *chans[32]; /* Channels */ struct dahdi_echocan_state *ec[32]; /* Echocan state for channels */ diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c index 0734892..39fe67c 100644 --- a/drivers/dahdi/xpp/xbus-core.c +++ b/drivers/dahdi/xpp/xbus-core.c @@ -871,6 +871,86 @@ err: goto out; } +static int xbus_register_dahdi_device(xbus_t *xbus) +{ + int i; + int offset = 0; + + XBUS_NOTICE(xbus, "Entering %s\n", __func__); + xbus->ddev = dahdi_create_device(); + /* + * This actually describe the dahdi_spaninfo version 3 + * A bunch of unrelated data exported via a modified ioctl() + * What a bummer... + */ + xbus->ddev->manufacturer = "Xorcom Inc."; /* OK, that's obvious */ + /* span->spantype = "...."; set in card_dahdi_preregistration() */ + /* + * Yes, this basically duplicates information available + * from the description field. If some more is needed + * why not add it there? + * OK, let's add to the kernel more useless info. + */ + xbus->ddev->devicetype = kasprintf(GFP_KERNEL, "Astribank2"); + if (!xbus->ddev->devicetype) + return -ENOMEM; + + /* + * location is the only usefull new data item. + * For our devices it was available for ages via: + * - The legacy "/proc/xpp/XBUS-??/summary" (CONNECTOR=...) + * - The same info in "/proc/xpp/xbuses" + * - The modern "/sys/bus/astribanks/devices/xbus-??/connector" attribute + * So let's also export it via the newfangled "location" field. + */ + xbus->ddev->location = xbus->connector; + + /* + * Prepare the span list + */ + for (i = 0; i < MAX_XPDS; i++) { + xpd_t *xpd = xpd_of(xbus, i); + if (xpd && IS_PHONEDEV(xpd)) { + XPD_DBG(DEVICES, xpd, "offset=%d\n", offset); + xpd_dahdi_preregister(xpd, offset++); + } + } + if (dahdi_register_device(xbus->ddev, &xbus->astribank)) { + XBUS_ERR(xbus, "Failed to dahdi_register_device()\n"); + return -ENODEV; + } + for (i = 0; i < MAX_XPDS; i++) { + xpd_t *xpd = xpd_of(xbus, i); + if (xpd && IS_PHONEDEV(xpd)) { + XPD_DBG(DEVICES, xpd, "\n"); + xpd_dahdi_postregister(xpd); + } + } + return 0; +} + +static void xbus_unregister_dahdi_device(xbus_t *xbus) +{ + int i; + + XBUS_NOTICE(xbus, "%s\n", __func__); + for(i = 0; i < MAX_XPDS; i++) { + xpd_t *xpd = xpd_of(xbus, i); + xpd_dahdi_preunregister(xpd); + } + dahdi_unregister_device(xbus->ddev); + XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n", __func__); + kfree(xbus->ddev->devicetype); + xbus->ddev->devicetype = NULL; + xbus->ddev->location = NULL; + dahdi_free_device(xbus->ddev); + xbus->ddev = NULL; + for(i = 0; i < MAX_XPDS; i++) { + xpd_t *xpd = xpd_of(xbus, i); + xpd_dahdi_postunregister(xpd); + } +} + /* * This must be called from synchronous (non-interrupt) context * it returns only when all XPD's on the bus are detected and @@ -934,6 +1014,7 @@ void xbus_populate(void *data) */ xbus_request_sync(xbus, SYNC_MODE_PLL); elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */ + xbus_register_dahdi_device(xbus); out: XBUS_DBG(DEVICES, xbus, "Leaving\n"); wake_up_interruptible_all(&worker->wait_for_xpd_initialization); @@ -1206,12 +1287,12 @@ void xbus_deactivate(xbus_t *xbus) xbus_request_sync(xbus, SYNC_MODE_NONE); /* no more ticks */ elect_syncer("deactivate"); xbus_echocancel(xbus, 0); - xbus_request_removal(xbus); XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label); xbus_command_queue_clean(xbus); xbus_command_queue_waitempty(xbus); xbus_setstate(xbus, XBUS_STATE_DEACTIVATED); worker_reset(xbus); + xbus_unregister_dahdi_device(xbus); xbus_release_xpds(xbus); /* taken in xpd_alloc() [kref_init] */ } @@ -1788,10 +1869,6 @@ err: void xbus_core_shutdown(void) { - int i; - - for(i = 0; i < MAX_BUSES; i++) - BUG_ON(xbus_num(i)); xbus_core_cleanup(); xpp_driver_exit(); } diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h index 2149a38..6f4c672 100644 --- a/drivers/dahdi/xpp/xbus-core.h +++ b/drivers/dahdi/xpp/xbus-core.h @@ -188,6 +188,7 @@ struct xbus { char label[LABEL_SIZE]; byte revision; /* Protocol revision */ struct xbus_transport transport; + struct dahdi_device *ddev; int num; struct xpd *xpds[MAX_XPDS]; diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c index daf16fc..c9f78f9 100644 --- a/drivers/dahdi/xpp/xbus-sysfs.c +++ b/drivers/dahdi/xpp/xbus-sysfs.c @@ -623,29 +623,6 @@ static DEVICE_ATTR_READER(span_show, dev, buf) return len; } -static DEVICE_ATTR_WRITER(span_store, dev, buf, count) -{ - xpd_t *xpd; - int dahdi_reg; - int ret; - - BUG_ON(!dev); - xpd = dev_to_xpd(dev); - if(!xpd) - return -ENODEV; - ret = sscanf(buf, "%d", &dahdi_reg); - if(ret != 1) - return -EINVAL; - if(!XBUS_IS(xpd->xbus, READY)) - return -ENODEV; - XPD_DBG(GENERAL, xpd, "%s\n", (dahdi_reg) ? "register" : "unregister"); - if(dahdi_reg) - ret = dahdi_register_xpd(xpd); - else - ret = dahdi_unregister_xpd(xpd); - return (ret < 0) ? ret : count; -} - static DEVICE_ATTR_READER(type_show, dev, buf) { xpd_t *xpd; @@ -728,7 +705,7 @@ static int xpd_match(struct device *dev, struct device_driver *driver) static struct device_attribute xpd_dev_attrs[] = { __ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store), __ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store), - __ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store), + __ATTR_RO(span), __ATTR_RO(type), __ATTR_RO(offhook), __ATTR_RO(timing_priority), diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c index 0f186ef..f2c7314 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.c +++ b/drivers/dahdi/xpp/xpp_dahdi.c @@ -256,8 +256,8 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, void xpd_post_init(xpd_t *xpd) { XPD_DBG(DEVICES, xpd, "\n"); - if(dahdi_autoreg) - dahdi_register_xpd(xpd); + /* DEBUG if(dahdi_autoreg) */ + /* DEBUG dahdi_register_xpd(xpd); */ } #ifdef CONFIG_PROC_FS @@ -568,46 +568,6 @@ err: return NULL; } -/* - * Try our best to make asterisk close all channels related to - * this Astribank: - * - Set span state to DAHDI_ALARM_NOTOPEN in all relevant spans. - * - Notify dahdi afterwards about spans (so it can see all changes at once). - * - Also send DAHDI_EVENT_REMOVED on all channels. - */ -void xbus_request_removal(xbus_t *xbus) -{ - unsigned long flags; - int i; - - for(i = 0; i < MAX_XPDS; i++) { - xpd_t *xpd = xpd_of(xbus, i); - if(xpd) { - XPD_DBG(DEVICES, xpd, "\n"); - spin_lock_irqsave(&xpd->lock, flags); - xpd->card_present = 0; - xpd_setstate(xpd, XPD_STATE_NOHW); - PHONEDEV(xpd).span.alarms = DAHDI_ALARM_NOTOPEN; - spin_unlock_irqrestore(&xpd->lock, flags); - } - } - /* Now notify dahdi */ - for(i = 0; i < MAX_XPDS; i++) { - xpd_t *xpd = xpd_of(xbus, i); - if(xpd) { - if(SPAN_REGISTERED(xpd)) { - int j; - - dahdi_alarm_notify(&PHONEDEV(xpd).span); - XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n"); - for (j=0; jlock, flags); - - if (!IS_PHONEDEV(xpd)) { - XPD_ERR(xpd, "Not a telephony device\n"); - spin_unlock_irqrestore(&xpd->lock, flags); - return -EBADF; - } - if(!SPAN_REGISTERED(xpd)) { - XPD_NOTICE(xpd, "Already unregistered\n"); - spin_unlock_irqrestore(&xpd->lock, flags); - return -EIDRM; - } - update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN); - mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish. - spin_unlock_irqrestore(&xpd->lock, flags); - if(xpd->card_present) - CALL_PHONE_METHOD(card_dahdi_preregistration, xpd, 0); - atomic_dec(&PHONEDEV(xpd).dahdi_registered); - atomic_dec(&num_registered_spans); - dahdi_unregister(&PHONEDEV(xpd).span); - if(xpd->card_present) - CALL_PHONE_METHOD(card_dahdi_postregistration, xpd, 0); - return 0; -} - static const struct dahdi_span_ops xpp_span_ops = { .owner = THIS_MODULE, .open = xpp_open, @@ -1055,12 +972,39 @@ static const struct dahdi_span_ops xpp_rbs_span_ops = { .echocan_name = xpp_echocan_name, }; -int dahdi_register_xpd(xpd_t *xpd) +static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn) { struct dahdi_span *span; + int i; + + XPD_NOTICE(xpd, "Initializing span(offset=%d): %d channels.\n", offset, cn); + memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span)); + for (i = 0; i < cn; i++) + memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan)); + + span = &PHONEDEV(xpd).span; + snprintf(span->name, MAX_SPANNAME, "%s/%s", xpd->xbus->busname, xpd->xpdname); + span->deflaw = DAHDI_LAW_MULAW; /* default, may be overriden by card_* drivers */ + span->channels = cn; + span->chans = PHONEDEV(xpd).chans; + + span->flags = DAHDI_FLAG_RBS; + span->offset = offset; + if (PHONEDEV(xpd).phoneops->card_hooksig) + span->ops = &xpp_rbs_span_ops; /* Only with RBS bits */ + else + span->ops = &xpp_span_ops; + + snprintf(PHONEDEV(xpd).span.desc, MAX_SPANDESC, "Xorcom XPD #%02d/%1d%1d: %s", + xpd->xbus->num, xpd->addr.unit, xpd->addr.subunit, xpd->type_name); + list_add_tail(&span->device_node, &xpd->xbus->ddev->spans); +} + +int xpd_dahdi_preregister(xpd_t *xpd, unsigned offset) +{ xbus_t *xbus; int cn; - int i; + struct phonedev *phonedev; BUG_ON(!xpd); @@ -1070,70 +1014,25 @@ int dahdi_register_xpd(xpd_t *xpd) XPD_ERR(xpd, "Not a telephony device\n"); return -EBADF; } + + phonedev = &PHONEDEV(xpd); + if (SPAN_REGISTERED(xpd)) { XPD_ERR(xpd, "Already registered\n"); return -EEXIST; } + cn = PHONEDEV(xpd).channels; - XPD_DBG(DEVICES, xpd, "Initializing span: %d channels.\n", cn); - memset(&PHONEDEV(xpd).span, 0, sizeof(struct dahdi_span)); - for(i = 0; i < cn; i++) { - memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan)); - } - - span = &PHONEDEV(xpd).span; - snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname); - span->deflaw = DAHDI_LAW_MULAW; /* default, may be overriden by card_* drivers */ - span->channels = cn; - span->chans = PHONEDEV(xpd).chans; - - span->flags = DAHDI_FLAG_RBS; - if(PHONEDEV(xpd).phoneops->card_hooksig) - span->ops = &xpp_rbs_span_ops; /* Only with RBS bits */ - else - span->ops = &xpp_span_ops; - - /* - * This actually describe the dahdi_spaninfo version 3 - * A bunch of unrelated data exported via a modified ioctl() - * What a bummer... - */ - span->manufacturer = "Xorcom Inc."; /* OK, that's obvious */ - /* span->spantype = "...."; set in card_dahdi_preregistration() */ - /* - * Yes, this basically duplicates information available - * from the description field. If some more is needed - * why not add it there? - * OK, let's add to the kernel more useless info. - */ - snprintf(span->devicetype, sizeof(span->devicetype) - 1, - "Astribank: Unit %x Subunit %x: %s", - XBUS_UNIT(xpd->xbus_idx), XBUS_SUBUNIT(xpd->xbus_idx), - xpd->type_name); - /* - * location is the only usefull new data item. - * For our devices it was available for ages via: - * - The legacy "/proc/xpp/XBUS-??/summary" (CONNECTOR=...) - * - The same info in "/proc/xpp/xbuses" - * - The modern "/sys/bus/astribanks/devices/xbus-??/connector" attribute - * So let's also export it via the newfangled "location" field. - */ - snprintf(span->location, sizeof(span->location) - 1, "%s", xbus->connector); - /* - * Who said a span and irq have 1-1 relationship? - * Also exporting this low-level detail isn't too wise. - * No irq's for you today! - */ - span->irq = 0; - - snprintf(PHONEDEV(xpd).span.desc, MAX_SPANDESC, "Xorcom XPD #%02d/%1d%1d: %s", - xbus->num, xpd->addr.unit, xpd->addr.subunit, xpd->type_name); + xpd_init_span(xpd, offset, cn); XPD_DBG(GENERAL, xpd, "Registering span '%s'\n", PHONEDEV(xpd).span.desc); CALL_PHONE_METHOD(card_dahdi_preregistration, xpd, 1); - if(dahdi_register(&PHONEDEV(xpd).span, prefmaster)) { - XPD_ERR(xpd, "Failed to dahdi_register span\n"); - return -ENODEV; - } + return 0; +} + +int xpd_dahdi_postregister(xpd_t *xpd) +{ + int cn; + atomic_inc(&num_registered_spans); atomic_inc(&PHONEDEV(xpd).dahdi_registered); CALL_PHONE_METHOD(card_dahdi_postregistration, xpd, 1); @@ -1153,6 +1052,48 @@ int dahdi_register_xpd(xpd_t *xpd) return 0; } +/* + * Try our best to make asterisk close all channels related to + * this Astribank: + * - Set span state to DAHDI_ALARM_NOTOPEN in all relevant spans. + * - Notify dahdi afterwards about spans (so it can see all changes at once). + * - Also send DAHDI_EVENT_REMOVED on all channels. + */ +void xpd_dahdi_preunregister(xpd_t *xpd) +{ + unsigned long flags; + if (!xpd) + return; + XPD_DBG(DEVICES, xpd, "\n"); + spin_lock_irqsave(&xpd->lock, flags); + xpd->card_present = 0; + xpd_setstate(xpd, XPD_STATE_NOHW); + spin_unlock_irqrestore(&xpd->lock, flags); + update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN); + if(xpd->card_present) + CALL_PHONE_METHOD(card_dahdi_preregistration, xpd, 0); + /* Now notify dahdi */ + if(SPAN_REGISTERED(xpd)) { + int j; + + dahdi_alarm_notify(&PHONEDEV(xpd).span); + XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n"); + for (j=0; jcard_present) + CALL_PHONE_METHOD(card_dahdi_postregistration, xpd, 0); +} + /*------------------------- Initialization -------------------------*/ static void do_cleanup(void) @@ -1217,7 +1158,6 @@ EXPORT_SYMBOL(get_xpd); EXPORT_SYMBOL(put_xpd); EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_free); -EXPORT_SYMBOL(xbus_request_removal); EXPORT_SYMBOL(update_xpd_status); EXPORT_SYMBOL(oht_pcm); EXPORT_SYMBOL(mark_offhook); diff --git a/drivers/dahdi/xpp/xpp_dahdi.h b/drivers/dahdi/xpp/xpp_dahdi.h index 01f4a24..cb76846 100644 --- a/drivers/dahdi/xpp/xpp_dahdi.h +++ b/drivers/dahdi/xpp/xpp_dahdi.h @@ -25,9 +25,10 @@ #include "xpd.h" #include "xproto.h" -int dahdi_register_xpd(xpd_t *xpd); -int dahdi_unregister_xpd(xpd_t *xpd); -void xbus_request_removal(xbus_t *xbus); +int xpd_dahdi_preregister(xpd_t *xpd, unsigned offset); +int xpd_dahdi_postregister(xpd_t *xpd); +void xpd_dahdi_preunregister(xpd_t *xpd); +void xpd_dahdi_postunregister(xpd_t *xpd); int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int unit, int subunit, byte type, byte subtype, int subunits, int subunit_ports, byte port_dir); void xpd_post_init(xpd_t *xpd); diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h index 9ae9d1e..9dec702 100644 --- a/include/dahdi/kernel.h +++ b/include/dahdi/kernel.h @@ -42,7 +42,7 @@ #include #endif #include -#include +#include #include #ifdef CONFIG_DAHDI_NET @@ -885,6 +885,26 @@ struct dahdi_span_ops { /*! Opt: Provide the name of the echo canceller on a channel */ const char *(*echocan_name)(const struct dahdi_chan *chan); + + /*! When using "pinned_spans", this function is called back when this + * span has been assigned with the system. */ + void (*assigned)(struct dahdi_span *span); +}; + +/** + * dahdi_device - Represents a device that can contain one or more spans. + * + * @spans: List of child spans. + * @manufacturer: Device manufacturer. + * @location: The location of this device + * @devicetype: What type of device this is. + * + */ +struct dahdi_device { + struct list_head spans; + const char *manufacturer; + const char *location; + const char *devicetype; }; struct dahdi_span { @@ -892,9 +912,6 @@ struct dahdi_span { char name[40]; /*!< Span name */ char desc[80]; /*!< Span description */ const char *spantype; /*!< span type in text form */ - const char *manufacturer; /*!< span's device manufacturer */ - char devicetype[80]; /*!< span's device type */ - char location[40]; /*!< span device's location in system */ int deflaw; /*!< Default law (DAHDI_MULAW or DAHDI_ALAW) */ int alarms; /*!< Pending alarms on span */ unsigned long flags; @@ -933,7 +950,10 @@ struct dahdi_span { #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; #endif - struct list_head node; + struct list_head spans_node; + + struct dahdi_device *parent; + struct list_head device_node; }; struct dahdi_transcoder_channel { @@ -1031,6 +1051,7 @@ struct dahdi_dynamic { long rxjif; unsigned short txcnt; unsigned short rxcnt; + struct dahdi_device *ddev; struct dahdi_span span; struct dahdi_chan *chans[256]; struct dahdi_dynamic_driver *driver; @@ -1038,6 +1059,7 @@ struct dahdi_dynamic { int timing; int master; unsigned char *msgbuf; + struct device *dev; struct list_head list; }; @@ -1131,10 +1153,11 @@ void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes); * and 1 if the currently transmitted message is now done */ int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size); - -/*! Register a span. Returns 0 on success, -1 on failure. Pref-master is non-zero if - we should have preference in being the master device */ -int dahdi_register(struct dahdi_span *span, int prefmaster); +/*! Register a device. Returns 0 on success, -1 on failure. */ +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); /*! Allocate / free memory for a transcoder */ struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans); @@ -1149,9 +1172,6 @@ int dahdi_transcoder_unregister(struct dahdi_transcoder *tc); /*! \brief Alert a transcoder */ int dahdi_transcoder_alert(struct dahdi_transcoder_channel *ztc); -/*! \brief Unregister a span */ -int dahdi_unregister(struct dahdi_span *span); - /*! \brief Gives a name to an LBO */ const char *dahdi_lboname(int lbo);