blob: c91e1d8e38025d32c292d888cac3feeb20103d6d [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,
Mauro Carvalho Chehab59d34482008-04-13 15:10:00 -0300390 .vmalloc = videobuf_to_vmalloc,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300391};
392
393void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
394 struct videobuf_queue_ops *ops,
395 void *dev,
396 spinlock_t *irqlock,
397 enum v4l2_buf_type type,
398 enum v4l2_field field,
399 unsigned int msize,
400 void *priv)
401{
Mauro Carvalho Chehabd4cae5a2007-10-08 12:20:02 -0300402 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
403 priv, &qops);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300404}
405
406EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
407
408void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
409{
Brandon Philips384b8352008-02-04 20:52:21 -0300410 struct videobuf_vmalloc_memory *mem=buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300411 BUG_ON (!mem);
412 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
413
414 return mem->vmalloc;
415}
416EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
417
418void videobuf_vmalloc_free (struct videobuf_buffer *buf)
419{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300420 struct videobuf_vmalloc_memory *mem = buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300421
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300422 /* mmapped memory can't be freed here, otherwise mmapped region
423 would be released, while still needed. In this case, the memory
424 release should happen inside videobuf_vm_close().
425 So, it should free memory only if the memory were allocated for
426 read() operation.
427 */
428 if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
429 return;
430
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300431 if (!mem)
432 return;
433
434 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300435
436 vfree(mem->vmalloc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300437 mem->vmalloc = NULL;
438
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300439 return;
440}
441EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
442
443/*
444 * Local variables:
445 * c-basic-offset: 8
446 * End:
447 */