diff options
Diffstat (limited to 'drivers/uio/uio.c')
| -rw-r--r-- | drivers/uio/uio.c | 119 |
1 files changed, 64 insertions, 55 deletions
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index b645c47501b..a673e5b6a2e 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -35,7 +35,6 @@ struct uio_device { atomic_t event; struct fasync_struct *async_queue; wait_queue_head_t wait; - int vma_count; struct uio_info *info; struct kobject *map_dir; struct kobject *portio_dir; @@ -224,38 +223,42 @@ static struct kobj_type portio_attr_type = { .default_attrs = portio_attrs, }; -static ssize_t show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->name); } +static DEVICE_ATTR_RO(name); -static ssize_t show_version(struct device *dev, +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->version); } +static DEVICE_ATTR_RO(version); -static ssize_t show_event(struct device *dev, +static ssize_t event_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); } +static DEVICE_ATTR_RO(event); -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 *uio_attrs[] = { + &dev_attr_name.attr, + &dev_attr_version.attr, + &dev_attr_event.attr, + NULL, }; +ATTRIBUTE_GROUPS(uio); /* UIO class infrastructure */ static struct class uio_class = { .name = "uio", - .dev_attrs = uio_class_attributes, + .dev_groups = uio_groups, }; /* @@ -285,13 +288,13 @@ static int uio_dev_add_attributes(struct uio_device *idev) } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) - goto err_map; + goto err_map_kobj; kobject_init(&map->kobj, &map_attr_type); map->mem = mem; mem->map = map; ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); if (ret) - goto err_map; + goto err_map_kobj; ret = kobject_uevent(&map->kobj, KOBJ_ADD); if (ret) goto err_map; @@ -310,14 +313,14 @@ static int uio_dev_add_attributes(struct uio_device *idev) } portio = kzalloc(sizeof(*portio), GFP_KERNEL); if (!portio) - goto err_portio; + goto err_portio_kobj; kobject_init(&portio->kobj, &portio_attr_type); portio->port = port; port->portio = portio; ret = kobject_add(&portio->kobj, idev->portio_dir, "port%d", pi); if (ret) - goto err_portio; + goto err_portio_kobj; ret = kobject_uevent(&portio->kobj, KOBJ_ADD); if (ret) goto err_portio; @@ -326,14 +329,18 @@ static int uio_dev_add_attributes(struct uio_device *idev) return 0; err_portio: - for (pi--; pi >= 0; pi--) { + pi--; +err_portio_kobj: + for (; pi >= 0; pi--) { port = &idev->info->port[pi]; portio = port->portio; kobject_put(&portio->kobj); } kobject_put(idev->portio_dir); err_map: - for (mi--; mi>=0; mi--) { + mi--; +err_map_kobj: + for (; mi >= 0; mi--) { mem = &idev->info->mem[mi]; map = mem->map; kobject_put(&map->kobj); @@ -593,23 +600,12 @@ static int uio_find_mem_index(struct vm_area_struct *vma) return -1; } -static void uio_vma_open(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count++; -} - -static void uio_vma_close(struct vm_area_struct *vma) -{ - struct uio_device *idev = vma->vm_private_data; - idev->vma_count--; -} - static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct uio_device *idev = vma->vm_private_data; struct page *page; unsigned long offset; + void *addr; int mi = uio_find_mem_index(vma); if (mi < 0) @@ -621,45 +617,66 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) */ offset = (vmf->pgoff - mi) << PAGE_SHIFT; + addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset; if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) - page = virt_to_page(idev->info->mem[mi].addr + offset); + page = virt_to_page(addr); else - page = vmalloc_to_page((void *)(unsigned long)idev->info->mem[mi].addr + offset); + page = vmalloc_to_page(addr); get_page(page); vmf->page = page; return 0; } -static const struct vm_operations_struct uio_vm_ops = { - .open = uio_vma_open, - .close = uio_vma_close, +static const struct vm_operations_struct uio_logical_vm_ops = { .fault = uio_vma_fault, }; +static int uio_mmap_logical(struct vm_area_struct *vma) +{ + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = &uio_logical_vm_ops; + return 0; +} + +static const struct vm_operations_struct uio_physical_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + static int uio_mmap_physical(struct vm_area_struct *vma) { struct uio_device *idev = vma->vm_private_data; int mi = uio_find_mem_index(vma); + struct uio_mem *mem; if (mi < 0) return -EINVAL; + mem = idev->info->mem + mi; + if (mem->addr & ~PAGE_MASK) + return -ENODEV; + if (vma->vm_end - vma->vm_start > mem->size) + return -EINVAL; + + vma->vm_ops = &uio_physical_vm_ops; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + /* + * We cannot use the vm_iomap_memory() helper here, + * because vma->vm_pgoff is the map index we looked + * up above in uio_find_mem_index(), rather than an + * actual page offset into the mmap. + * + * So we just do the physical mmap without a page + * offset. + */ return remap_pfn_range(vma, vma->vm_start, - idev->info->mem[mi].addr >> PAGE_SHIFT, + mem->addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -static int uio_mmap_logical(struct vm_area_struct *vma) -{ - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &uio_vm_ops; - uio_vma_open(vma); - return 0; -} - static int uio_mmap(struct file *filep, struct vm_area_struct *vma) { struct uio_listener *listener = filep->private_data; @@ -677,7 +694,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma) if (mi < 0) return -EINVAL; - requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + requested_pages = vma_pages(vma); actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK) + idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT; if (requested_pages > actual_pages) @@ -800,10 +817,9 @@ int __uio_register_device(struct module *owner, info->uio_dev = NULL; - idev = kzalloc(sizeof(*idev), GFP_KERNEL); + idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL); if (!idev) { - ret = -ENOMEM; - goto err_kzalloc; + return -ENOMEM; } idev->owner = owner; @@ -813,7 +829,7 @@ int __uio_register_device(struct module *owner, ret = uio_get_minor(idev); if (ret) - goto err_get_minor; + return ret; idev->dev = device_create(&uio_class, parent, MKDEV(uio_major, idev->minor), idev, @@ -831,7 +847,7 @@ int __uio_register_device(struct module *owner, info->uio_dev = idev; if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { - ret = request_irq(info->irq, uio_interrupt, + ret = devm_request_irq(idev->dev, info->irq, uio_interrupt, info->irq_flags, info->name, idev); if (ret) goto err_request_irq; @@ -845,9 +861,6 @@ err_uio_dev_add_attributes: device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); err_device_create: uio_free_minor(idev); -err_get_minor: - kfree(idev); -err_kzalloc: return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); @@ -868,13 +881,9 @@ void uio_unregister_device(struct uio_info *info) uio_free_minor(idev); - if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) - free_irq(info->irq, idev); - uio_dev_del_attributes(idev); device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); - kfree(idev); return; } |
