powerpc: use consistent types in mktree
[zen-stable.git] / drivers / media / video / videobuf-vmalloc.c
blob30ae30f99ccc38dd6f10bd0b0685e7e881111099
1 /*
2 * helper functions for vmalloc video4linux capture buffers
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.
9 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
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
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>
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>
28 #include <media/videobuf-vmalloc.h>
30 #define MAGIC_DMABUF 0x17760309
31 #define MAGIC_VMAL_MEM 0x18221223
33 #define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
34 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
36 static int debug;
37 module_param(debug, int, 0644);
39 MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
40 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
41 MODULE_LICENSE("GPL");
43 #define dprintk(level, fmt, arg...) if (debug >= level) \
44 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
47 /***************************************************************************/
49 static void
50 videobuf_vm_open(struct vm_area_struct *vma)
52 struct videobuf_mapping *map = vma->vm_private_data;
54 dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map,
55 map->count,vma->vm_start,vma->vm_end);
57 map->count++;
60 static void videobuf_vm_close(struct vm_area_struct *vma)
62 struct videobuf_mapping *map = vma->vm_private_data;
63 struct videobuf_queue *q = map->q;
64 int i;
66 dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
67 map->count, vma->vm_start, vma->vm_end);
69 map->count--;
70 if (0 == map->count) {
71 struct videobuf_vmalloc_memory *mem;
73 dprintk(1, "munmap %p q=%p\n", map, q);
74 mutex_lock(&q->vb_lock);
76 /* We need first to cancel streams, before unmapping */
77 if (q->streaming)
78 videobuf_queue_cancel(q);
80 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
81 if (NULL == q->bufs[i])
82 continue;
84 if (q->bufs[i]->map != map)
85 continue;
87 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.
95 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
97 /* vfree is not atomic - can't be
98 called with IRQ's disabled
100 dprintk(1, "%s: buf[%d] freeing (%p)\n",
101 __func__, i, mem->vmalloc);
103 vfree(mem->vmalloc);
104 mem->vmalloc = NULL;
107 q->bufs[i]->map = NULL;
108 q->bufs[i]->baddr = 0;
111 kfree(map);
113 mutex_unlock(&q->vb_lock);
116 return;
119 static struct vm_operations_struct videobuf_vm_ops =
121 .open = videobuf_vm_open,
122 .close = videobuf_vm_close,
125 /* ---------------------------------------------------------------------
126 * vmalloc handlers for the generic methods
129 /* Allocated area consists on 3 parts:
130 struct video_buffer
131 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
132 struct videobuf_dma_sg_memory
135 static void *__videobuf_alloc(size_t size)
137 struct videobuf_vmalloc_memory *mem;
138 struct videobuf_buffer *vb;
140 vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
142 mem = vb->priv = ((char *)vb)+size;
143 mem->magic=MAGIC_VMAL_MEM;
145 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
146 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
147 mem,(long)sizeof(*mem));
149 return vb;
152 static int __videobuf_iolock (struct videobuf_queue* q,
153 struct videobuf_buffer *vb,
154 struct v4l2_framebuffer *fbuf)
156 struct videobuf_vmalloc_memory *mem = vb->priv;
157 int pages;
159 BUG_ON(!mem);
161 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
163 switch (vb->memory) {
164 case V4L2_MEMORY_MMAP:
165 dprintk(1, "%s memory method MMAP\n", __func__);
167 /* 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;
172 break;
173 case V4L2_MEMORY_USERPTR:
174 pages = PAGE_ALIGN(vb->size);
176 dprintk(1, "%s memory method USERPTR\n", __func__);
178 #if 1
179 if (vb->baddr) {
180 printk(KERN_ERR "USERPTR is currently not supported\n");
181 return -EINVAL;
183 #endif
185 /* The only USERPTR currently supported is the one needed for
186 read() method.
189 mem->vmalloc = vmalloc_user(pages);
190 if (!mem->vmalloc) {
191 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
192 return -ENOMEM;
194 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
195 mem->vmalloc, pages);
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
202 if (!vb->baddr)
203 return 0;
205 /* FIXME: to properly support USERPTR, remap should occur.
206 The code below won't work, since mem->vma = NULL
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;
214 #endif
216 break;
217 case V4L2_MEMORY_OVERLAY:
218 default:
219 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
221 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
222 printk(KERN_ERR "Memory method currently unsupported.\n");
223 return -EINVAL;
226 return 0;
229 static int __videobuf_sync(struct videobuf_queue *q,
230 struct videobuf_buffer *buf)
232 return 0;
235 static int __videobuf_mmap_free(struct videobuf_queue *q)
237 unsigned int i;
239 dprintk(1, "%s\n", __func__);
240 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
241 if (q->bufs[i]) {
242 if (q->bufs[i]->map)
243 return -EBUSY;
247 return 0;
250 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
251 struct vm_area_struct *vma)
253 struct videobuf_vmalloc_memory *mem;
254 struct videobuf_mapping *map;
255 unsigned int first;
256 int retval, pages;
257 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
259 dprintk(1, "%s\n", __func__);
260 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
261 return -EINVAL;
263 /* look for first buffer to map */
264 for (first = 0; first < VIDEO_MAX_FRAME; first++) {
265 if (NULL == q->bufs[first])
266 continue;
268 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
269 continue;
270 if (q->bufs[first]->boff == offset)
271 break;
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;
279 /* create mapping + update buffer list */
280 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
281 if (NULL == map)
282 return -ENOMEM;
284 q->bufs[first]->map = map;
285 map->start = vma->vm_start;
286 map->end = vma->vm_end;
287 map->q = q;
289 q->bufs[first]->baddr = vma->vm_start;
291 mem = q->bufs[first]->priv;
292 BUG_ON(!mem);
293 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
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;
301 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
302 mem->vmalloc, pages);
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;
312 vma->vm_ops = &videobuf_vm_ops;
313 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
314 vma->vm_private_data = map;
316 dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
317 map, q, vma->vm_start, vma->vm_end,
318 (long int) q->bufs[first]->bsize,
319 vma->vm_pgoff, first);
321 videobuf_vm_open(vma);
323 return 0;
325 error:
326 mem = NULL;
327 kfree(map);
328 return -ENOMEM;
331 static int __videobuf_copy_to_user ( struct videobuf_queue *q,
332 char __user *data, size_t count,
333 int nonblocking )
335 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
336 BUG_ON (!mem);
337 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
339 BUG_ON (!mem->vmalloc);
341 /* copy to userspace */
342 if (count > q->read_buf->size - q->read_off)
343 count = q->read_buf->size - q->read_off;
345 if (copy_to_user(data, mem->vmalloc+q->read_off, count))
346 return -EFAULT;
348 return count;
351 static int __videobuf_copy_stream ( struct videobuf_queue *q,
352 char __user *data, size_t count, size_t pos,
353 int vbihack, int nonblocking )
355 unsigned int *fc;
356 struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
357 BUG_ON (!mem);
358 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
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);
371 /* copy stuff using the common method */
372 count = __videobuf_copy_to_user (q,data,count,nonblocking);
374 if ( (count==-EFAULT) && (0 == pos) )
375 return -EFAULT;
377 return count;
380 static struct videobuf_qtype_ops qops = {
381 .magic = MAGIC_QTYPE_OPS,
383 .alloc = __videobuf_alloc,
384 .iolock = __videobuf_iolock,
385 .sync = __videobuf_sync,
386 .mmap_free = __videobuf_mmap_free,
387 .mmap_mapper = __videobuf_mmap_mapper,
388 .video_copy_to_user = __videobuf_copy_to_user,
389 .copy_stream = __videobuf_copy_stream,
390 .vmalloc = videobuf_to_vmalloc,
393 void 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)
402 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
403 priv, &qops);
406 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
408 void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
410 struct videobuf_vmalloc_memory *mem=buf->priv;
411 BUG_ON (!mem);
412 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
414 return mem->vmalloc;
416 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
418 void videobuf_vmalloc_free (struct videobuf_buffer *buf)
420 struct videobuf_vmalloc_memory *mem = buf->priv;
422 /* 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.
428 if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
429 return;
431 if (!mem)
432 return;
434 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
436 vfree(mem->vmalloc);
437 mem->vmalloc = NULL;
439 return;
441 EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
444 * Local variables:
445 * c-basic-offset: 8
446 * End: