blob: d6a8a38dc9cb6bf5fe9ced21cbb5f832c7baa429 [file] [log] [blame]
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -03001/*
2 * helper functions for vmalloc video4linux capture buffers
3 *
Magnus Damm5d6aaf52008-07-16 21:27:49 -03004 * The functions expect the hardware being able to scatter gather
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -03005 * (i.e. the buffers are not linear in physical memory, but fragmented
6 * into PAGE_SIZE chunks). They also assume the driver does not need
7 * to touch the video data.
8 *
9 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/slab.h>
20#include <linux/interrupt.h>
21
22#include <linux/pci.h>
23#include <linux/vmalloc.h>
24#include <linux/pagemap.h>
25#include <asm/page.h>
26#include <asm/pgtable.h>
27
28#include <media/videobuf-vmalloc.h>
29
30#define MAGIC_DMABUF 0x17760309
31#define MAGIC_VMAL_MEM 0x18221223
32
Pawel Osciak7a022642010-03-17 04:01:04 -030033#define MAGIC_CHECK(is, should) \
34 if (unlikely((is) != (should))) { \
35 printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \
36 is, should); \
37 BUG(); \
38 }
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030039
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030040static int debug;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030041module_param(debug, int, 0644);
42
43MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
44MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
45MODULE_LICENSE("GPL");
46
Pawel Osciak7a022642010-03-17 04:01:04 -030047#define dprintk(level, fmt, arg...) \
48 if (debug >= level) \
49 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030050
51
52/***************************************************************************/
53
Pawel Osciak7a022642010-03-17 04:01:04 -030054static void videobuf_vm_open(struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030055{
56 struct videobuf_mapping *map = vma->vm_private_data;
57
Pawel Osciak7a022642010-03-17 04:01:04 -030058 dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
59 map->count, vma->vm_start, vma->vm_end);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030060
61 map->count++;
62}
63
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030064static void videobuf_vm_close(struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030065{
66 struct videobuf_mapping *map = vma->vm_private_data;
67 struct videobuf_queue *q = map->q;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030068 int i;
69
Pawel Osciak7a022642010-03-17 04:01:04 -030070 dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030071 map->count, vma->vm_start, vma->vm_end);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030072
73 map->count--;
74 if (0 == map->count) {
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030075 struct videobuf_vmalloc_memory *mem;
76
77 dprintk(1, "munmap %p q=%p\n", map, q);
Mauro Carvalho Chehab64f94772008-01-31 13:57:53 -030078 mutex_lock(&q->vb_lock);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030079
80 /* We need first to cancel streams, before unmapping */
81 if (q->streaming)
82 videobuf_queue_cancel(q);
83
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030084 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
85 if (NULL == q->bufs[i])
86 continue;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030087
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -030088 if (q->bufs[i]->map != map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030089 continue;
Mauro Carvalho Chehab123f8ef2007-09-06 20:11:35 -030090
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030091 mem = q->bufs[i]->priv;
92 if (mem) {
93 /* This callback is called only if kernel has
94 allocated memory and this memory is mmapped.
95 In this case, memory should be freed,
96 in order to do memory unmap.
97 */
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030098
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030099 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300100
101 /* vfree is not atomic - can't be
102 called with IRQ's disabled
103 */
104 dprintk(1, "%s: buf[%d] freeing (%p)\n",
105 __func__, i, mem->vmalloc);
106
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300107 vfree(mem->vmalloc);
108 mem->vmalloc = NULL;
109 }
110
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300111 q->bufs[i]->map = NULL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300112 q->bufs[i]->baddr = 0;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300113 }
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300114
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300115 kfree(map);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300116
117 mutex_unlock(&q->vb_lock);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300118 }
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300119
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300120 return;
121}
122
Pawel Osciak7a022642010-03-17 04:01:04 -0300123static const struct vm_operations_struct videobuf_vm_ops = {
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300124 .open = videobuf_vm_open,
125 .close = videobuf_vm_close,
126};
127
128/* ---------------------------------------------------------------------
129 * vmalloc handlers for the generic methods
130 */
131
132/* Allocated area consists on 3 parts:
133 struct video_buffer
134 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
Guennadi Liakhovetski07051352008-04-22 14:42:13 -0300135 struct videobuf_dma_sg_memory
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300136 */
137
138static void *__videobuf_alloc(size_t size)
139{
Brandon Philips384b8352008-02-04 20:52:21 -0300140 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300141 struct videobuf_buffer *vb;
142
Pawel Osciak7a022642010-03-17 04:01:04 -0300143 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
Pawel Osciakbee527f2010-02-22 13:10:06 -0300144 if (!vb)
145 return vb;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300146
Pawel Osciak7a022642010-03-17 04:01:04 -0300147 mem = vb->priv = ((char *)vb) + size;
148 mem->magic = MAGIC_VMAL_MEM;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300149
Pawel Osciak7a022642010-03-17 04:01:04 -0300150 dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
151 __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
152 mem, (long)sizeof(*mem));
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300153
154 return vb;
155}
156
Pawel Osciak7a022642010-03-17 04:01:04 -0300157static int __videobuf_iolock(struct videobuf_queue *q,
158 struct videobuf_buffer *vb,
159 struct v4l2_framebuffer *fbuf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300160{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300161 struct videobuf_vmalloc_memory *mem = vb->priv;
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300162 int pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300163
164 BUG_ON(!mem);
165
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300166 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300167
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300168 switch (vb->memory) {
169 case V4L2_MEMORY_MMAP:
170 dprintk(1, "%s memory method MMAP\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300171
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300172 /* All handling should be done by __videobuf_mmap_mapper() */
173 if (!mem->vmalloc) {
174 printk(KERN_ERR "memory is not alloced/mmapped.\n");
175 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300176 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300177 break;
178 case V4L2_MEMORY_USERPTR:
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300179 pages = PAGE_ALIGN(vb->size);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300180
181 dprintk(1, "%s memory method USERPTR\n", __func__);
182
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300183 if (vb->baddr) {
184 printk(KERN_ERR "USERPTR is currently not supported\n");
185 return -EINVAL;
186 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300187
188 /* The only USERPTR currently supported is the one needed for
Pawel Osciak7a022642010-03-17 04:01:04 -0300189 * read() method.
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300190 */
191
192 mem->vmalloc = vmalloc_user(pages);
193 if (!mem->vmalloc) {
194 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
195 return -ENOMEM;
196 }
197 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
198 mem->vmalloc, pages);
199
200#if 0
201 int rc;
202 /* Kernel userptr is used also by read() method. In this case,
203 there's no need to remap, since data will be copied to user
204 */
205 if (!vb->baddr)
206 return 0;
207
208 /* FIXME: to properly support USERPTR, remap should occur.
Hans Verkuilde1e5752008-07-26 08:37:58 -0300209 The code below won't work, since mem->vma = NULL
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300210 */
211 /* Try to remap memory */
212 rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
213 if (rc < 0) {
Pawel Osciak7a022642010-03-17 04:01:04 -0300214 printk(KERN_ERR "mmap: remap failed with error %d", rc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300215 return -ENOMEM;
216 }
217#endif
218
219 break;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300220 case V4L2_MEMORY_OVERLAY:
221 default:
222 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
223
224 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
225 printk(KERN_ERR "Memory method currently unsupported.\n");
226 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300227 }
228
229 return 0;
230}
231
232static int __videobuf_sync(struct videobuf_queue *q,
233 struct videobuf_buffer *buf)
234{
235 return 0;
236}
237
238static int __videobuf_mmap_free(struct videobuf_queue *q)
239{
240 unsigned int i;
241
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300242 dprintk(1, "%s\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300243 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
244 if (q->bufs[i]) {
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300245 if (q->bufs[i]->map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300246 return -EBUSY;
247 }
248 }
249
250 return 0;
251}
252
253static int __videobuf_mmap_mapper(struct videobuf_queue *q,
254 struct vm_area_struct *vma)
255{
Brandon Philips384b8352008-02-04 20:52:21 -0300256 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300257 struct videobuf_mapping *map;
258 unsigned int first;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300259 int retval, pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300260 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
261
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300262 dprintk(1, "%s\n", __func__);
263 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300264 return -EINVAL;
265
266 /* look for first buffer to map */
267 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
268 if (NULL == q->bufs[first])
269 continue;
270
271 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
272 continue;
273 if (q->bufs[first]->boff == offset)
274 break;
275 }
276 if (VIDEO_MAX_FRAME == first) {
Pawel Osciak7a022642010-03-17 04:01:04 -0300277 dprintk(1, "mmap app bug: offset invalid [offset=0x%lx]\n",
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300278 (vma->vm_pgoff << PAGE_SHIFT));
279 return -EINVAL;
280 }
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300281
282 /* create mapping + update buffer list */
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300283 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300284 if (NULL == map)
285 return -ENOMEM;
286
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300287 q->bufs[first]->map = map;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300288 map->start = vma->vm_start;
289 map->end = vma->vm_end;
290 map->q = q;
291
292 q->bufs[first]->baddr = vma->vm_start;
293
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300294 mem = q->bufs[first]->priv;
295 BUG_ON(!mem);
296 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
297
298 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
299 mem->vmalloc = vmalloc_user(pages);
300 if (!mem->vmalloc) {
301 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
302 goto error;
303 }
Pawel Osciak7a022642010-03-17 04:01:04 -0300304 dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300305
306 /* Try to remap memory */
307 retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
308 if (retval < 0) {
309 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
310 vfree(mem->vmalloc);
311 goto error;
312 }
313
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300314 vma->vm_ops = &videobuf_vm_ops;
315 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
316 vma->vm_private_data = map;
317
Pawel Osciak7a022642010-03-17 04:01:04 -0300318 dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300319 map, q, vma->vm_start, vma->vm_end,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300320 (long int) q->bufs[first]->bsize,
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300321 vma->vm_pgoff, first);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300322
323 videobuf_vm_open(vma);
324
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300325 return 0;
326
327error:
328 mem = NULL;
329 kfree(map);
330 return -ENOMEM;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300331}
332
Pawel Osciak7a022642010-03-17 04:01:04 -0300333static int __videobuf_copy_to_user(struct videobuf_queue *q,
334 char __user *data, size_t count,
335 int nonblocking)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300336{
Pawel Osciak7a022642010-03-17 04:01:04 -0300337 struct videobuf_vmalloc_memory *mem = q->read_buf->priv;
338 BUG_ON(!mem);
339 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300340
Pawel Osciak7a022642010-03-17 04:01:04 -0300341 BUG_ON(!mem->vmalloc);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300342
343 /* copy to userspace */
344 if (count > q->read_buf->size - q->read_off)
345 count = q->read_buf->size - q->read_off;
346
347 if (copy_to_user(data, mem->vmalloc+q->read_off, count))
348 return -EFAULT;
349
350 return count;
351}
352
Pawel Osciak7a022642010-03-17 04:01:04 -0300353static int __videobuf_copy_stream(struct videobuf_queue *q,
354 char __user *data, size_t count, size_t pos,
355 int vbihack, int nonblocking)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300356{
Pawel Osciak7a022642010-03-17 04:01:04 -0300357 unsigned int *fc;
358 struct videobuf_vmalloc_memory *mem = q->read_buf->priv;
359 BUG_ON(!mem);
360 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300361
362 if (vbihack) {
363 /* dirty, undocumented hack -- pass the frame counter
364 * within the last four bytes of each vbi data block.
365 * We need that one to maintain backward compatibility
366 * to all vbi decoding software out there ... */
Pawel Osciak7a022642010-03-17 04:01:04 -0300367 fc = (unsigned int *)mem->vmalloc;
368 fc += (q->read_buf->size >> 2) - 1;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300369 *fc = q->read_buf->field_count >> 1;
Pawel Osciak7a022642010-03-17 04:01:04 -0300370 dprintk(1, "vbihack: %d\n", *fc);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300371 }
372
373 /* copy stuff using the common method */
Pawel Osciak7a022642010-03-17 04:01:04 -0300374 count = __videobuf_copy_to_user(q, data, count, nonblocking);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300375
Pawel Osciak7a022642010-03-17 04:01:04 -0300376 if ((count == -EFAULT) && (0 == pos))
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300377 return -EFAULT;
378
379 return count;
380}
381
382static struct videobuf_qtype_ops qops = {
383 .magic = MAGIC_QTYPE_OPS,
384
385 .alloc = __videobuf_alloc,
386 .iolock = __videobuf_iolock,
387 .sync = __videobuf_sync,
388 .mmap_free = __videobuf_mmap_free,
389 .mmap_mapper = __videobuf_mmap_mapper,
Al Viro13bcd5d2007-10-13 08:25:24 +0100390 .video_copy_to_user = __videobuf_copy_to_user,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300391 .copy_stream = __videobuf_copy_stream,
Mauro Carvalho Chehab59d34482008-04-13 15:10:00 -0300392 .vmalloc = videobuf_to_vmalloc,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300393};
394
Pawel Osciak7a022642010-03-17 04:01:04 -0300395void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300396 const struct videobuf_queue_ops *ops,
Jonathan Corbetf8b0bca2009-11-23 14:29:35 -0300397 struct device *dev,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300398 spinlock_t *irqlock,
399 enum v4l2_buf_type type,
400 enum v4l2_field field,
401 unsigned int msize,
402 void *priv)
403{
Mauro Carvalho Chehabd4cae5a2007-10-08 12:20:02 -0300404 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
405 priv, &qops);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300406}
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300407EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
408
Pawel Osciak7a022642010-03-17 04:01:04 -0300409void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300410{
Pawel Osciak7a022642010-03-17 04:01:04 -0300411 struct videobuf_vmalloc_memory *mem = buf->priv;
412 BUG_ON(!mem);
413 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300414
415 return mem->vmalloc;
416}
417EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
418
Pawel Osciak7a022642010-03-17 04:01:04 -0300419void videobuf_vmalloc_free(struct videobuf_buffer *buf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300420{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300421 struct videobuf_vmalloc_memory *mem = buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300422
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300423 /* mmapped memory can't be freed here, otherwise mmapped region
424 would be released, while still needed. In this case, the memory
425 release should happen inside videobuf_vm_close().
426 So, it should free memory only if the memory were allocated for
427 read() operation.
428 */
Mauro Carvalho Chehab5993a662009-01-23 21:35:12 -0300429 if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300430 return;
431
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300432 if (!mem)
433 return;
434
435 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300436
437 vfree(mem->vmalloc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300438 mem->vmalloc = NULL;
439
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300440 return;
441}
442EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
443