diff options
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r-- | drivers/uio/uio.c | 182 |
1 files changed, 81 insertions, 101 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index bff1afbde5a4..d2efe823c20d 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> | 4 | * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de> |
5 | * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> | 5 | * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de> |
6 | * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de> | 6 | * Copyright(C) 2006, Hans J. Koch <hjk@hansjkoch.de> |
7 | * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> | 7 | * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com> |
8 | * | 8 | * |
9 | * Userspace IO | 9 | * Userspace IO |
@@ -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) |
@@ -404,7 +381,13 @@ static int uio_get_minor(struct uio_device *idev) | |||
404 | retval = -ENOMEM; | 381 | retval = -ENOMEM; |
405 | goto exit; | 382 | goto exit; |
406 | } | 383 | } |
407 | idev->minor = id & MAX_ID_MASK; | 384 | if (id < UIO_MAX_DEVICES) { |
385 | idev->minor = id; | ||
386 | } else { | ||
387 | dev_err(idev->dev, "too many uio devices\n"); | ||
388 | retval = -EINVAL; | ||
389 | idr_remove(&uio_idr, id); | ||
390 | } | ||
408 | exit: | 391 | exit: |
409 | mutex_unlock(&minor_lock); | 392 | mutex_unlock(&minor_lock); |
410 | return retval; | 393 | return retval; |
@@ -525,7 +508,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait) | |||
525 | struct uio_listener *listener = filep->private_data; | 508 | struct uio_listener *listener = filep->private_data; |
526 | struct uio_device *idev = listener->dev; | 509 | struct uio_device *idev = listener->dev; |
527 | 510 | ||
528 | if (idev->info->irq == UIO_IRQ_NONE) | 511 | if (!idev->info->irq) |
529 | return -EIO; | 512 | return -EIO; |
530 | 513 | ||
531 | poll_wait(filep, &idev->wait, wait); | 514 | poll_wait(filep, &idev->wait, wait); |
@@ -543,7 +526,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf, | |||
543 | ssize_t retval; | 526 | ssize_t retval; |
544 | s32 event_count; | 527 | s32 event_count; |
545 | 528 | ||
546 | if (idev->info->irq == UIO_IRQ_NONE) | 529 | if (!idev->info->irq) |
547 | return -EIO; | 530 | return -EIO; |
548 | 531 | ||
549 | if (count != sizeof(s32)) | 532 | if (count != sizeof(s32)) |
@@ -591,7 +574,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, | |||
591 | ssize_t retval; | 574 | ssize_t retval; |
592 | s32 irq_on; | 575 | s32 irq_on; |
593 | 576 | ||
594 | if (idev->info->irq == UIO_IRQ_NONE) | 577 | if (!idev->info->irq) |
595 | return -EIO; | 578 | return -EIO; |
596 | 579 | ||
597 | if (count != sizeof(s32)) | 580 | if (count != sizeof(s32)) |
@@ -610,14 +593,12 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, | |||
610 | 593 | ||
611 | static int uio_find_mem_index(struct vm_area_struct *vma) | 594 | static int uio_find_mem_index(struct vm_area_struct *vma) |
612 | { | 595 | { |
613 | int mi; | ||
614 | struct uio_device *idev = vma->vm_private_data; | 596 | struct uio_device *idev = vma->vm_private_data; |
615 | 597 | ||
616 | for (mi = 0; mi < MAX_UIO_MAPS; mi++) { | 598 | if (vma->vm_pgoff < MAX_UIO_MAPS) { |
617 | if (idev->info->mem[mi].size == 0) | 599 | if (idev->info->mem[vma->vm_pgoff].size == 0) |
618 | return -1; | 600 | return -1; |
619 | if (vma->vm_pgoff == mi) | 601 | return (int)vma->vm_pgoff; |
620 | return mi; | ||
621 | } | 602 | } |
622 | return -1; | 603 | return -1; |
623 | } | 604 | } |
@@ -740,72 +721,77 @@ static const struct file_operations uio_fops = { | |||
740 | .mmap = uio_mmap, | 721 | .mmap = uio_mmap, |
741 | .poll = uio_poll, | 722 | .poll = uio_poll, |
742 | .fasync = uio_fasync, | 723 | .fasync = uio_fasync, |
724 | .llseek = noop_llseek, | ||
743 | }; | 725 | }; |
744 | 726 | ||
745 | static int uio_major_init(void) | 727 | static int uio_major_init(void) |
746 | { | 728 | { |
747 | uio_major = register_chrdev(0, "uio", &uio_fops); | 729 | static const char name[] = "uio"; |
748 | if (uio_major < 0) | 730 | struct cdev *cdev = NULL; |
749 | return uio_major; | 731 | dev_t uio_dev = 0; |
750 | return 0; | 732 | int result; |
733 | |||
734 | result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); | ||
735 | if (result) | ||
736 | goto out; | ||
737 | |||
738 | result = -ENOMEM; | ||
739 | cdev = cdev_alloc(); | ||
740 | if (!cdev) | ||
741 | goto out_unregister; | ||
742 | |||
743 | cdev->owner = THIS_MODULE; | ||
744 | cdev->ops = &uio_fops; | ||
745 | kobject_set_name(&cdev->kobj, "%s", name); | ||
746 | |||
747 | result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); | ||
748 | if (result) | ||
749 | goto out_put; | ||
750 | |||
751 | uio_major = MAJOR(uio_dev); | ||
752 | uio_cdev = cdev; | ||
753 | result = 0; | ||
754 | out: | ||
755 | return result; | ||
756 | out_put: | ||
757 | kobject_put(&cdev->kobj); | ||
758 | out_unregister: | ||
759 | unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); | ||
760 | goto out; | ||
751 | } | 761 | } |
752 | 762 | ||
753 | static void uio_major_cleanup(void) | 763 | static void uio_major_cleanup(void) |
754 | { | 764 | { |
755 | unregister_chrdev(uio_major, "uio"); | 765 | unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); |
766 | cdev_del(uio_cdev); | ||
756 | } | 767 | } |
757 | 768 | ||
758 | static int init_uio_class(void) | 769 | static int init_uio_class(void) |
759 | { | 770 | { |
760 | int ret = 0; | 771 | int ret; |
761 | |||
762 | if (uio_class != NULL) { | ||
763 | kref_get(&uio_class->kref); | ||
764 | goto exit; | ||
765 | } | ||
766 | 772 | ||
767 | /* This is the first time in here, set everything up properly */ | 773 | /* This is the first time in here, set everything up properly */ |
768 | ret = uio_major_init(); | 774 | ret = uio_major_init(); |
769 | if (ret) | 775 | if (ret) |
770 | goto exit; | 776 | goto exit; |
771 | 777 | ||
772 | uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); | 778 | ret = class_register(&uio_class); |
773 | if (!uio_class) { | 779 | if (ret) { |
774 | ret = -ENOMEM; | 780 | printk(KERN_ERR "class_register failed for uio\n"); |
775 | goto err_kzalloc; | 781 | goto err_class_register; |
776 | } | ||
777 | |||
778 | kref_init(&uio_class->kref); | ||
779 | uio_class->class = class_create(THIS_MODULE, "uio"); | ||
780 | if (IS_ERR(uio_class->class)) { | ||
781 | ret = IS_ERR(uio_class->class); | ||
782 | printk(KERN_ERR "class_create failed for uio\n"); | ||
783 | goto err_class_create; | ||
784 | } | 782 | } |
785 | return 0; | 783 | return 0; |
786 | 784 | ||
787 | err_class_create: | 785 | err_class_register: |
788 | kfree(uio_class); | ||
789 | uio_class = NULL; | ||
790 | err_kzalloc: | ||
791 | uio_major_cleanup(); | 786 | uio_major_cleanup(); |
792 | exit: | 787 | exit: |
793 | return ret; | 788 | return ret; |
794 | } | 789 | } |
795 | 790 | ||
796 | static void release_uio_class(struct kref *kref) | 791 | static void release_uio_class(void) |
797 | { | 792 | { |
798 | /* Ok, we cheat as we know we only have one uio_class */ | 793 | class_unregister(&uio_class); |
799 | class_destroy(uio_class->class); | ||
800 | kfree(uio_class); | ||
801 | uio_major_cleanup(); | 794 | uio_major_cleanup(); |
802 | uio_class = NULL; | ||
803 | } | ||
804 | |||
805 | static void uio_class_destroy(void) | ||
806 | { | ||
807 | if (uio_class) | ||
808 | kref_put(&uio_class->kref, release_uio_class); | ||
809 | } | 795 | } |
810 | 796 | ||
811 | /** | 797 | /** |
@@ -828,10 +814,6 @@ int __uio_register_device(struct module *owner, | |||
828 | 814 | ||
829 | info->uio_dev = NULL; | 815 | info->uio_dev = NULL; |
830 | 816 | ||
831 | ret = init_uio_class(); | ||
832 | if (ret) | ||
833 | return ret; | ||
834 | |||
835 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | 817 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); |
836 | if (!idev) { | 818 | if (!idev) { |
837 | ret = -ENOMEM; | 819 | ret = -ENOMEM; |
@@ -847,7 +829,7 @@ int __uio_register_device(struct module *owner, | |||
847 | if (ret) | 829 | if (ret) |
848 | goto err_get_minor; | 830 | goto err_get_minor; |
849 | 831 | ||
850 | idev->dev = device_create(uio_class->class, parent, | 832 | idev->dev = device_create(&uio_class, parent, |
851 | MKDEV(uio_major, idev->minor), idev, | 833 | MKDEV(uio_major, idev->minor), idev, |
852 | "uio%d", idev->minor); | 834 | "uio%d", idev->minor); |
853 | if (IS_ERR(idev->dev)) { | 835 | if (IS_ERR(idev->dev)) { |
@@ -862,9 +844,9 @@ int __uio_register_device(struct module *owner, | |||
862 | 844 | ||
863 | info->uio_dev = idev; | 845 | info->uio_dev = idev; |
864 | 846 | ||
865 | if (idev->info->irq >= 0) { | 847 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { |
866 | ret = request_irq(idev->info->irq, uio_interrupt, | 848 | ret = request_irq(info->irq, uio_interrupt, |
867 | idev->info->irq_flags, idev->info->name, idev); | 849 | info->irq_flags, info->name, idev); |
868 | if (ret) | 850 | if (ret) |
869 | goto err_request_irq; | 851 | goto err_request_irq; |
870 | } | 852 | } |
@@ -874,13 +856,12 @@ int __uio_register_device(struct module *owner, | |||
874 | err_request_irq: | 856 | err_request_irq: |
875 | uio_dev_del_attributes(idev); | 857 | uio_dev_del_attributes(idev); |
876 | err_uio_dev_add_attributes: | 858 | err_uio_dev_add_attributes: |
877 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | 859 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
878 | err_device_create: | 860 | err_device_create: |
879 | uio_free_minor(idev); | 861 | uio_free_minor(idev); |
880 | err_get_minor: | 862 | err_get_minor: |
881 | kfree(idev); | 863 | kfree(idev); |
882 | err_kzalloc: | 864 | err_kzalloc: |
883 | uio_class_destroy(); | ||
884 | return ret; | 865 | return ret; |
885 | } | 866 | } |
886 | EXPORT_SYMBOL_GPL(__uio_register_device); | 867 | EXPORT_SYMBOL_GPL(__uio_register_device); |
@@ -901,15 +882,13 @@ void uio_unregister_device(struct uio_info *info) | |||
901 | 882 | ||
902 | uio_free_minor(idev); | 883 | uio_free_minor(idev); |
903 | 884 | ||
904 | if (info->irq >= 0) | 885 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) |
905 | free_irq(info->irq, idev); | 886 | free_irq(info->irq, idev); |
906 | 887 | ||
907 | uio_dev_del_attributes(idev); | 888 | uio_dev_del_attributes(idev); |
908 | 889 | ||
909 | dev_set_drvdata(idev->dev, NULL); | 890 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
910 | device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); | ||
911 | kfree(idev); | 891 | kfree(idev); |
912 | uio_class_destroy(); | ||
913 | 892 | ||
914 | return; | 893 | return; |
915 | } | 894 | } |
@@ -917,11 +896,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); | |||
917 | 896 | ||
918 | static int __init uio_init(void) | 897 | static int __init uio_init(void) |
919 | { | 898 | { |
920 | return 0; | 899 | return init_uio_class(); |
921 | } | 900 | } |
922 | 901 | ||
923 | static void __exit uio_exit(void) | 902 | static void __exit uio_exit(void) |
924 | { | 903 | { |
904 | release_uio_class(); | ||
925 | } | 905 | } |
926 | 906 | ||
927 | module_init(uio_init) | 907 | module_init(uio_init) |