#include #include #define DAHDI_PRINK_MACROS_USE_debug #include #include #include #include "dahdi.h" /* FIXME: Move to kernel.h */ #define module_printk(level, fmt, args...) printk(level "%s: " fmt, THIS_MODULE->name, ## args) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) #define CLASS_DEV_CREATE(class, devt, device, name) \ device_create(class, device, devt, NULL, "%s", name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #define CLASS_DEV_CREATE(class, devt, device, name) \ device_create(class, device, devt, name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) #define CLASS_DEV_CREATE(class, devt, device, name) \ class_device_create(class, NULL, devt, device, name) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) #define CLASS_DEV_CREATE(class, devt, device, name) \ class_device_create(class, devt, device, name) #else #define CLASS_DEV_CREATE(class, devt, device, name) \ class_simple_device_add(class, devt, device, name) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) #define CLASS_DEV_DESTROY(class, devt) \ device_destroy(class, devt) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) #define CLASS_DEV_DESTROY(class, devt) \ class_device_destroy(class, devt) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9) #define CLASS_DEV_DESTROY(class, devt) \ class_simple_device_remove(devt) #else #define CLASS_DEV_DESTROY(class, devt) \ class_simple_device_remove(class, devt) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) static struct class *dahdi_class = NULL; #else static struct class_simple *dahdi_class = NULL; #define class_create class_simple_create #define class_destroy class_simple_destroy #endif int dahdi_register_chardev(struct dahdi_chardev *dev) { static const char *DAHDI_STRING = "dahdi!"; char *udevname; udevname = kzalloc(strlen(dev->name) + sizeof(DAHDI_STRING) + 1, GFP_KERNEL); if (!udevname) return -ENOMEM; strcpy(udevname, DAHDI_STRING); strcat(udevname, dev->name); CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor), NULL, udevname); kfree(udevname); return 0; } EXPORT_SYMBOL(dahdi_register_chardev); int dahdi_unregister_chardev(struct dahdi_chardev *dev) { CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, dev->minor)); return 0; } EXPORT_SYMBOL(dahdi_unregister_chardev); void span_sysfs_remove(struct dahdi_span *span) { int x; for (x = 0; x < span->channels; x++) { struct dahdi_chan *chan = span->chans[x]; if (!test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags)) continue; CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, chan->channo)); clear_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags); } } int span_sysfs_create(struct dahdi_span *span) { int res = 0; int x; for (x = 0; x < span->channels; x++) { struct dahdi_chan *chan = span->chans[x]; char chan_name[32]; void *dummy; if (chan->channo >= 250) continue; if (test_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags)) continue; snprintf(chan_name, sizeof(chan_name), "dahdi!%d", chan->channo); dummy = (void *)CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, chan->channo), NULL, chan_name); if (IS_ERR(dummy)) { res = PTR_ERR(dummy); chan_err(chan, "Failed creating sysfs device: %d\n", res); goto cleanup; } set_bit(DAHDI_FLAGBIT_DEVFILE, &chan->flags); } return 0; cleanup: span_sysfs_remove(span); return res; } #define MAKE_DAHDI_DEV(num, name) \ CLASS_DEV_CREATE(dahdi_class, MKDEV(DAHDI_MAJOR, num), NULL, name) #define DEL_DAHDI_DEV(num) \ CLASS_DEV_DESTROY(dahdi_class, MKDEV(DAHDI_MAJOR, num)) /* Only used to flag that the device exists: */ static struct { unsigned int ctl:1; unsigned int timer:1; unsigned int channel:1; unsigned int pseudo:1; } dummy_dev; void dahdi_sysfs_exit(void) { if (dummy_dev.pseudo) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/pseudo:\n"); DEL_DAHDI_DEV(DAHDI_PSEUDO); dummy_dev.pseudo = 0; } if (dummy_dev.channel) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/channel:\n"); DEL_DAHDI_DEV(DAHDI_CHANNEL); dummy_dev.channel = 0; } if (dummy_dev.timer) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/timer:\n"); DEL_DAHDI_DEV(DAHDI_TIMER); dummy_dev.timer = 0; } if (dummy_dev.ctl) { dahdi_dbg(DEVICES, "Removing /dev/dahdi/ctl:\n"); DEL_DAHDI_DEV(DAHDI_CTL); dummy_dev.ctl = 0; } if (dahdi_class) { dahdi_dbg(DEVICES, "Destroying DAHDI class:\n"); class_destroy(dahdi_class); dahdi_class = NULL; } unregister_chrdev(DAHDI_MAJOR, "dahdi"); } int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops) { int res = 0; void *dev; res = register_chrdev(DAHDI_MAJOR, "dahdi", dahdi_fops); if (res) { module_printk(KERN_ERR, "Unable to register DAHDI character device handler on %d\n", DAHDI_MAJOR); return res; } module_printk(KERN_INFO, "Telephony Interface Registered on major %d\n", DAHDI_MAJOR); module_printk(KERN_INFO, "Version: %s\n", DAHDI_VERSION); dahdi_class = class_create(THIS_MODULE, "dahdi"); if (!dahdi_class) { res = -EEXIST; goto cleanup; } dahdi_dbg(DEVICES, "Creating /dev/dahdi/timer:\n"); dev = MAKE_DAHDI_DEV(DAHDI_TIMER, "dahdi!timer"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.timer = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/channel:\n"); dev = MAKE_DAHDI_DEV(DAHDI_CHANNEL, "dahdi!channel"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.channel = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/pseudo:\n"); dev = MAKE_DAHDI_DEV(DAHDI_PSEUDO, "dahdi!pseudo"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.pseudo = 1; dahdi_dbg(DEVICES, "Creating /dev/dahdi/ctl:\n"); dev = MAKE_DAHDI_DEV(DAHDI_CTL, "dahdi!ctl"); if (IS_ERR(dev)) { res = PTR_ERR(dev); goto cleanup; } dummy_dev.ctl = 1; return 0; cleanup: dahdi_sysfs_exit(); return res; }