2 * helper functions for physically contiguous capture buffers
4 * The functions support hardware lacking scatter gather support
5 * (i.e. the buffers must be linear in physical memory)
7 * Copyright (c) 2008 Magnus Damm
9 * Based on videobuf-vmalloc.c,
10 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2
17 #include <linux/init.h>
18 #include <linux/module.h>
20 #include <linux/pagemap.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/sched.h>
23 #include <media/videobuf-dma-contig.h>
25 struct videobuf_dma_contig_memory {
28 dma_addr_t dma_handle;
33 #define MAGIC_DC_MEM 0x0733ac61
34 #define MAGIC_CHECK(is, should) \
35 if (unlikely((is) != (should))) { \
36 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
41 videobuf_vm_open(struct vm_area_struct *vma)
43 struct videobuf_mapping *map = vma->vm_private_data;
45 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
46 map, map->count, vma->vm_start, vma->vm_end);
51 static void videobuf_vm_close(struct vm_area_struct *vma)
53 struct videobuf_mapping *map = vma->vm_private_data;
54 struct videobuf_queue *q = map->q;
57 dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
58 map, map->count, vma->vm_start, vma->vm_end);
61 if (0 == map->count) {
62 struct videobuf_dma_contig_memory *mem;
64 dev_dbg(map->q->dev, "munmap %p q=%p\n", map, q);
65 mutex_lock(&q->vb_lock);
67 /* We need first to cancel streams, before unmapping */
69 videobuf_queue_cancel(q);
71 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
72 if (NULL == q->bufs[i])
75 if (q->bufs[i]->map != map)
78 mem = q->bufs[i]->priv;
80 /* This callback is called only if kernel has
81 allocated memory and this memory is mmapped.
82 In this case, memory should be freed,
83 in order to do memory unmap.
86 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
88 /* vfree is not atomic - can't be
89 called with IRQ's disabled
91 dev_dbg(map->q->dev, "buf[%d] freeing %p\n",
94 dma_free_coherent(q->dev, mem->size,
95 mem->vaddr, mem->dma_handle);
99 q->bufs[i]->map = NULL;
100 q->bufs[i]->baddr = 0;
105 mutex_unlock(&q->vb_lock);
109 static const struct vm_operations_struct videobuf_vm_ops = {
110 .open = videobuf_vm_open,
111 .close = videobuf_vm_close,
115 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
116 * @mem: per-buffer private videobuf-dma-contig data
118 * This function resets the user space pointer
120 static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
128 * videobuf_dma_contig_user_get() - setup user space memory pointer
129 * @mem: per-buffer private videobuf-dma-contig data
130 * @vb: video buffer to map
132 * This function validates and sets up a pointer to user space memory.
133 * Only physically contiguous pfn-mapped memory is accepted.
135 * Returns 0 if successful.
137 static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
138 struct videobuf_buffer *vb)
140 struct mm_struct *mm = current->mm;
141 struct vm_area_struct *vma;
142 unsigned long prev_pfn, this_pfn;
143 unsigned long pages_done, user_address;
146 mem->size = PAGE_ALIGN(vb->size);
150 down_read(&mm->mmap_sem);
152 vma = find_vma(mm, vb->baddr);
156 if ((vb->baddr + mem->size) > vma->vm_end)
160 prev_pfn = 0; /* kill warning */
161 user_address = vb->baddr;
163 while (pages_done < (mem->size >> PAGE_SHIFT)) {
164 ret = follow_pfn(vma, user_address, &this_pfn);
169 mem->dma_handle = this_pfn << PAGE_SHIFT;
170 else if (this_pfn != (prev_pfn + 1))
177 user_address += PAGE_SIZE;
185 up_read(¤t->mm->mmap_sem);
190 static void *__videobuf_alloc(size_t size)
192 struct videobuf_dma_contig_memory *mem;
193 struct videobuf_buffer *vb;
195 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
197 mem = vb->priv = ((char *)vb) + size;
198 mem->magic = MAGIC_DC_MEM;
204 static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
206 struct videobuf_dma_contig_memory *mem = buf->priv;
209 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
214 static int __videobuf_iolock(struct videobuf_queue *q,
215 struct videobuf_buffer *vb,
216 struct v4l2_framebuffer *fbuf)
218 struct videobuf_dma_contig_memory *mem = vb->priv;
221 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
223 switch (vb->memory) {
224 case V4L2_MEMORY_MMAP:
225 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
227 /* All handling should be done by __videobuf_mmap_mapper() */
229 dev_err(q->dev, "memory is not alloced/mmapped.\n");
233 case V4L2_MEMORY_USERPTR:
234 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
236 /* handle pointer from user space */
238 return videobuf_dma_contig_user_get(mem, vb);
240 /* allocate memory for the read() method */
241 mem->size = PAGE_ALIGN(vb->size);
242 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
243 &mem->dma_handle, GFP_KERNEL);
245 dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
250 dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
251 mem->vaddr, mem->size);
253 case V4L2_MEMORY_OVERLAY:
254 break; /* ddl@rock-chips.com : nzy modify V4L2_MEMORY_OVERLAY */
256 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
264 static int __videobuf_mmap_free(struct videobuf_queue *q)
268 dev_dbg(q->dev, "%s\n", __func__);
269 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
270 if (q->bufs[i] && q->bufs[i]->map)
277 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
278 struct vm_area_struct *vma)
280 struct videobuf_dma_contig_memory *mem;
281 struct videobuf_mapping *map;
284 unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
286 dev_dbg(q->dev, "%s\n", __func__);
287 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
290 /* look for first buffer to map */
291 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
295 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
297 if (q->bufs[first]->boff == offset)
300 if (VIDEO_MAX_FRAME == first) {
301 dev_dbg(q->dev, "invalid user space offset [offset=0x%lx]\n",
306 /* create mapping + update buffer list */
307 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
311 q->bufs[first]->map = map;
312 map->start = vma->vm_start;
313 map->end = vma->vm_end;
316 q->bufs[first]->baddr = vma->vm_start;
318 mem = q->bufs[first]->priv;
320 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
322 mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
323 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
324 &mem->dma_handle, GFP_KERNEL);
326 dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
330 dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
331 mem->vaddr, mem->size);
333 /* Try to remap memory */
335 size = vma->vm_end - vma->vm_start;
336 size = (size < mem->size) ? size : mem->size;
338 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
339 retval = remap_pfn_range(vma, vma->vm_start,
340 mem->dma_handle >> PAGE_SHIFT,
341 size, vma->vm_page_prot);
343 dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
344 dma_free_coherent(q->dev, mem->size,
345 mem->vaddr, mem->dma_handle);
349 vma->vm_ops = &videobuf_vm_ops;
350 vma->vm_flags |= VM_DONTEXPAND;
351 vma->vm_private_data = map;
353 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
354 map, q, vma->vm_start, vma->vm_end,
355 (long int) q->bufs[first]->bsize,
356 vma->vm_pgoff, first);
358 videobuf_vm_open(vma);
367 static int __videobuf_copy_to_user(struct videobuf_queue *q,
368 char __user *data, size_t count,
371 struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
375 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
378 /* copy to userspace */
379 if (count > q->read_buf->size - q->read_off)
380 count = q->read_buf->size - q->read_off;
384 if (copy_to_user(data, vaddr + q->read_off, count))
390 static int __videobuf_copy_stream(struct videobuf_queue *q,
391 char __user *data, size_t count, size_t pos,
392 int vbihack, int nonblocking)
395 struct videobuf_dma_contig_memory *mem = q->read_buf->priv;
398 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
401 /* dirty, undocumented hack -- pass the frame counter
402 * within the last four bytes of each vbi data block.
403 * We need that one to maintain backward compatibility
404 * to all vbi decoding software out there ... */
405 fc = (unsigned int *)mem->vaddr;
406 fc += (q->read_buf->size >> 2) - 1;
407 *fc = q->read_buf->field_count >> 1;
408 dev_dbg(q->dev, "vbihack: %d\n", *fc);
411 /* copy stuff using the common method */
412 count = __videobuf_copy_to_user(q, data, count, nonblocking);
414 if ((count == -EFAULT) && (pos == 0))
420 static struct videobuf_qtype_ops qops = {
421 .magic = MAGIC_QTYPE_OPS,
423 .alloc = __videobuf_alloc,
424 .iolock = __videobuf_iolock,
425 .mmap_free = __videobuf_mmap_free,
426 .mmap_mapper = __videobuf_mmap_mapper,
427 .video_copy_to_user = __videobuf_copy_to_user,
428 .copy_stream = __videobuf_copy_stream,
429 .vmalloc = __videobuf_to_vmalloc,
432 void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
433 struct videobuf_queue_ops *ops,
436 enum v4l2_buf_type type,
437 enum v4l2_field field,
441 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
444 EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
446 dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
448 struct videobuf_dma_contig_memory *mem = buf->priv;
451 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
453 return mem->dma_handle;
455 EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
457 void videobuf_dma_contig_free(struct videobuf_queue *q,
458 struct videobuf_buffer *buf)
460 struct videobuf_dma_contig_memory *mem = buf->priv;
462 /* mmapped memory can't be freed here, otherwise mmapped region
463 would be released, while still needed. In this case, the memory
464 release should happen inside videobuf_vm_close().
465 So, it should free memory only if the memory were allocated for
468 if (buf->memory != V4L2_MEMORY_USERPTR)
474 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
476 /* handle user space pointer case */
478 videobuf_dma_contig_user_put(mem);
483 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
486 EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
488 MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
489 MODULE_AUTHOR("Magnus Damm");
490 MODULE_LICENSE("GPL");