]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/media/video/videobuf-dma-contig.c
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[net-next-2.6.git] / drivers / media / video / videobuf-dma-contig.c
CommitLineData
2cc45cf2
MD
1/*
2 * helper functions for physically contiguous capture buffers
3 *
4 * The functions support hardware lacking scatter gather support
5 * (i.e. the buffers must be linear in physical memory)
6 *
7 * Copyright (c) 2008 Magnus Damm
8 *
9 * Based on videobuf-vmalloc.c,
10 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
11 *
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
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
f19ad390 19#include <linux/mm.h>
720b17e7 20#include <linux/pagemap.h>
2cc45cf2 21#include <linux/dma-mapping.h>
f39c1ab3 22#include <linux/sched.h>
5a0e3ad6 23#include <linux/slab.h>
2cc45cf2
MD
24#include <media/videobuf-dma-contig.h>
25
26struct videobuf_dma_contig_memory {
27 u32 magic;
28 void *vaddr;
29 dma_addr_t dma_handle;
30 unsigned long size;
720b17e7 31 int is_userptr;
2cc45cf2
MD
32};
33
34#define MAGIC_DC_MEM 0x0733ac61
c60f2b5c
GL
35#define MAGIC_CHECK(is, should) \
36 if (unlikely((is) != (should))) { \
37 pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
38 BUG(); \
2cc45cf2
MD
39 }
40
41static void
42videobuf_vm_open(struct vm_area_struct *vma)
43{
44 struct videobuf_mapping *map = vma->vm_private_data;
45
46 dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
47 map, map->count, vma->vm_start, vma->vm_end);
48
49 map->count++;
50}
51
52static void videobuf_vm_close(struct vm_area_struct *vma)
53{
54 struct videobuf_mapping *map = vma->vm_private_data;
55 struct videobuf_queue *q = map->q;
56 int i;
57
f35f1bb8 58 dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
2cc45cf2
MD
59 map, map->count, vma->vm_start, vma->vm_end);
60
61 map->count--;
62 if (0 == map->count) {
63 struct videobuf_dma_contig_memory *mem;
64
f35f1bb8 65 dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
2cc45cf2
MD
66 mutex_lock(&q->vb_lock);
67
68 /* We need first to cancel streams, before unmapping */
69 if (q->streaming)
70 videobuf_queue_cancel(q);
71
72 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
73 if (NULL == q->bufs[i])
74 continue;
75
76 if (q->bufs[i]->map != map)
77 continue;
78
79 mem = q->bufs[i]->priv;
80 if (mem) {
81 /* This callback is called only if kernel has
82 allocated memory and this memory is mmapped.
83 In this case, memory should be freed,
84 in order to do memory unmap.
85 */
86
87 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
88
89 /* vfree is not atomic - can't be
90 called with IRQ's disabled
91 */
f35f1bb8 92 dev_dbg(q->dev, "buf[%d] freeing %p\n",
2cc45cf2
MD
93 i, mem->vaddr);
94
95 dma_free_coherent(q->dev, mem->size,
96 mem->vaddr, mem->dma_handle);
97 mem->vaddr = NULL;
98 }
99
100 q->bufs[i]->map = NULL;
101 q->bufs[i]->baddr = 0;
102 }
103
104 kfree(map);
105
106 mutex_unlock(&q->vb_lock);
107 }
108}
109
f0f37e2f 110static const struct vm_operations_struct videobuf_vm_ops = {
2cc45cf2
MD
111 .open = videobuf_vm_open,
112 .close = videobuf_vm_close,
113};
114
720b17e7
MD
115/**
116 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
117 * @mem: per-buffer private videobuf-dma-contig data
118 *
119 * This function resets the user space pointer
120 */
121static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
122{
123 mem->is_userptr = 0;
124 mem->dma_handle = 0;
125 mem->size = 0;
126}
127
128/**
129 * videobuf_dma_contig_user_get() - setup user space memory pointer
130 * @mem: per-buffer private videobuf-dma-contig data
131 * @vb: video buffer to map
132 *
133 * This function validates and sets up a pointer to user space memory.
134 * Only physically contiguous pfn-mapped memory is accepted.
135 *
136 * Returns 0 if successful.
137 */
138static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
139 struct videobuf_buffer *vb)
140{
141 struct mm_struct *mm = current->mm;
142 struct vm_area_struct *vma;
143 unsigned long prev_pfn, this_pfn;
144 unsigned long pages_done, user_address;
31bedfa5 145 unsigned int offset;
720b17e7
MD
146 int ret;
147
31bedfa5
MK
148 offset = vb->baddr & ~PAGE_MASK;
149 mem->size = PAGE_ALIGN(vb->size + offset);
720b17e7
MD
150 mem->is_userptr = 0;
151 ret = -EINVAL;
152
153 down_read(&mm->mmap_sem);
154
155 vma = find_vma(mm, vb->baddr);
156 if (!vma)
157 goto out_up;
158
159 if ((vb->baddr + mem->size) > vma->vm_end)
160 goto out_up;
161
162 pages_done = 0;
163 prev_pfn = 0; /* kill warning */
164 user_address = vb->baddr;
165
166 while (pages_done < (mem->size >> PAGE_SHIFT)) {
167 ret = follow_pfn(vma, user_address, &this_pfn);
168 if (ret)
169 break;
170
171 if (pages_done == 0)
31bedfa5 172 mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
720b17e7
MD
173 else if (this_pfn != (prev_pfn + 1))
174 ret = -EFAULT;
175
176 if (ret)
177 break;
178
179 prev_pfn = this_pfn;
180 user_address += PAGE_SIZE;
181 pages_done++;
182 }
183
184 if (!ret)
185 mem->is_userptr = 1;
186
187 out_up:
188 up_read(&current->mm->mmap_sem);
189
190 return ret;
191}
192
33c38283 193static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
2cc45cf2
MD
194{
195 struct videobuf_dma_contig_memory *mem;
196 struct videobuf_buffer *vb;
197
198 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
199 if (vb) {
200 mem = vb->priv = ((char *)vb) + size;
201 mem->magic = MAGIC_DC_MEM;
202 }
203
204 return vb;
205}
206
037c75eb 207static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
2cc45cf2
MD
208{
209 struct videobuf_dma_contig_memory *mem = buf->priv;
210
211 BUG_ON(!mem);
212 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
213
214 return mem->vaddr;
215}
216
217static int __videobuf_iolock(struct videobuf_queue *q,
218 struct videobuf_buffer *vb,
219 struct v4l2_framebuffer *fbuf)
220{
221 struct videobuf_dma_contig_memory *mem = vb->priv;
222
223 BUG_ON(!mem);
224 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
225
226 switch (vb->memory) {
227 case V4L2_MEMORY_MMAP:
228 dev_dbg(q->dev, "%s memory method MMAP\n", __func__);
229
230 /* All handling should be done by __videobuf_mmap_mapper() */
231 if (!mem->vaddr) {
232 dev_err(q->dev, "memory is not alloced/mmapped.\n");
233 return -EINVAL;
234 }
235 break;
236 case V4L2_MEMORY_USERPTR:
237 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
238
720b17e7 239 /* handle pointer from user space */
2cc45cf2 240 if (vb->baddr)
720b17e7 241 return videobuf_dma_contig_user_get(mem, vb);
2cc45cf2 242
720b17e7 243 /* allocate memory for the read() method */
2cc45cf2
MD
244 mem->size = PAGE_ALIGN(vb->size);
245 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
246 &mem->dma_handle, GFP_KERNEL);
247 if (!mem->vaddr) {
248 dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
249 mem->size);
250 return -ENOMEM;
251 }
252
253 dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
254 mem->vaddr, mem->size);
255 break;
256 case V4L2_MEMORY_OVERLAY:
257 default:
258 dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
259 __func__);
260 return -EINVAL;
261 }
262
263 return 0;
264}
265
2cc45cf2 266static int __videobuf_mmap_mapper(struct videobuf_queue *q,
0b62b737 267 struct videobuf_buffer *buf,
2cc45cf2
MD
268 struct vm_area_struct *vma)
269{
270 struct videobuf_dma_contig_memory *mem;
271 struct videobuf_mapping *map;
2cc45cf2 272 int retval;
0b62b737 273 unsigned long size;
2cc45cf2
MD
274
275 dev_dbg(q->dev, "%s\n", __func__);
2cc45cf2
MD
276
277 /* create mapping + update buffer list */
278 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
279 if (!map)
280 return -ENOMEM;
281
0b62b737 282 buf->map = map;
2cc45cf2
MD
283 map->q = q;
284
0b62b737 285 buf->baddr = vma->vm_start;
2cc45cf2 286
0b62b737 287 mem = buf->priv;
2cc45cf2
MD
288 BUG_ON(!mem);
289 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
290
0b62b737 291 mem->size = PAGE_ALIGN(buf->bsize);
2cc45cf2
MD
292 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
293 &mem->dma_handle, GFP_KERNEL);
294 if (!mem->vaddr) {
295 dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
296 mem->size);
297 goto error;
298 }
299 dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
300 mem->vaddr, mem->size);
301
302 /* Try to remap memory */
303
304 size = vma->vm_end - vma->vm_start;
305 size = (size < mem->size) ? size : mem->size;
306
307 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
308 retval = remap_pfn_range(vma, vma->vm_start,
309 mem->dma_handle >> PAGE_SHIFT,
310 size, vma->vm_page_prot);
311 if (retval) {
312 dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
313 dma_free_coherent(q->dev, mem->size,
314 mem->vaddr, mem->dma_handle);
315 goto error;
316 }
317
318 vma->vm_ops = &videobuf_vm_ops;
319 vma->vm_flags |= VM_DONTEXPAND;
320 vma->vm_private_data = map;
321
322 dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
323 map, q, vma->vm_start, vma->vm_end,
0b62b737
HV
324 (long int)buf->bsize,
325 vma->vm_pgoff, buf->i);
2cc45cf2
MD
326
327 videobuf_vm_open(vma);
328
329 return 0;
330
331error:
332 kfree(map);
333 return -ENOMEM;
334}
335
2cc45cf2
MD
336static struct videobuf_qtype_ops qops = {
337 .magic = MAGIC_QTYPE_OPS,
338
33c38283 339 .alloc_vb = __videobuf_alloc_vb,
2cc45cf2 340 .iolock = __videobuf_iolock,
2cc45cf2 341 .mmap_mapper = __videobuf_mmap_mapper,
037c75eb 342 .vaddr = __videobuf_to_vaddr,
2cc45cf2
MD
343};
344
345void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
38a54f35 346 const struct videobuf_queue_ops *ops,
2cc45cf2
MD
347 struct device *dev,
348 spinlock_t *irqlock,
349 enum v4l2_buf_type type,
350 enum v4l2_field field,
351 unsigned int msize,
352 void *priv)
353{
354 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
355 priv, &qops);
356}
357EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
358
359dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
360{
361 struct videobuf_dma_contig_memory *mem = buf->priv;
362
363 BUG_ON(!mem);
364 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
365
366 return mem->dma_handle;
367}
368EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
369
370void videobuf_dma_contig_free(struct videobuf_queue *q,
371 struct videobuf_buffer *buf)
372{
373 struct videobuf_dma_contig_memory *mem = buf->priv;
374
375 /* mmapped memory can't be freed here, otherwise mmapped region
376 would be released, while still needed. In this case, the memory
377 release should happen inside videobuf_vm_close().
378 So, it should free memory only if the memory were allocated for
379 read() operation.
380 */
720b17e7 381 if (buf->memory != V4L2_MEMORY_USERPTR)
2cc45cf2
MD
382 return;
383
384 if (!mem)
385 return;
386
387 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
388
720b17e7
MD
389 /* handle user space pointer case */
390 if (buf->baddr) {
391 videobuf_dma_contig_user_put(mem);
392 return;
393 }
394
395 /* read() method */
b2b476f5
PO
396 if (mem->vaddr) {
397 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
398 mem->vaddr = NULL;
399 }
2cc45cf2
MD
400}
401EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
402
403MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers");
404MODULE_AUTHOR("Magnus Damm");
405MODULE_LICENSE("GPL");