[media] mt9v011: Fixed incorrect value for the first valid column
[deliverable/linux.git] / drivers / media / video / videobuf2-vmalloc.c
1 /*
2 * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2
3 *
4 * Copyright (C) 2010 Samsung Electronics
5 *
6 * Author: Pawel Osciak <pawel@osciak.com>
7 *
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.
11 */
12
13 #include <linux/module.h>
14 #include <linux/mm.h>
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
17
18 #include <media/videobuf2-core.h>
19 #include <media/videobuf2-memops.h>
20
21 struct vb2_vmalloc_buf {
22 void *vaddr;
23 unsigned long size;
24 atomic_t refcount;
25 struct vb2_vmarea_handler handler;
26 };
27
28 static void vb2_vmalloc_put(void *buf_priv);
29
30 static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
31 {
32 struct vb2_vmalloc_buf *buf;
33
34 buf = kzalloc(sizeof *buf, GFP_KERNEL);
35 if (!buf)
36 return NULL;
37
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;
43
44 if (!buf->vaddr) {
45 printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size);
46 kfree(buf);
47 return NULL;
48 }
49
50 atomic_inc(&buf->refcount);
51 printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n",
52 buf->size, buf->vaddr);
53
54 return buf;
55 }
56
57 static void vb2_vmalloc_put(void *buf_priv)
58 {
59 struct vb2_vmalloc_buf *buf = buf_priv;
60
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);
66 }
67 }
68
69 static void *vb2_vmalloc_vaddr(void *buf_priv)
70 {
71 struct vb2_vmalloc_buf *buf = buf_priv;
72
73 BUG_ON(!buf);
74
75 if (!buf->vaddr) {
76 printk(KERN_ERR "Address of an unallocated plane requested\n");
77 return NULL;
78 }
79
80 return buf->vaddr;
81 }
82
83 static unsigned int vb2_vmalloc_num_users(void *buf_priv)
84 {
85 struct vb2_vmalloc_buf *buf = buf_priv;
86 return atomic_read(&buf->refcount);
87 }
88
89 static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
90 {
91 struct vb2_vmalloc_buf *buf = buf_priv;
92 int ret;
93
94 if (!buf) {
95 printk(KERN_ERR "No memory to map\n");
96 return -EINVAL;
97 }
98
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;
103 }
104
105 /*
106 * Make sure that vm_areas for 2 buffers won't be merged together
107 */
108 vma->vm_flags |= VM_DONTEXPAND;
109
110 /*
111 * Use common vm_area operations to track buffer refcount.
112 */
113 vma->vm_private_data = &buf->handler;
114 vma->vm_ops = &vb2_common_vm_ops;
115
116 vma->vm_ops->open(vma);
117
118 return 0;
119 }
120
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,
127 };
128 EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
129
130 MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2");
131 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
132 MODULE_LICENSE("GPL");
This page took 0.088659 seconds and 5 git commands to generate.