• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/media/video/
1/*
2 * helper functions for vmalloc video4linux capture buffers
3 *
4 * The functions expect the hardware being able to scatter gather
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)						\
34	if (unlikely((is) != (should))) {				\
35		printk(KERN_ERR "magic mismatch: %x (expected %x)\n",	\
36				is, should);				\
37		BUG();							\
38	}
39
40static int debug;
41module_param(debug, int, 0644);
42
43MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
44MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
45MODULE_LICENSE("GPL");
46
47#define dprintk(level, fmt, arg...)					\
48	if (debug >= level)						\
49		printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
50
51
52/***************************************************************************/
53
54static void videobuf_vm_open(struct vm_area_struct *vma)
55{
56	struct videobuf_mapping *map = vma->vm_private_data;
57
58	dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
59		map->count, vma->vm_start, vma->vm_end);
60
61	map->count++;
62}
63
64static void videobuf_vm_close(struct vm_area_struct *vma)
65{
66	struct videobuf_mapping *map = vma->vm_private_data;
67	struct videobuf_queue *q = map->q;
68	int i;
69
70	dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
71		map->count, vma->vm_start, vma->vm_end);
72
73	map->count--;
74	if (0 == map->count) {
75		struct videobuf_vmalloc_memory *mem;
76
77		dprintk(1, "munmap %p q=%p\n", map, q);
78		mutex_lock(&q->vb_lock);
79
80		/* We need first to cancel streams, before unmapping */
81		if (q->streaming)
82			videobuf_queue_cancel(q);
83
84		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
85			if (NULL == q->bufs[i])
86				continue;
87
88			if (q->bufs[i]->map != map)
89				continue;
90
91			mem = q->bufs[i]->priv;
92			if (mem) {
93				/* This callback is called only if kernel has
94				   allocated memory and this memory is mmapped.
95				   In this case, memory should be freed,
96				   in order to do memory unmap.
97				 */
98
99				MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
100
101				/* vfree is not atomic - can't be
102				   called with IRQ's disabled
103				 */
104				dprintk(1, "%s: buf[%d] freeing (%p)\n",
105					__func__, i, mem->vaddr);
106
107				vfree(mem->vaddr);
108				mem->vaddr = NULL;
109			}
110
111			q->bufs[i]->map   = NULL;
112			q->bufs[i]->baddr = 0;
113		}
114
115		kfree(map);
116
117		mutex_unlock(&q->vb_lock);
118	}
119
120	return;
121}
122
123static const struct vm_operations_struct videobuf_vm_ops = {
124	.open     = videobuf_vm_open,
125	.close    = videobuf_vm_close,
126};
127
128/* ---------------------------------------------------------------------
129 * vmalloc handlers for the generic methods
130 */
131
132/* Allocated area consists on 3 parts:
133	struct video_buffer
134	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
135	struct videobuf_dma_sg_memory
136 */
137
138static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
139{
140	struct videobuf_vmalloc_memory *mem;
141	struct videobuf_buffer *vb;
142
143	vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
144	if (!vb)
145		return vb;
146
147	mem = vb->priv = ((char *)vb) + size;
148	mem->magic = MAGIC_VMAL_MEM;
149
150	dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
151		__func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
152		mem, (long)sizeof(*mem));
153
154	return vb;
155}
156
157static int __videobuf_iolock(struct videobuf_queue *q,
158			     struct videobuf_buffer *vb,
159			     struct v4l2_framebuffer *fbuf)
160{
161	struct videobuf_vmalloc_memory *mem = vb->priv;
162	int pages;
163
164	BUG_ON(!mem);
165
166	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
167
168	switch (vb->memory) {
169	case V4L2_MEMORY_MMAP:
170		dprintk(1, "%s memory method MMAP\n", __func__);
171
172		/* All handling should be done by __videobuf_mmap_mapper() */
173		if (!mem->vaddr) {
174			printk(KERN_ERR "memory is not alloced/mmapped.\n");
175			return -EINVAL;
176		}
177		break;
178	case V4L2_MEMORY_USERPTR:
179		pages = PAGE_ALIGN(vb->size);
180
181		dprintk(1, "%s memory method USERPTR\n", __func__);
182
183		if (vb->baddr) {
184			printk(KERN_ERR "USERPTR is currently not supported\n");
185			return -EINVAL;
186		}
187
188		/* The only USERPTR currently supported is the one needed for
189		 * read() method.
190		 */
191
192		mem->vaddr = vmalloc_user(pages);
193		if (!mem->vaddr) {
194			printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
195			return -ENOMEM;
196		}
197		dprintk(1, "vmalloc is at addr %p (%d pages)\n",
198			mem->vaddr, pages);
199
200
201		break;
202	case V4L2_MEMORY_OVERLAY:
203	default:
204		dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
205
206		/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
207		printk(KERN_ERR "Memory method currently unsupported.\n");
208		return -EINVAL;
209	}
210
211	return 0;
212}
213
214static int __videobuf_mmap_mapper(struct videobuf_queue *q,
215				  struct videobuf_buffer *buf,
216				  struct vm_area_struct *vma)
217{
218	struct videobuf_vmalloc_memory *mem;
219	struct videobuf_mapping *map;
220	int retval, pages;
221
222	dprintk(1, "%s\n", __func__);
223
224	/* create mapping + update buffer list */
225	map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
226	if (NULL == map)
227		return -ENOMEM;
228
229	buf->map = map;
230	map->q     = q;
231
232	buf->baddr = vma->vm_start;
233
234	mem = buf->priv;
235	BUG_ON(!mem);
236	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
237
238	pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
239	mem->vaddr = vmalloc_user(pages);
240	if (!mem->vaddr) {
241		printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
242		goto error;
243	}
244	dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
245
246	/* Try to remap memory */
247	retval = remap_vmalloc_range(vma, mem->vaddr, 0);
248	if (retval < 0) {
249		printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
250		vfree(mem->vaddr);
251		goto error;
252	}
253
254	vma->vm_ops          = &videobuf_vm_ops;
255	vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
256	vma->vm_private_data = map;
257
258	dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
259		map, q, vma->vm_start, vma->vm_end,
260		(long int)buf->bsize,
261		vma->vm_pgoff, buf->i);
262
263	videobuf_vm_open(vma);
264
265	return 0;
266
267error:
268	mem = NULL;
269	kfree(map);
270	return -ENOMEM;
271}
272
273static struct videobuf_qtype_ops qops = {
274	.magic        = MAGIC_QTYPE_OPS,
275
276	.alloc_vb     = __videobuf_alloc_vb,
277	.iolock       = __videobuf_iolock,
278	.mmap_mapper  = __videobuf_mmap_mapper,
279	.vaddr        = videobuf_to_vmalloc,
280};
281
282void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
283			 const struct videobuf_queue_ops *ops,
284			 struct device *dev,
285			 spinlock_t *irqlock,
286			 enum v4l2_buf_type type,
287			 enum v4l2_field field,
288			 unsigned int msize,
289			 void *priv)
290{
291	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
292				 priv, &qops);
293}
294EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
295
296void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
297{
298	struct videobuf_vmalloc_memory *mem = buf->priv;
299	BUG_ON(!mem);
300	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
301
302	return mem->vaddr;
303}
304EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
305
306void videobuf_vmalloc_free(struct videobuf_buffer *buf)
307{
308	struct videobuf_vmalloc_memory *mem = buf->priv;
309
310	/* mmapped memory can't be freed here, otherwise mmapped region
311	   would be released, while still needed. In this case, the memory
312	   release should happen inside videobuf_vm_close().
313	   So, it should free memory only if the memory were allocated for
314	   read() operation.
315	 */
316	if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
317		return;
318
319	if (!mem)
320		return;
321
322	MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
323
324	vfree(mem->vaddr);
325	mem->vaddr = NULL;
326
327	return;
328}
329EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
330