diff options
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r-- | drivers/uio/uio.c | 163 |
1 files changed, 69 insertions, 94 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 4d3a6fd1a152..a858d2b87b94 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -23,9 +23,10 @@ | |||
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/string.h> | 24 | #include <linux/string.h> |
25 | #include <linux/kobject.h> | 25 | #include <linux/kobject.h> |
26 | #include <linux/cdev.h> | ||
26 | #include <linux/uio_driver.h> | 27 | #include <linux/uio_driver.h> |
27 | 28 | ||
28 | #define UIO_MAX_DEVICES 255 | 29 | #define UIO_MAX_DEVICES (1U << MINORBITS) |
29 | 30 | ||
30 | struct uio_device { | 31 | struct uio_device { |
31 | struct module *owner; | 32 | struct module *owner; |
@@ -41,15 +42,10 @@ struct uio_device { | |||
41 | }; | 42 | }; |
42 | 43 | ||
43 | static int uio_major; | 44 | static int uio_major; |
45 | static struct cdev *uio_cdev; | ||
44 | static DEFINE_IDR(uio_idr); | 46 | static DEFINE_IDR(uio_idr); |
45 | static const struct file_operations uio_fops; | 47 | static const struct file_operations uio_fops; |
46 | 48 | ||
47 | /* UIO class infrastructure */ | ||
48 | static struct uio_class { | ||
49 | struct kref kref; | ||
50 | struct class *class; | ||
51 | } *uio_class; | ||
52 | |||
53 | /* Protect idr accesses */ | 49 | /* Protect idr accesses */ |
54 | static DEFINE_MUTEX(minor_lock); | 50 | static DEFINE_MUTEX(minor_lock); |
55 | 51 | ||
@@ -232,45 +228,34 @@ static ssize_t show_name(struct device *dev, | |||
232 | struct device_attribute *attr, char *buf) | 228 | struct device_attribute *attr, char *buf) |
233 | { | 229 | { |
234 | struct uio_device *idev = dev_get_drvdata(dev); | 230 | struct uio_device *idev = dev_get_drvdata(dev); |
235 | if (idev) | 231 | return sprintf(buf, "%s\n", idev->info->name); |
236 | return sprintf(buf, "%s\n", idev->info->name); | ||
237 | else | ||
238 | return -ENODEV; | ||
239 | } | 232 | } |
240 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
241 | 233 | ||
242 | static ssize_t show_version(struct device *dev, | 234 | static ssize_t show_version(struct device *dev, |
243 | struct device_attribute *attr, char *buf) | 235 | struct device_attribute *attr, char *buf) |
244 | { | 236 | { |
245 | struct uio_device *idev = dev_get_drvdata(dev); | 237 | struct uio_device *idev = dev_get_drvdata(dev); |
246 | if (idev) | 238 | return sprintf(buf, "%s\n", idev->info->version); |
247 | return sprintf(buf, "%s\n", idev->info->version); | ||
248 | else | ||
249 | return -ENODEV; | ||
250 | } | 239 | } |
251 | static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); | ||
252 | 240 | ||
253 | static ssize_t show_event(struct device *dev, | 241 | static ssize_t show_event(struct device *dev, |
254 | struct device_attribute *attr, char *buf) | 242 | struct device_attribute *attr, char *buf) |
255 | { | 243 | { |
256 | struct uio_device *idev = dev_get_drvdata(dev); | 244 | struct uio_device *idev = dev_get_drvdata(dev); |
257 | if (idev) | 245 | return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); |
258 | return sprintf(buf, "%u\n", | ||
259 | (unsigned int)atomic_read(&idev->event)); | ||
260 | else | ||
261 | return -ENODEV; | ||
262 | } | 246 | } |
263 | static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); | ||
264 | 247 | ||
265 | static struct attribute *uio_attrs[] = { | 248 | static struct device_attribute uio_class_attributes[] = { |
266 | &dev_attr_name.attr, | 249 | __ATTR(name, S_IRUGO, show_name, NULL), |
267 | &dev_attr_version.attr, | 250 | __ATTR(version, S_IRUGO, show_version, NULL), |
268 | &dev_attr_event.attr, | 251 | __ATTR(event, S_IRUGO, show_event, NULL), |
269 | NULL, | 252 | {} |
270 | }; | 253 | }; |
271 | 254 | ||
272 | static struct attribute_group uio_attr_grp = { | 255 | /* UIO class infrastructure */ |
273 | .attrs = uio_attrs, | 256 | static struct class uio_class = { |
257 | .name = "uio", | ||
258 | .dev_attrs = uio_class_attributes, | ||
274 | }; | 259 | }; |
275 | 260 | ||
276 | /* | 261 | /* |
@@ -287,10 +272,6 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
287 | struct uio_port *port; | 272 | struct uio_port *port; |
288 | struct uio_portio *portio; | 273 | struct uio_portio *portio; |
289 | 274 | ||
290 | ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); | ||
291 | if (ret) | ||
292 | goto err_group; | ||
293 | |||
294 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { | 275 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { |
295 | mem = &idev->info->mem[mi]; | 276 | mem = &idev->info->mem[mi]; |
296 | if (mem->size == 0) | 277 | if (mem->size == 0) |
@@ -358,8 +339,6 @@ err_map: | |||
358 | kobject_put(&map->kobj); | 339 | kobject_put(&map->kobj); |
359 | } | 340 | } |
360 | kobject_put(idev->map_dir); | 341 | kobject_put(idev->map_dir); |
361 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | ||
362 | err_group: | ||
363 | dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); | 342 | dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); |
364 | return ret; | 343 | return ret; |
365 | } | 344 | } |
@@ -385,8 +364,6 @@ static void uio_dev_del_attributes(struct uio_device *idev) | |||
385 | kobject_put(&port->portio->kobj); | 364 | kobject_put(&port->portio->kobj); |
386 | } | 365 | } |
387 | kobject_put(idev->portio_dir); | 366 | kobject_put(idev->portio_dir); |
388 | |||
389 | sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); | ||
390 | } | 367 | } |
391 | 368 | ||
392 | static int uio_get_minor(struct uio_device *idev) | 369 | static int uio_get_minor(struct uio_device *idev) |
@@ -525,7 +502,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait) | |||
525 | struct uio_listener *listener = filep->private_data; | 502 | struct uio_listener *listener = filep->private_data; |
526 | struct uio_device *idev = listener->dev; | 503 | struct uio_device *idev = listener->dev; |
527 | 504 | ||
528 | if (idev->info->irq == UIO_IRQ_NONE) | 505 | if (!idev->info->irq) |
529 | return -EIO; | 506 | return -EIO; |
530 | 507 | ||
531 | poll_wait(filep, &idev->wait, wait); | 508 | poll_wait(filep, &idev->wait, wait); |
@@ -543,7 +520,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf, | |||
543 | ssize_t retval; | 520 | ssize_t retval; |
544 | s32 event_count; | 521 | s32 event_count; |
545 | 522 | ||
546 | if (idev->info->irq == UIO_IRQ_NONE) | 523 | if (!idev->info->irq) |
547 | return -EIO; | 524 | return -EIO; |
548 | 525 | ||
549 | if (count != sizeof(s32)) | 526 | if (count != sizeof(s32)) |
@@ -591,7 +568,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, | |||
591 | ssize_t retval; | 568 | ssize_t retval; |
592 | s32 irq_on; | 569 | s32 irq_on; |
593 | 570 | ||
594 | if (idev->info->irq == UIO_IRQ_NONE) | 571 | if (!idev->info->irq) |
595 | return -EIO; | 572 | return -EIO; |
596 | 573 | ||
597 | if (count != sizeof(s32)) | 574 | if (count != sizeof(s32)) |
@@ -745,68 +722,72 @@ static const struct file_operations uio_fops = { | |||
745 | 722 | ||
746 | static int uio_major_init(void) | 723 | static int uio_major_init(void) |
747 | { | 724 | { |
748 | uio_major = register_chrdev(0, "uio", &uio_fops); | 725 | static const char name[] = "uio"; |
749 | if (uio_major < 0) | 726 | struct cdev *cdev = NULL; |
750 | return uio_major; | 727 | dev_t uio_dev = 0; |
751 | return 0; | 728 | int result; |
729 | |||
730 | result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); | ||
731 | if (result) | ||
732 | goto out; | ||
733 | |||
734 | result = -ENOMEM; | ||
735 | cdev = cdev_alloc(); | ||
736 | if (!cdev) | ||
737 | goto out_unregister; | ||
738 | |||
739 | cdev->owner = THIS_MODULE; | ||
740 | cdev->ops = &uio_fops; | ||
741 | kobject_set_name(&cdev->kobj, "%s", name); | ||
742 | |||
743 | result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); | ||
744 | if (result) | ||
745 | goto out_put; | ||
746 | |||
747 | uio_major = MAJOR(uio_dev); | ||
748 | uio_cdev = cdev; | ||
749 | result = 0; | ||
750 | out: | ||
751 | return result; | ||
752 | out_put: | ||
753 | kobject_put(&cdev->kobj); | ||
754 | out_unregister: | ||
755 | unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); | ||
756 | goto out; | ||
752 | } | 757 | } |
753 | 758 | ||
754 | static void uio_major_cleanup(void) | 759 | static void uio_major_cleanup(void) |
755 | { | 760 | { |
756 | unregister_chrdev(uio_major, "uio"); | 761 | unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); |
762 | cdev_del(uio_cdev); | ||
757 | } | 763 | } |
758 | 764 | ||
759 | static int init_uio_class(void) | 765 | static int init_uio_class(void) |
760 | { | 766 | { |
761 | int ret = 0; | 767 | int ret; |
762 | |||
763 | if (uio_class != NULL) { | ||
764 | kref_get(&uio_class->kref); | ||
765 | goto exit; | ||
766 | } | ||
767 | 768 | ||
768 | /* This is the first time in here, set everything up properly */ | 769 | /* This is the first time in here, set everything up properly */ |
769 | ret = uio_major_init(); | 770 | ret = uio_major_init(); |
770 | if (ret) | 771 | if (ret) |
771 | goto exit; | 772 | goto exit; |
772 | 773 | ||
773 | uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); | 774 | ret = class_register(&uio_class); |
774 | if (!uio_class) { | 775 | if (ret) { |
775 | ret = -ENOMEM; | 776 | printk(KERN_ERR "class_register failed for uio\n"); |
776 | goto err_kzalloc; | 777 | goto err_class_register; |
777 | } | ||
778 | |||
779 | kref_init(&uio_class->kref); | ||
780 | uio_class->class = class_create(THIS_MODULE, "uio"); | ||
781 | if (IS_ERR(uio_class->class)) { | ||
782 | ret = IS_ERR(uio_class->class); | ||
783 | printk(KERN_ERR "class_create failed for uio\n"); | ||
784 | goto err_class_create; | ||
785 | } | 778 | } |
786 | return 0; | 779 | return 0; |
787 | 780 | ||
788 | err_class_create: | 781 | err_class_register: |
789 | kfree(uio_class); | ||
790 | uio_class = NULL; | ||
791 | err_kzalloc: | ||
792 | uio_major_cleanup(); | 782 | uio_major_cleanup(); |
793 | exit: | 783 | exit: |
794 | return ret; | 784 | return ret; |
795 | } | 785 | } |
796 | 786 | ||
797 | static void release_uio_class(struct kref *kref) | 787 | static void release_uio_class(void) |
798 | { | 788 | { |
799 | /* Ok, we cheat as we know we only have one uio_class */ | 789 | class_unregister(&uio_class); |
800 | class_destroy(uio_class->class); | ||
801 | kfree(uio_class); | ||
802 | uio_major_cleanup(); | 790 | uio_major_cleanup(); |
803 | uio_class = NULL; | ||
804 | } | ||
805 | |||
806 | static void uio_class_destroy(void) | ||
807 | { | ||
808 | if (uio_class) | ||
809 | kref_put(&uio_class->kref, release_uio_class); | ||
810 | } | 791 | } |
811 | 792 | ||
812 | /** | 793 | /** |
@@ -829,10 +810,6 @@ int __uio_register_device(struct module *owner, | |||
829 | 810 | ||
830 | info->uio_dev = NULL; | 811 | info->uio_dev = NULL; |
831 | 812 | ||
832 | ret = init_uio_class(); | ||
833 | if (ret) | ||
834 | return ret; | ||
835 | |||
836 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | 813 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); |
837 | if (!idev) { | 814 | if (!idev) { |
838 | ret = -ENOMEM; | 815 | ret = -ENOMEM; |
@@ -848,7 +825,7 @@ int __uio_register_device(struct module *owner, | |||
848 | if (ret) | 825 | if (ret) |
849 | goto err_get_minor; | 826 | goto err_get_minor; |
850 | 827 | ||
851 | idev->dev = device_create(uio_class->class, parent, | 828 | idev->dev = device_create(&uio_class, parent, |
852 | MKDEV(uio_major, idev->minor), idev, | 829 | MKDEV(uio_major, idev->minor), idev, |
853 | "uio%d", idev->minor); | 830 | "uio%d", idev->minor); |
854 | if (IS_ERR(idev->dev)) { | 831 | if (IS_ERR(idev->dev)) { |
@@ -863,9 +840,9 @@ int __uio_register_device(struct module *owner, | |||
863 | 840 | ||
864 | info->uio_dev = idev; | 841 | info->uio_dev = idev; |
865 | 842 | ||
866 | if (idev->info->irq >= 0) { | 843 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { |
867 | ret = request_irq(idev->info->irq, uio_interrupt, | 844 | ret = request_irq(info->irq, uio_interrupt, |
868 | idev->info->irq_flags, idev->info->name, idev); | 845 | info->irq_flags, info->name, idev); |
869 | if (ret) | 846 | if (ret) |
870 | goto err_request_irq; | 847 | goto err_request_irq; |
871 | } | 848 | } |
@@ -875,13 +852,12 @@ int __uio_register_device(struct module *owner, | |||
875 | err_request_irq: | 852 | err_request_irq: |
876 | uio_dev_del_attributes(idev); | 853 | uio_dev_del_attributes(idev); |
877 | err_uio_dev_add_attributes: | 854 | err_uio_dev_add_attributes: |
878 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | 855 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
879 | err_device_create: | 856 | err_device_create: |
880 | uio_free_minor(idev); | 857 | uio_free_minor(idev); |
881 | err_get_minor: | 858 | err_get_minor: |
882 | kfree(idev); | 859 | kfree(idev); |
883 | err_kzalloc: | 860 | err_kzalloc: |
884 | uio_class_destroy(); | ||
885 | return ret; | 861 | return ret; |
886 | } | 862 | } |
887 | EXPORT_SYMBOL_GPL(__uio_register_device); | 863 | EXPORT_SYMBOL_GPL(__uio_register_device); |
@@ -902,15 +878,13 @@ void uio_unregister_device(struct uio_info *info) | |||
902 | 878 | ||
903 | uio_free_minor(idev); | 879 | uio_free_minor(idev); |
904 | 880 | ||
905 | if (info->irq >= 0) | 881 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) |
906 | free_irq(info->irq, idev); | 882 | free_irq(info->irq, idev); |
907 | 883 | ||
908 | uio_dev_del_attributes(idev); | 884 | uio_dev_del_attributes(idev); |
909 | 885 | ||
910 | dev_set_drvdata(idev->dev, NULL); | 886 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
911 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | ||
912 | kfree(idev); | 887 | kfree(idev); |
913 | uio_class_destroy(); | ||
914 | 888 | ||
915 | return; | 889 | return; |
916 | } | 890 | } |
@@ -918,11 +892,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); | |||
918 | 892 | ||
919 | static int __init uio_init(void) | 893 | static int __init uio_init(void) |
920 | { | 894 | { |
921 | return 0; | 895 | return init_uio_class(); |
922 | } | 896 | } |
923 | 897 | ||
924 | static void __exit uio_exit(void) | 898 | static void __exit uio_exit(void) |
925 | { | 899 | { |
900 | release_uio_class(); | ||
926 | } | 901 | } |
927 | 902 | ||
928 | module_init(uio_init) | 903 | module_init(uio_init) |