Merge remote-tracking branch 'moduleh/module.h-split'
[linux-2.6/next.git] / drivers / media / video / videobuf2-vmalloc.c
bloba3a884234059afcacae18bd2e246190bfcfa5970
1 /*
2 * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
4 * Copyright (C) 2010 Samsung Electronics
6 * Author: Pawel Osciak <pawel@osciak.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/mm.h>
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
18 #include <media/videobuf2-core.h>
19 #include <media/videobuf2-memops.h>
21 struct vb2_vmalloc_buf {
22 void *vaddr;
23 unsigned long size;
24 atomic_t refcount;
25 struct vb2_vmarea_handler handler;
28 static void vb2_vmalloc_put(void *buf_priv);
30 static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
32 struct vb2_vmalloc_buf *buf;
34 buf = kzalloc(sizeof *buf, GFP_KERNEL);
35 if (!buf)
36 return NULL;
38 buf->size = size;
39 buf->vaddr = vmalloc_user(buf->size);
40 buf->handler.refcount = &buf->refcount;
41 buf->handler.put = vb2_vmalloc_put;
42 buf->handler.arg = buf;
44 if (!buf->vaddr) {
45 printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
46 kfree(buf);
47 return NULL;
50 atomic_inc(&buf->refcount);
51 printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
52 buf->size, buf->vaddr);
54 return buf;
57 static void vb2_vmalloc_put(void *buf_priv)
59 struct vb2_vmalloc_buf *buf = buf_priv;
61 if (atomic_dec_and_test(&buf->refcount)) {
62 printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n",
63 __func__, buf->vaddr);
64 vfree(buf->vaddr);
65 kfree(buf);
69 static void *vb2_vmalloc_vaddr(void *buf_priv)
71 struct vb2_vmalloc_buf *buf = buf_priv;
73 BUG_ON(!buf);
75 if (!buf->vaddr) {
76 printk(KERN_ERR "Address of an unallocated plane requested\n");
77 return NULL;
80 return buf->vaddr;
83 static unsigned int vb2_vmalloc_num_users(void *buf_priv)
85 struct vb2_vmalloc_buf *buf = buf_priv;
86 return atomic_read(&buf->refcount);
89 static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
91 struct vb2_vmalloc_buf *buf = buf_priv;
92 int ret;
94 if (!buf) {
95 printk(KERN_ERR "No memory to map\n");
96 return -EINVAL;
99 ret = remap_vmalloc_range(vma, buf->vaddr, 0);
100 if (ret) {
101 printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret);
102 return ret;
106 * Make sure that vm_areas for 2 buffers won't be merged together
108 vma->vm_flags |= VM_DONTEXPAND;
111 * Use common vm_area operations to track buffer refcount.
113 vma->vm_private_data = &buf->handler;
114 vma->vm_ops = &vb2_common_vm_ops;
116 vma->vm_ops->open(vma);
118 return 0;
121 const struct vb2_mem_ops vb2_vmalloc_memops = {
122 .alloc = vb2_vmalloc_alloc,
123 .put = vb2_vmalloc_put,
124 .vaddr = vb2_vmalloc_vaddr,
125 .mmap = vb2_vmalloc_mmap,
126 .num_users = vb2_vmalloc_num_users,
128 EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
130 MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
131 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
132 MODULE_LICENSE("GPL");