diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/uio | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/uio')
-rw-r--r-- | drivers/uio/Kconfig | 23 | ||||
-rw-r--r-- | drivers/uio/Makefile | 1 | ||||
-rw-r--r-- | drivers/uio/uio.c | 182 | ||||
-rw-r--r-- | drivers/uio/uio_cif.c | 2 | ||||
-rw-r--r-- | drivers/uio/uio_netx.c | 21 | ||||
-rw-r--r-- | drivers/uio/uio_pci_generic.c | 13 | ||||
-rw-r--r-- | drivers/uio/uio_pdrv_genirq.c | 4 | ||||
-rw-r--r-- | drivers/uio/uio_pruss.c | 247 |
8 files changed, 381 insertions, 112 deletions
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 1da73ecd9799..6f3ea9bbc818 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig | |||
@@ -17,9 +17,9 @@ config UIO_CIF | |||
17 | depends on PCI | 17 | depends on PCI |
18 | help | 18 | help |
19 | Driver for Hilscher CIF DeviceNet and Profibus cards. This | 19 | Driver for Hilscher CIF DeviceNet and Profibus cards. This |
20 | driver requires a userspace component that handles all of the | 20 | driver requires a userspace component called cif that handles |
21 | heavy lifting and can be found at: | 21 | all of the heavy lifting and can be found at: |
22 | http://www.osadl.org/projects/downloads/UIO/user/cif-* | 22 | <http://www.osadl.org/projects/downloads/UIO/user/> |
23 | 23 | ||
24 | To compile this driver as a module, choose M here: the module | 24 | To compile this driver as a module, choose M here: the module |
25 | will be called uio_cif. | 25 | will be called uio_cif. |
@@ -94,4 +94,21 @@ config UIO_NETX | |||
94 | To compile this driver as a module, choose M here; the module | 94 | To compile this driver as a module, choose M here; the module |
95 | will be called uio_netx. | 95 | will be called uio_netx. |
96 | 96 | ||
97 | config UIO_PRUSS | ||
98 | tristate "Texas Instruments PRUSS driver" | ||
99 | depends on ARCH_DAVINCI_DA850 | ||
100 | help | ||
101 | PRUSS driver for OMAPL138/DA850/AM18XX devices | ||
102 | PRUSS driver requires user space components, examples and user space | ||
103 | driver is available from below SVN repo - you may use anonymous login | ||
104 | |||
105 | https://gforge.ti.com/gf/project/pru_sw/ | ||
106 | |||
107 | More info on API is available at below wiki | ||
108 | |||
109 | http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader | ||
110 | |||
111 | To compile this driver as a module, choose M here: the module | ||
112 | will be called uio_pruss. | ||
113 | |||
97 | endif | 114 | endif |
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index 18fd818c5b97..d4dd9a5552f8 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile | |||
@@ -6,3 +6,4 @@ obj-$(CONFIG_UIO_AEC) += uio_aec.o | |||
6 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o | 6 | obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o |
7 | obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o | 7 | obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o |
8 | obj-$(CONFIG_UIO_NETX) += uio_netx.o | 8 | obj-$(CONFIG_UIO_NETX) += uio_netx.o |
9 | obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o | ||
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) |
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index a8ea2f19a0cc..a84a451159ed 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * UIO Hilscher CIF card driver | 2 | * UIO Hilscher CIF card driver |
3 | * | 3 | * |
4 | * (C) 2007 Hans J. Koch <hjk@linutronix.de> | 4 | * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> |
5 | * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de> | 5 | * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de> |
6 | * | 6 | * |
7 | * Licensed under GPL version 2 only. | 7 | * Licensed under GPL version 2 only. |
diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index 5a18e9f7b836..a879fd5741f8 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). | 2 | * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). |
3 | * See http://www.hilscher.com for details. | 3 | * See http://www.hilscher.com for details. |
4 | * | 4 | * |
5 | * (C) 2007 Hans J. Koch <hjk@linutronix.de> | 5 | * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> |
6 | * (C) 2008 Manuel Traut <manut@linutronix.de> | 6 | * (C) 2008 Manuel Traut <manut@linutronix.de> |
7 | * | 7 | * |
8 | * Licensed under GPL version 2 only. | 8 | * Licensed under GPL version 2 only. |
@@ -18,6 +18,9 @@ | |||
18 | 18 | ||
19 | #define PCI_VENDOR_ID_HILSCHER 0x15CF | 19 | #define PCI_VENDOR_ID_HILSCHER 0x15CF |
20 | #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 | 20 | #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 |
21 | #define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010 | ||
22 | #define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000 | ||
23 | #define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001 | ||
21 | #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 | 24 | #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 |
22 | #define PCI_SUBDEVICE_ID_NXPCA 0x3335 | 25 | #define PCI_SUBDEVICE_ID_NXPCA 0x3335 |
23 | 26 | ||
@@ -66,6 +69,10 @@ static int __devinit netx_pci_probe(struct pci_dev *dev, | |||
66 | bar = 0; | 69 | bar = 0; |
67 | info->name = "netx"; | 70 | info->name = "netx"; |
68 | break; | 71 | break; |
72 | case PCI_DEVICE_ID_HILSCHER_NETPLC: | ||
73 | bar = 0; | ||
74 | info->name = "netplc"; | ||
75 | break; | ||
69 | default: | 76 | default: |
70 | bar = 2; | 77 | bar = 2; |
71 | info->name = "netx_plx"; | 78 | info->name = "netx_plx"; |
@@ -134,6 +141,18 @@ static struct pci_device_id netx_pci_ids[] = { | |||
134 | .subdevice = 0, | 141 | .subdevice = 0, |
135 | }, | 142 | }, |
136 | { | 143 | { |
144 | .vendor = PCI_VENDOR_ID_HILSCHER, | ||
145 | .device = PCI_DEVICE_ID_HILSCHER_NETPLC, | ||
146 | .subvendor = PCI_VENDOR_ID_HILSCHER, | ||
147 | .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM, | ||
148 | }, | ||
149 | { | ||
150 | .vendor = PCI_VENDOR_ID_HILSCHER, | ||
151 | .device = PCI_DEVICE_ID_HILSCHER_NETPLC, | ||
152 | .subvendor = PCI_VENDOR_ID_HILSCHER, | ||
153 | .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH, | ||
154 | }, | ||
155 | { | ||
137 | .vendor = PCI_VENDOR_ID_PLX, | 156 | .vendor = PCI_VENDOR_ID_PLX, |
138 | .device = PCI_DEVICE_ID_PLX_9030, | 157 | .device = PCI_DEVICE_ID_PLX_9030, |
139 | .subvendor = PCI_VENDOR_ID_PLX, | 158 | .subvendor = PCI_VENDOR_ID_PLX, |
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 85c9884a67fd..fc22e1e6f215 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c | |||
@@ -128,12 +128,6 @@ static int __devinit probe(struct pci_dev *pdev, | |||
128 | struct uio_pci_generic_dev *gdev; | 128 | struct uio_pci_generic_dev *gdev; |
129 | int err; | 129 | int err; |
130 | 130 | ||
131 | if (!pdev->irq) { | ||
132 | dev_warn(&pdev->dev, "No IRQ assigned to device: " | ||
133 | "no support for interrupts?\n"); | ||
134 | return -ENODEV; | ||
135 | } | ||
136 | |||
137 | err = pci_enable_device(pdev); | 131 | err = pci_enable_device(pdev); |
138 | if (err) { | 132 | if (err) { |
139 | dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", | 133 | dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", |
@@ -141,6 +135,13 @@ static int __devinit probe(struct pci_dev *pdev, | |||
141 | return err; | 135 | return err; |
142 | } | 136 | } |
143 | 137 | ||
138 | if (!pdev->irq) { | ||
139 | dev_warn(&pdev->dev, "No IRQ assigned to device: " | ||
140 | "no support for interrupts?\n"); | ||
141 | pci_disable_device(pdev); | ||
142 | return -ENODEV; | ||
143 | } | ||
144 | |||
144 | err = verify_pci_2_3(pdev); | 145 | err = verify_pci_2_3(pdev); |
145 | if (err) | 146 | if (err) |
146 | goto err_verify; | 147 | goto err_verify; |
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 7174d518b8a6..0f424af7f109 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c | |||
@@ -189,6 +189,10 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev) | |||
189 | 189 | ||
190 | uio_unregister_device(priv->uioinfo); | 190 | uio_unregister_device(priv->uioinfo); |
191 | pm_runtime_disable(&pdev->dev); | 191 | pm_runtime_disable(&pdev->dev); |
192 | |||
193 | priv->uioinfo->handler = NULL; | ||
194 | priv->uioinfo->irqcontrol = NULL; | ||
195 | |||
192 | kfree(priv); | 196 | kfree(priv); |
193 | return 0; | 197 | return 0; |
194 | } | 198 | } |
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c new file mode 100644 index 000000000000..e67b566e7aa3 --- /dev/null +++ b/drivers/uio/uio_pruss.c | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss) | ||
3 | * | ||
4 | * This driver exports PRUSS host event out interrupts and PRUSS, L3 RAM, | ||
5 | * and DDR RAM to user space for applications interacting with PRUSS firmware | ||
6 | * | ||
7 | * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation version 2. | ||
12 | * | ||
13 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
14 | * kind, whether express or implied; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/uio_driver.h> | ||
23 | #include <linux/platform_data/uio_pruss.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <mach/sram.h> | ||
29 | |||
30 | #define DRV_NAME "pruss_uio" | ||
31 | #define DRV_VERSION "1.0" | ||
32 | |||
33 | static int sram_pool_sz = SZ_16K; | ||
34 | module_param(sram_pool_sz, int, 0); | ||
35 | MODULE_PARM_DESC(sram_pool_sz, "sram pool size to allocate "); | ||
36 | |||
37 | static int extram_pool_sz = SZ_256K; | ||
38 | module_param(extram_pool_sz, int, 0); | ||
39 | MODULE_PARM_DESC(extram_pool_sz, "external ram pool size to allocate"); | ||
40 | |||
41 | /* | ||
42 | * Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt | ||
43 | * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS | ||
44 | * firmware and user space application, async notification from PRU firmware | ||
45 | * to user space application | ||
46 | * 3 PRU_EVTOUT0 | ||
47 | * 4 PRU_EVTOUT1 | ||
48 | * 5 PRU_EVTOUT2 | ||
49 | * 6 PRU_EVTOUT3 | ||
50 | * 7 PRU_EVTOUT4 | ||
51 | * 8 PRU_EVTOUT5 | ||
52 | * 9 PRU_EVTOUT6 | ||
53 | * 10 PRU_EVTOUT7 | ||
54 | */ | ||
55 | #define MAX_PRUSS_EVT 8 | ||
56 | |||
57 | #define PINTC_HIDISR 0x0038 | ||
58 | #define PINTC_HIPIR 0x0900 | ||
59 | #define HIPIR_NOPEND 0x80000000 | ||
60 | #define PINTC_HIER 0x1500 | ||
61 | |||
62 | struct uio_pruss_dev { | ||
63 | struct uio_info *info; | ||
64 | struct clk *pruss_clk; | ||
65 | dma_addr_t sram_paddr; | ||
66 | dma_addr_t ddr_paddr; | ||
67 | void __iomem *prussio_vaddr; | ||
68 | void *sram_vaddr; | ||
69 | void *ddr_vaddr; | ||
70 | unsigned int hostirq_start; | ||
71 | unsigned int pintc_base; | ||
72 | }; | ||
73 | |||
74 | static irqreturn_t pruss_handler(int irq, struct uio_info *info) | ||
75 | { | ||
76 | struct uio_pruss_dev *gdev = info->priv; | ||
77 | int intr_bit = (irq - gdev->hostirq_start + 2); | ||
78 | int val, intr_mask = (1 << intr_bit); | ||
79 | void __iomem *base = gdev->prussio_vaddr + gdev->pintc_base; | ||
80 | void __iomem *intren_reg = base + PINTC_HIER; | ||
81 | void __iomem *intrdis_reg = base + PINTC_HIDISR; | ||
82 | void __iomem *intrstat_reg = base + PINTC_HIPIR + (intr_bit << 2); | ||
83 | |||
84 | val = ioread32(intren_reg); | ||
85 | /* Is interrupt enabled and active ? */ | ||
86 | if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND)) | ||
87 | return IRQ_NONE; | ||
88 | /* Disable interrupt */ | ||
89 | iowrite32(intr_bit, intrdis_reg); | ||
90 | return IRQ_HANDLED; | ||
91 | } | ||
92 | |||
93 | static void pruss_cleanup(struct platform_device *dev, | ||
94 | struct uio_pruss_dev *gdev) | ||
95 | { | ||
96 | int cnt; | ||
97 | struct uio_info *p = gdev->info; | ||
98 | |||
99 | for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) { | ||
100 | uio_unregister_device(p); | ||
101 | kfree(p->name); | ||
102 | } | ||
103 | iounmap(gdev->prussio_vaddr); | ||
104 | if (gdev->ddr_vaddr) { | ||
105 | dma_free_coherent(&dev->dev, extram_pool_sz, gdev->ddr_vaddr, | ||
106 | gdev->ddr_paddr); | ||
107 | } | ||
108 | if (gdev->sram_vaddr) | ||
109 | sram_free(gdev->sram_vaddr, sram_pool_sz); | ||
110 | kfree(gdev->info); | ||
111 | clk_put(gdev->pruss_clk); | ||
112 | kfree(gdev); | ||
113 | } | ||
114 | |||
115 | static int __devinit pruss_probe(struct platform_device *dev) | ||
116 | { | ||
117 | struct uio_info *p; | ||
118 | struct uio_pruss_dev *gdev; | ||
119 | struct resource *regs_prussio; | ||
120 | int ret = -ENODEV, cnt = 0, len; | ||
121 | struct uio_pruss_pdata *pdata = dev->dev.platform_data; | ||
122 | |||
123 | gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL); | ||
124 | if (!gdev) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | gdev->info = kzalloc(sizeof(*p) * MAX_PRUSS_EVT, GFP_KERNEL); | ||
128 | if (!gdev->info) { | ||
129 | kfree(gdev); | ||
130 | return -ENOMEM; | ||
131 | } | ||
132 | /* Power on PRU in case its not done as part of boot-loader */ | ||
133 | gdev->pruss_clk = clk_get(&dev->dev, "pruss"); | ||
134 | if (IS_ERR(gdev->pruss_clk)) { | ||
135 | dev_err(&dev->dev, "Failed to get clock\n"); | ||
136 | kfree(gdev->info); | ||
137 | kfree(gdev); | ||
138 | ret = PTR_ERR(gdev->pruss_clk); | ||
139 | return ret; | ||
140 | } else { | ||
141 | clk_enable(gdev->pruss_clk); | ||
142 | } | ||
143 | |||
144 | regs_prussio = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
145 | if (!regs_prussio) { | ||
146 | dev_err(&dev->dev, "No PRUSS I/O resource specified\n"); | ||
147 | goto out_free; | ||
148 | } | ||
149 | |||
150 | if (!regs_prussio->start) { | ||
151 | dev_err(&dev->dev, "Invalid memory resource\n"); | ||
152 | goto out_free; | ||
153 | } | ||
154 | |||
155 | gdev->sram_vaddr = sram_alloc(sram_pool_sz, &(gdev->sram_paddr)); | ||
156 | if (!gdev->sram_vaddr) { | ||
157 | dev_err(&dev->dev, "Could not allocate SRAM pool\n"); | ||
158 | goto out_free; | ||
159 | } | ||
160 | |||
161 | gdev->ddr_vaddr = dma_alloc_coherent(&dev->dev, extram_pool_sz, | ||
162 | &(gdev->ddr_paddr), GFP_KERNEL | GFP_DMA); | ||
163 | if (!gdev->ddr_vaddr) { | ||
164 | dev_err(&dev->dev, "Could not allocate external memory\n"); | ||
165 | goto out_free; | ||
166 | } | ||
167 | |||
168 | len = resource_size(regs_prussio); | ||
169 | gdev->prussio_vaddr = ioremap(regs_prussio->start, len); | ||
170 | if (!gdev->prussio_vaddr) { | ||
171 | dev_err(&dev->dev, "Can't remap PRUSS I/O address range\n"); | ||
172 | goto out_free; | ||
173 | } | ||
174 | |||
175 | gdev->pintc_base = pdata->pintc_base; | ||
176 | gdev->hostirq_start = platform_get_irq(dev, 0); | ||
177 | |||
178 | for (cnt = 0, p = gdev->info; cnt < MAX_PRUSS_EVT; cnt++, p++) { | ||
179 | p->mem[0].addr = regs_prussio->start; | ||
180 | p->mem[0].size = resource_size(regs_prussio); | ||
181 | p->mem[0].memtype = UIO_MEM_PHYS; | ||
182 | |||
183 | p->mem[1].addr = gdev->sram_paddr; | ||
184 | p->mem[1].size = sram_pool_sz; | ||
185 | p->mem[1].memtype = UIO_MEM_PHYS; | ||
186 | |||
187 | p->mem[2].addr = gdev->ddr_paddr; | ||
188 | p->mem[2].size = extram_pool_sz; | ||
189 | p->mem[2].memtype = UIO_MEM_PHYS; | ||
190 | |||
191 | p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt); | ||
192 | p->version = DRV_VERSION; | ||
193 | |||
194 | /* Register PRUSS IRQ lines */ | ||
195 | p->irq = gdev->hostirq_start + cnt; | ||
196 | p->handler = pruss_handler; | ||
197 | p->priv = gdev; | ||
198 | |||
199 | ret = uio_register_device(&dev->dev, p); | ||
200 | if (ret < 0) | ||
201 | goto out_free; | ||
202 | } | ||
203 | |||
204 | platform_set_drvdata(dev, gdev); | ||
205 | return 0; | ||
206 | |||
207 | out_free: | ||
208 | pruss_cleanup(dev, gdev); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | static int __devexit pruss_remove(struct platform_device *dev) | ||
213 | { | ||
214 | struct uio_pruss_dev *gdev = platform_get_drvdata(dev); | ||
215 | |||
216 | pruss_cleanup(dev, gdev); | ||
217 | platform_set_drvdata(dev, NULL); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static struct platform_driver pruss_driver = { | ||
222 | .probe = pruss_probe, | ||
223 | .remove = __devexit_p(pruss_remove), | ||
224 | .driver = { | ||
225 | .name = DRV_NAME, | ||
226 | .owner = THIS_MODULE, | ||
227 | }, | ||
228 | }; | ||
229 | |||
230 | static int __init pruss_init_module(void) | ||
231 | { | ||
232 | return platform_driver_register(&pruss_driver); | ||
233 | } | ||
234 | |||
235 | module_init(pruss_init_module); | ||
236 | |||
237 | static void __exit pruss_exit_module(void) | ||
238 | { | ||
239 | platform_driver_unregister(&pruss_driver); | ||
240 | } | ||
241 | |||
242 | module_exit(pruss_exit_module); | ||
243 | |||
244 | MODULE_LICENSE("GPL v2"); | ||
245 | MODULE_VERSION(DRV_VERSION); | ||
246 | MODULE_AUTHOR("Amit Chatterjee <amit.chatterjee@ti.com>"); | ||
247 | MODULE_AUTHOR("Pratheesh Gangadhar <pratheesh@ti.com>"); | ||