blob: d68d0273807baa3b7b800806dc4b4a76b9e8f618 [file] [log] [blame]
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -03001/*
2 * helper functions for vmalloc video4linux capture buffers
3 *
4 * The functions expect the hardware being able to scatter gatter
5 * (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
33#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
34 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
35
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030036static int debug;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030037module_param(debug, int, 0644);
38
39MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
40MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
41MODULE_LICENSE("GPL");
42
43#define dprintk(level, fmt, arg...) if (debug >= level) \
Brandon Philips493977f2007-11-30 22:37:28 -030044 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030045
46
47/***************************************************************************/
48
49static void
50videobuf_vm_open(struct vm_area_struct *vma)
51{
52 struct videobuf_mapping *map = vma->vm_private_data;
53
Brandon Philips0b296692007-12-08 23:05:53 -030054 dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030055 map->count,vma->vm_start,vma->vm_end);
56
57 map->count++;
58}
59
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030060static void videobuf_vm_close(struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030061{
62 struct videobuf_mapping *map = vma->vm_private_data;
63 struct videobuf_queue *q = map->q;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030064 int i;
65
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030066 dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
67 map->count, vma->vm_start, vma->vm_end);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030068
69 map->count--;
70 if (0 == map->count) {
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030071 struct videobuf_vmalloc_memory *mem;
72
73 dprintk(1, "munmap %p q=%p\n", map, q);
Mauro Carvalho Chehab64f94772008-01-31 13:57:53 -030074 mutex_lock(&q->vb_lock);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030075
76 /* We need first to cancel streams, before unmapping */
77 if (q->streaming)
78 videobuf_queue_cancel(q);
79
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030080 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
81 if (NULL == q->bufs[i])
82 continue;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030083
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -030084 if (q->bufs[i]->map != map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030085 continue;
Mauro Carvalho Chehab123f8ef2007-09-06 20:11:35 -030086
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030087 mem = q->bufs[i]->priv;
88 if (mem) {
89 /* This callback is called only if kernel has
90 allocated memory and this memory is mmapped.
91 In this case, memory should be freed,
92 in order to do memory unmap.
93 */
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030094
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030095 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030096
97 /* vfree is not atomic - can't be
98 called with IRQ's disabled
99 */
100 dprintk(1, "%s: buf[%d] freeing (%p)\n",
101 __func__, i, mem->vmalloc);
102
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300103 vfree(mem->vmalloc);
104 mem->vmalloc = NULL;
105 }
106
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300107 q->bufs[i]->map = NULL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300108 q->bufs[i]->baddr = 0;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300109 }
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300110
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300111 kfree(map);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300112
113 mutex_unlock(&q->vb_lock);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300114 }
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300115
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300116 return;
117}
118
119static struct vm_operations_struct videobuf_vm_ops =
120{
121 .open = videobuf_vm_open,
122 .close = videobuf_vm_close,
123};
124
125/* ---------------------------------------------------------------------
126 * vmalloc handlers for the generic methods
127 */
128
129/* Allocated area consists on 3 parts:
130 struct video_buffer
131 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
Guennadi Liakhovetski07051352008-04-22 14:42:13 -0300132 struct videobuf_dma_sg_memory
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300133 */
134
135static void *__videobuf_alloc(size_t size)
136{
Brandon Philips384b8352008-02-04 20:52:21 -0300137 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300138 struct videobuf_buffer *vb;
139
140 vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
141
142 mem = vb->priv = ((char *)vb)+size;
143 mem->magic=MAGIC_VMAL_MEM;
144
145 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300146 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300147 mem,(long)sizeof(*mem));
148
149 return vb;
150}
151
152static int __videobuf_iolock (struct videobuf_queue* q,
153 struct videobuf_buffer *vb,
154 struct v4l2_framebuffer *fbuf)
155{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300156 struct videobuf_vmalloc_memory *mem = vb->priv;
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300157 int pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300158
159 BUG_ON(!mem);
160
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300161 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300162
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300163 switch (vb->memory) {
164 case V4L2_MEMORY_MMAP:
165 dprintk(1, "%s memory method MMAP\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300166
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300167 /* All handling should be done by __videobuf_mmap_mapper() */
168 if (!mem->vmalloc) {
169 printk(KERN_ERR "memory is not alloced/mmapped.\n");
170 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300171 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300172 break;
173 case V4L2_MEMORY_USERPTR:
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300174 pages = PAGE_ALIGN(vb->size);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300175
176 dprintk(1, "%s memory method USERPTR\n", __func__);
177
178#if 1
179 if (vb->baddr) {
180 printk(KERN_ERR "USERPTR is currently not supported\n");
181 return -EINVAL;
182 }
183#endif
184
185 /* The only USERPTR currently supported is the one needed for
186 read() method.
187 */
188
189 mem->vmalloc = vmalloc_user(pages);
190 if (!mem->vmalloc) {
191 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
192 return -ENOMEM;
193 }
194 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
195 mem->vmalloc, pages);
196
197#if 0
198 int rc;
199 /* Kernel userptr is used also by read() method. In this case,
200 there's no need to remap, since data will be copied to user
201 */
202 if (!vb->baddr)
203 return 0;
204
205 /* FIXME: to properly support USERPTR, remap should occur.
206 The code bellow won't work, since mem->vma = NULL
207 */
208 /* Try to remap memory */
209 rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
210 if (rc < 0) {
211 printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
212 return -ENOMEM;
213 }
214#endif
215
216 break;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300217 case V4L2_MEMORY_OVERLAY:
218 default:
219 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
220
221 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
222 printk(KERN_ERR "Memory method currently unsupported.\n");
223 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300224 }
225
226 return 0;
227}
228
229static int __videobuf_sync(struct videobuf_queue *q,
230 struct videobuf_buffer *buf)
231{
232 return 0;
233}
234
235static int __videobuf_mmap_free(struct videobuf_queue *q)
236{
237 unsigned int i;
238
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300239 dprintk(1, "%s\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300240 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
241 if (q->bufs[i]) {
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300242 if (q->bufs[i]->map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300243 return -EBUSY;
244 }
245 }
246
247 return 0;
248}
249
250static int __videobuf_mmap_mapper(struct videobuf_queue *q,
251 struct vm_area_struct *vma)
252{
Brandon Philips384b8352008-02-04 20:52:21 -0300253 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300254 struct videobuf_mapping *map;
255 unsigned int first;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300256 int retval, pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300257 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
258
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300259 dprintk(1, "%s\n", __func__);
260 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300261 return -EINVAL;
262
263 /* look for first buffer to map */
264 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
265 if (NULL == q->bufs[first])
266 continue;
267
268 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
269 continue;
270 if (q->bufs[first]->boff == offset)
271 break;
272 }
273 if (VIDEO_MAX_FRAME == first) {
274 dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
275 (vma->vm_pgoff << PAGE_SHIFT));
276 return -EINVAL;
277 }
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300278
279 /* create mapping + update buffer list */
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300280 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300281 if (NULL == map)
282 return -ENOMEM;
283
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300284 q->bufs[first]->map = map;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300285 map->start = vma->vm_start;
286 map->end = vma->vm_end;
287 map->q = q;
288
289 q->bufs[first]->baddr = vma->vm_start;
290
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300291 mem = q->bufs[first]->priv;
292 BUG_ON(!mem);
293 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
294
295 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
296 mem->vmalloc = vmalloc_user(pages);
297 if (!mem->vmalloc) {
298 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
299 goto error;
300 }
301 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
302 mem->vmalloc, pages);
303
304 /* Try to remap memory */
305 retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
306 if (retval < 0) {
307 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
308 vfree(mem->vmalloc);
309 goto error;
310 }
311
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300312 vma->vm_ops = &videobuf_vm_ops;
313 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
314 vma->vm_private_data = map;
315
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300316 dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300317 map, q, vma->vm_start, vma->vm_end,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300318 (long int) q->bufs[first]->bsize,
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300319 vma->vm_pgoff, first);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300320
321 videobuf_vm_open(vma);
322
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300323 return 0;
324
325error:
326 mem = NULL;
327 kfree(map);
328 return -ENOMEM;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300329}
330
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300331static int __videobuf_copy_to_user ( struct videobuf_queue *q,
332 char __user *data, size_t count,
333 int nonblocking )
334{
Brandon Philips384b8352008-02-04 20:52:21 -0300335 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300336 BUG_ON (!mem);
337 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
338
339 BUG_ON (!mem->vmalloc);
340
341 /* copy to userspace */
342 if (count > q->read_buf->size - q->read_off)
343 count = q->read_buf->size - q->read_off;
344
345 if (copy_to_user(data, mem->vmalloc+q->read_off, count))
346 return -EFAULT;
347
348 return count;
349}
350
351static int __videobuf_copy_stream ( struct videobuf_queue *q,
352 char __user *data, size_t count, size_t pos,
353 int vbihack, int nonblocking )
354{
355 unsigned int *fc;
Brandon Philips384b8352008-02-04 20:52:21 -0300356 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300357 BUG_ON (!mem);
358 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
359
360 if (vbihack) {
361 /* dirty, undocumented hack -- pass the frame counter
362 * within the last four bytes of each vbi data block.
363 * We need that one to maintain backward compatibility
364 * to all vbi decoding software out there ... */
365 fc = (unsigned int*)mem->vmalloc;
366 fc += (q->read_buf->size>>2) -1;
367 *fc = q->read_buf->field_count >> 1;
368 dprintk(1,"vbihack: %d\n",*fc);
369 }
370
371 /* copy stuff using the common method */
372 count = __videobuf_copy_to_user (q,data,count,nonblocking);
373
374 if ( (count==-EFAULT) && (0 == pos) )
375 return -EFAULT;
376
377 return count;
378}
379
380static struct videobuf_qtype_ops qops = {
381 .magic = MAGIC_QTYPE_OPS,
382
383 .alloc = __videobuf_alloc,
384 .iolock = __videobuf_iolock,
385 .sync = __videobuf_sync,
386 .mmap_free = __videobuf_mmap_free,
387 .mmap_mapper = __videobuf_mmap_mapper,
Al Viro13bcd5d2007-10-13 08:25:24 +0100388 .video_copy_to_user = __videobuf_copy_to_user,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300389 .copy_stream = __videobuf_copy_stream,
390};
391
392void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
393 struct videobuf_queue_ops *ops,
394 void *dev,
395 spinlock_t *irqlock,
396 enum v4l2_buf_type type,
397 enum v4l2_field field,
398 unsigned int msize,
399 void *priv)
400{
Mauro Carvalho Chehabd4cae5a2007-10-08 12:20:02 -0300401 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
402 priv, &qops);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300403}
404
405EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
406
407void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
408{
Brandon Philips384b8352008-02-04 20:52:21 -0300409 struct videobuf_vmalloc_memory *mem=buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300410 BUG_ON (!mem);
411 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
412
413 return mem->vmalloc;
414}
415EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
416
417void videobuf_vmalloc_free (struct videobuf_buffer *buf)
418{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300419 struct videobuf_vmalloc_memory *mem = buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300420
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300421 /* mmapped memory can't be freed here, otherwise mmapped region
422 would be released, while still needed. In this case, the memory
423 release should happen inside videobuf_vm_close().
424 So, it should free memory only if the memory were allocated for
425 read() operation.
426 */
427 if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
428 return;
429
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300430 if (!mem)
431 return;
432
433 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300434
435 vfree(mem->vmalloc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300436 mem->vmalloc = NULL;
437
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300438 return;
439}
440EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
441
442/*
443 * Local variables:
444 * c-basic-offset: 8
445 * End:
446 */