diff options
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r-- | drivers/uio/uio.c | 164 |
1 files changed, 70 insertions, 94 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index bff1afb..a858d2b 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -23,9 +23,10 @@ #include <linux/sched.h> #include <linux/string.h> #include <linux/kobject.h> +#include <linux/cdev.h> #include <linux/uio_driver.h> -#define UIO_MAX_DEVICES 255 +#define UIO_MAX_DEVICES (1U << MINORBITS) struct uio_device { struct module *owner; @@ -41,15 +42,10 @@ struct uio_device { }; static int uio_major; +static struct cdev *uio_cdev; static DEFINE_IDR(uio_idr); static const struct file_operations uio_fops; -/* UIO class infrastructure */ -static struct uio_class { - struct kref kref; - struct class *class; -} *uio_class; - /* Protect idr accesses */ static DEFINE_MUTEX(minor_lock); @@ -232,45 +228,34 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%s\n", idev->info->name); - else - return -ENODEV; + return sprintf(buf, "%s\n", idev->info->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%s\n", idev->info->version); - else - return -ENODEV; + return sprintf(buf, "%s\n", idev->info->version); } -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%u\n", - (unsigned int)atomic_read(&idev->event)); - else - return -ENODEV; + return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); } -static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); -static struct attribute *uio_attrs[] = { - &dev_attr_name.attr, - &dev_attr_version.attr, - &dev_attr_event.attr, - NULL, +static struct device_attribute uio_class_attributes[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(version, S_IRUGO, show_version, NULL), + __ATTR(event, S_IRUGO, show_event, NULL), + {} }; -static struct attribute_group uio_attr_grp = { - .attrs = uio_attrs, +/* UIO class infrastructure */ +static struct class uio_class = { + .name = "uio", + .dev_attrs = uio_class_attributes, }; /* @@ -287,10 +272,6 @@ static int uio_dev_add_attributes(struct uio_device *idev) struct uio_port *port; struct uio_portio *portio; - ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); - if (ret) - goto err_group; - for (mi = 0; mi < MAX_UIO_MAPS; mi++) { mem = &idev->info->mem[mi]; if (mem->size == 0) @@ -358,8 +339,6 @@ err_map: kobject_put(&map->kobj); } kobject_put(idev->map_dir); - sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); -err_group: dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); return ret; } @@ -385,8 +364,6 @@ static void uio_dev_del_attributes(struct uio_device *idev) kobject_put(&port->portio->kobj); } kobject_put(idev->portio_dir); - - sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); } static int uio_get_minor(struct uio_device *idev) @@ -525,7 +502,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait) struct uio_listener *listener = filep->private_data; struct uio_device *idev = listener->dev; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; poll_wait(filep, &idev->wait, wait); @@ -543,7 +520,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf, ssize_t retval; s32 event_count; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; if (count != sizeof(s32)) @@ -591,7 +568,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, ssize_t retval; s32 irq_on; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; if (count != sizeof(s32)) @@ -740,72 +717,77 @@ static const struct file_operations uio_fops = { .mmap = uio_mmap, .poll = uio_poll, .fasync = uio_fasync, + .llseek = noop_llseek, }; static int uio_major_init(void) { - uio_major = register_chrdev(0, "uio", &uio_fops); - if (uio_major < 0) - return uio_major; - return 0; + static const char name[] = "uio"; + struct cdev *cdev = NULL; + dev_t uio_dev = 0; + int result; + + result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); + if (result) + goto out; + + result = -ENOMEM; + cdev = cdev_alloc(); + if (!cdev) + goto out_unregister; + + cdev->owner = THIS_MODULE; + cdev->ops = &uio_fops; + kobject_set_name(&cdev->kobj, "%s", name); + + result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); + if (result) + goto out_put; + + uio_major = MAJOR(uio_dev); + uio_cdev = cdev; + result = 0; +out: + return result; +out_put: + kobject_put(&cdev->kobj); +out_unregister: + unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); + goto out; } static void uio_major_cleanup(void) { - unregister_chrdev(uio_major, "uio"); + unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); + cdev_del(uio_cdev); } static int init_uio_class(void) { - int ret = 0; - - if (uio_class != NULL) { - kref_get(&uio_class->kref); - goto exit; - } + int ret; /* This is the first time in here, set everything up properly */ ret = uio_major_init(); if (ret) goto exit; - uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); - if (!uio_class) { - ret = -ENOMEM; - goto err_kzalloc; - } - - kref_init(&uio_class->kref); - uio_class->class = class_create(THIS_MODULE, "uio"); - if (IS_ERR(uio_class->class)) { - ret = IS_ERR(uio_class->class); - printk(KERN_ERR "class_create failed for uio\n"); - goto err_class_create; + ret = class_register(&uio_class); + if (ret) { + printk(KERN_ERR "class_register failed for uio\n"); + goto err_class_register; } return 0; -err_class_create: - kfree(uio_class); - uio_class = NULL; -err_kzalloc: +err_class_register: uio_major_cleanup(); exit: return ret; } -static void release_uio_class(struct kref *kref) +static void release_uio_class(void) { - /* Ok, we cheat as we know we only have one uio_class */ - class_destroy(uio_class->class); - kfree(uio_class); + class_unregister(&uio_class); uio_major_cleanup(); - uio_class = NULL; -} - -static void uio_class_destroy(void) -{ - if (uio_class) - kref_put(&uio_class->kref, release_uio_class); } /** @@ -828,10 +810,6 @@ int __uio_register_device(struct module *owner, info->uio_dev = NULL; - ret = init_uio_class(); - if (ret) - return ret; - idev = kzalloc(sizeof(*idev), GFP_KERNEL); if (!idev) { ret = -ENOMEM; @@ -847,7 +825,7 @@ int __uio_register_device(struct module *owner, if (ret) goto err_get_minor; - idev->dev = device_create(uio_class->class, parent, + idev->dev = device_create(&uio_class, parent, MKDEV(uio_major, idev->minor), idev, "uio%d", idev->minor); if (IS_ERR(idev->dev)) { @@ -862,9 +840,9 @@ int __uio_register_device(struct module *owner, info->uio_dev = idev; - if (idev->info->irq >= 0) { - ret = request_irq(idev->info->irq, uio_interrupt, - idev->info->irq_flags, idev->info->name, idev); + if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { + ret = request_irq(info->irq, uio_interrupt, + info->irq_flags, info->name, idev); if (ret) goto err_request_irq; } @@ -874,13 +852,12 @@ int __uio_register_device(struct module *owner, err_request_irq: uio_dev_del_attributes(idev); err_uio_dev_add_attributes: - device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); + device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); err_device_create: uio_free_minor(idev); err_get_minor: kfree(idev); err_kzalloc: - uio_class_destroy(); return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); @@ -901,15 +878,13 @@ void uio_unregister_device(struct uio_info *info) uio_free_minor(idev); - if (info->irq >= 0) + if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) free_irq(info->irq, idev); uio_dev_del_attributes(idev); - dev_set_drvdata(idev->dev, NULL); - device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); + device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); kfree(idev); - uio_class_destroy(); return; } @@ -917,11 +892,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); static int __init uio_init(void) { - return 0; + return init_uio_class(); } static void __exit uio_exit(void) { + release_uio_class(); } module_init(uio_init) |