blob: 136e09383c061ae5a630e6e56b46dc69ad68892c [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
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
Alexey Dobriyanf0f37e22009-09-27 22:29:37 +0400119static const struct vm_operations_struct videobuf_vm_ops =
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300120{
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);
Pawel Osciakbee527f2010-02-22 13:10:06 -0300141 if (!vb)
142 return vb;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300143
144 mem = vb->priv = ((char *)vb)+size;
145 mem->magic=MAGIC_VMAL_MEM;
146
147 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
Harvey Harrison7e28adb2008-04-08 23:20:00 -0300148 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300149 mem,(long)sizeof(*mem));
150
151 return vb;
152}
153
154static int __videobuf_iolock (struct videobuf_queue* q,
155 struct videobuf_buffer *vb,
156 struct v4l2_framebuffer *fbuf)
157{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300158 struct videobuf_vmalloc_memory *mem = vb->priv;
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300159 int pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300160
161 BUG_ON(!mem);
162
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300163 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300164
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300165 switch (vb->memory) {
166 case V4L2_MEMORY_MMAP:
167 dprintk(1, "%s memory method MMAP\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300168
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300169 /* All handling should be done by __videobuf_mmap_mapper() */
170 if (!mem->vmalloc) {
171 printk(KERN_ERR "memory is not alloced/mmapped.\n");
172 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300173 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300174 break;
175 case V4L2_MEMORY_USERPTR:
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300176 pages = PAGE_ALIGN(vb->size);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300177
178 dprintk(1, "%s memory method USERPTR\n", __func__);
179
180#if 1
181 if (vb->baddr) {
182 printk(KERN_ERR "USERPTR is currently not supported\n");
183 return -EINVAL;
184 }
185#endif
186
187 /* The only USERPTR currently supported is the one needed for
188 read() method.
189 */
190
191 mem->vmalloc = vmalloc_user(pages);
192 if (!mem->vmalloc) {
193 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
194 return -ENOMEM;
195 }
196 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
197 mem->vmalloc, pages);
198
199#if 0
200 int rc;
201 /* Kernel userptr is used also by read() method. In this case,
202 there's no need to remap, since data will be copied to user
203 */
204 if (!vb->baddr)
205 return 0;
206
207 /* FIXME: to properly support USERPTR, remap should occur.
Hans Verkuilde1e5752008-07-26 08:37:58 -0300208 The code below won't work, since mem->vma = NULL
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300209 */
210 /* Try to remap memory */
211 rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
212 if (rc < 0) {
213 printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
214 return -ENOMEM;
215 }
216#endif
217
218 break;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300219 case V4L2_MEMORY_OVERLAY:
220 default:
221 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
222
223 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
224 printk(KERN_ERR "Memory method currently unsupported.\n");
225 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300226 }
227
228 return 0;
229}
230
231static int __videobuf_sync(struct videobuf_queue *q,
232 struct videobuf_buffer *buf)
233{
234 return 0;
235}
236
237static int __videobuf_mmap_free(struct videobuf_queue *q)
238{
239 unsigned int i;
240
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300241 dprintk(1, "%s\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300242 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
243 if (q->bufs[i]) {
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300244 if (q->bufs[i]->map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300245 return -EBUSY;
246 }
247 }
248
249 return 0;
250}
251
252static int __videobuf_mmap_mapper(struct videobuf_queue *q,
253 struct vm_area_struct *vma)
254{
Brandon Philips384b8352008-02-04 20:52:21 -0300255 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300256 struct videobuf_mapping *map;
257 unsigned int first;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300258 int retval, pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300259 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
260
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300261 dprintk(1, "%s\n", __func__);
262 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300263 return -EINVAL;
264
265 /* look for first buffer to map */
266 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
267 if (NULL == q->bufs[first])
268 continue;
269
270 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
271 continue;
272 if (q->bufs[first]->boff == offset)
273 break;
274 }
275 if (VIDEO_MAX_FRAME == first) {
276 dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
277 (vma->vm_pgoff << PAGE_SHIFT));
278 return -EINVAL;
279 }
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300280
281 /* create mapping + update buffer list */
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300282 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300283 if (NULL == map)
284 return -ENOMEM;
285
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300286 q->bufs[first]->map = map;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300287 map->start = vma->vm_start;
288 map->end = vma->vm_end;
289 map->q = q;
290
291 q->bufs[first]->baddr = vma->vm_start;
292
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300293 mem = q->bufs[first]->priv;
294 BUG_ON(!mem);
295 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
296
297 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
298 mem->vmalloc = vmalloc_user(pages);
299 if (!mem->vmalloc) {
300 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
301 goto error;
302 }
303 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
304 mem->vmalloc, pages);
305
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
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -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
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300333static int __videobuf_copy_to_user ( struct videobuf_queue *q,
334 char __user *data, size_t count,
335 int nonblocking )
336{
Brandon Philips384b8352008-02-04 20:52:21 -0300337 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300338 BUG_ON (!mem);
339 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
340
341 BUG_ON (!mem->vmalloc);
342
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
353static int __videobuf_copy_stream ( struct videobuf_queue *q,
354 char __user *data, size_t count, size_t pos,
355 int vbihack, int nonblocking )
356{
357 unsigned int *fc;
Brandon Philips384b8352008-02-04 20:52:21 -0300358 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300359 BUG_ON (!mem);
360 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
361
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 ... */
367 fc = (unsigned int*)mem->vmalloc;
368 fc += (q->read_buf->size>>2) -1;
369 *fc = q->read_buf->field_count >> 1;
370 dprintk(1,"vbihack: %d\n",*fc);
371 }
372
373 /* copy stuff using the common method */
374 count = __videobuf_copy_to_user (q,data,count,nonblocking);
375
376 if ( (count==-EFAULT) && (0 == pos) )
377 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
395void 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}
407
408EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
409
410void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
411{
Brandon Philips384b8352008-02-04 20:52:21 -0300412 struct videobuf_vmalloc_memory *mem=buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300413 BUG_ON (!mem);
414 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
415
416 return mem->vmalloc;
417}
418EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
419
420void videobuf_vmalloc_free (struct videobuf_buffer *buf)
421{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300422 struct videobuf_vmalloc_memory *mem = buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300423
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300424 /* mmapped memory can't be freed here, otherwise mmapped region
425 would be released, while still needed. In this case, the memory
426 release should happen inside videobuf_vm_close().
427 So, it should free memory only if the memory were allocated for
428 read() operation.
429 */
Mauro Carvalho Chehab5993a662009-01-23 21:35:12 -0300430 if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300431 return;
432
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300433 if (!mem)
434 return;
435
436 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300437
438 vfree(mem->vmalloc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300439 mem->vmalloc = NULL;
440
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300441 return;
442}
443EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
444
445/*
446 * Local variables:
447 * c-basic-offset: 8
448 * End:
449 */