diff options
Diffstat (limited to 'drivers/uio/uio.c')
-rw-r--r-- | drivers/uio/uio.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 3a6934bf7131..5dccf057a7dd 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -67,6 +67,11 @@ static ssize_t map_size_show(struct uio_mem *mem, char *buf) | |||
67 | return sprintf(buf, "0x%lx\n", mem->size); | 67 | return sprintf(buf, "0x%lx\n", mem->size); |
68 | } | 68 | } |
69 | 69 | ||
70 | static ssize_t map_offset_show(struct uio_mem *mem, char *buf) | ||
71 | { | ||
72 | return sprintf(buf, "0x%lx\n", mem->addr & ~PAGE_MASK); | ||
73 | } | ||
74 | |||
70 | struct uio_sysfs_entry { | 75 | struct uio_sysfs_entry { |
71 | struct attribute attr; | 76 | struct attribute attr; |
72 | ssize_t (*show)(struct uio_mem *, char *); | 77 | ssize_t (*show)(struct uio_mem *, char *); |
@@ -77,10 +82,13 @@ static struct uio_sysfs_entry addr_attribute = | |||
77 | __ATTR(addr, S_IRUGO, map_addr_show, NULL); | 82 | __ATTR(addr, S_IRUGO, map_addr_show, NULL); |
78 | static struct uio_sysfs_entry size_attribute = | 83 | static struct uio_sysfs_entry size_attribute = |
79 | __ATTR(size, S_IRUGO, map_size_show, NULL); | 84 | __ATTR(size, S_IRUGO, map_size_show, NULL); |
85 | static struct uio_sysfs_entry offset_attribute = | ||
86 | __ATTR(offset, S_IRUGO, map_offset_show, NULL); | ||
80 | 87 | ||
81 | static struct attribute *attrs[] = { | 88 | static struct attribute *attrs[] = { |
82 | &addr_attribute.attr, | 89 | &addr_attribute.attr, |
83 | &size_attribute.attr, | 90 | &size_attribute.attr, |
91 | &offset_attribute.attr, | ||
84 | NULL, /* need to NULL terminate the list of attributes */ | 92 | NULL, /* need to NULL terminate the list of attributes */ |
85 | }; | 93 | }; |
86 | 94 | ||
@@ -482,15 +490,23 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
482 | { | 490 | { |
483 | struct uio_device *idev = vma->vm_private_data; | 491 | struct uio_device *idev = vma->vm_private_data; |
484 | struct page *page; | 492 | struct page *page; |
493 | unsigned long offset; | ||
485 | 494 | ||
486 | int mi = uio_find_mem_index(vma); | 495 | int mi = uio_find_mem_index(vma); |
487 | if (mi < 0) | 496 | if (mi < 0) |
488 | return VM_FAULT_SIGBUS; | 497 | return VM_FAULT_SIGBUS; |
489 | 498 | ||
499 | /* | ||
500 | * We need to subtract mi because userspace uses offset = N*PAGE_SIZE | ||
501 | * to use mem[N]. | ||
502 | */ | ||
503 | offset = (vmf->pgoff - mi) << PAGE_SHIFT; | ||
504 | |||
490 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) | 505 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) |
491 | page = virt_to_page(idev->info->mem[mi].addr); | 506 | page = virt_to_page(idev->info->mem[mi].addr + offset); |
492 | else | 507 | else |
493 | page = vmalloc_to_page((void*)idev->info->mem[mi].addr); | 508 | page = vmalloc_to_page((void *)idev->info->mem[mi].addr |
509 | + offset); | ||
494 | get_page(page); | 510 | get_page(page); |
495 | vmf->page = page; | 511 | vmf->page = page; |
496 | return 0; | 512 | return 0; |
@@ -682,9 +698,9 @@ int __uio_register_device(struct module *owner, | |||
682 | if (ret) | 698 | if (ret) |
683 | goto err_get_minor; | 699 | goto err_get_minor; |
684 | 700 | ||
685 | idev->dev = device_create_drvdata(uio_class->class, parent, | 701 | idev->dev = device_create(uio_class->class, parent, |
686 | MKDEV(uio_major, idev->minor), idev, | 702 | MKDEV(uio_major, idev->minor), idev, |
687 | "uio%d", idev->minor); | 703 | "uio%d", idev->minor); |
688 | if (IS_ERR(idev->dev)) { | 704 | if (IS_ERR(idev->dev)) { |
689 | printk(KERN_ERR "UIO: device register failed\n"); | 705 | printk(KERN_ERR "UIO: device register failed\n"); |
690 | ret = PTR_ERR(idev->dev); | 706 | ret = PTR_ERR(idev->dev); |