blob: 1365c651c1777bd5f7973281f26baccdad6c8995 [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
Pawel Osciak7a022642010-03-17 04:01:04 -030033#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 }
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030039
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030040static int debug;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030041module_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
Pawel Osciak7a022642010-03-17 04:01:04 -030047#define dprintk(level, fmt, arg...) \
48 if (debug >= level) \
49 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030050
51
52/***************************************************************************/
53
Pawel Osciak7a022642010-03-17 04:01:04 -030054static void videobuf_vm_open(struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030055{
56 struct videobuf_mapping *map = vma->vm_private_data;
Al Viroa242f422013-05-09 15:03:33 -030057 struct videobuf_queue *q = map->q;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030058
Pawel Osciak7a022642010-03-17 04:01:04 -030059 dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
60 map->count, vma->vm_start, vma->vm_end);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030061
Al Viroa242f422013-05-09 15:03:33 -030062 videobuf_queue_lock(q);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030063 map->count++;
Al Viroa242f422013-05-09 15:03:33 -030064 videobuf_queue_unlock(q);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030065}
66
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030067static void videobuf_vm_close(struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030068{
69 struct videobuf_mapping *map = vma->vm_private_data;
70 struct videobuf_queue *q = map->q;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030071 int i;
72
Pawel Osciak7a022642010-03-17 04:01:04 -030073 dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030074 map->count, vma->vm_start, vma->vm_end);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030075
Al Viroa242f422013-05-09 15:03:33 -030076 videobuf_queue_lock(q);
77 if (!--map->count) {
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030078 struct videobuf_vmalloc_memory *mem;
79
80 dprintk(1, "munmap %p q=%p\n", map, q);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -030081
82 /* We need first to cancel streams, before unmapping */
83 if (q->streaming)
84 videobuf_queue_cancel(q);
85
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030086 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
87 if (NULL == q->bufs[i])
88 continue;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030089
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -030090 if (q->bufs[i]->map != map)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -030091 continue;
Mauro Carvalho Chehab123f8ef2007-09-06 20:11:35 -030092
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -030093 mem = q->bufs[i]->priv;
94 if (mem) {
95 /* This callback is called only if kernel has
96 allocated memory and this memory is mmapped.
97 In this case, memory should be freed,
98 in order to do memory unmap.
99 */
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300100
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300101 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300102
103 /* vfree is not atomic - can't be
104 called with IRQ's disabled
105 */
106 dprintk(1, "%s: buf[%d] freeing (%p)\n",
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300107 __func__, i, mem->vaddr);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300108
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300109 vfree(mem->vaddr);
110 mem->vaddr = NULL;
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300111 }
112
Mauro Carvalho Chehab851c0c92007-09-27 18:25:44 -0300113 q->bufs[i]->map = NULL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300114 q->bufs[i]->baddr = 0;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300115 }
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300116
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300117 kfree(map);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300118
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300119 }
Al Viroa242f422013-05-09 15:03:33 -0300120 videobuf_queue_unlock(q);
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300121
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300122 return;
123}
124
Pawel Osciak7a022642010-03-17 04:01:04 -0300125static const struct vm_operations_struct videobuf_vm_ops = {
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300126 .open = videobuf_vm_open,
127 .close = videobuf_vm_close,
128};
129
130/* ---------------------------------------------------------------------
131 * vmalloc handlers for the generic methods
132 */
133
134/* Allocated area consists on 3 parts:
135 struct video_buffer
136 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
Guennadi Liakhovetski07051352008-04-22 14:42:13 -0300137 struct videobuf_dma_sg_memory
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300138 */
139
Pawel Osciak33c38282010-05-11 10:36:28 -0300140static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300141{
Brandon Philips384b8352008-02-04 20:52:21 -0300142 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300143 struct videobuf_buffer *vb;
144
Pawel Osciak7a022642010-03-17 04:01:04 -0300145 vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
Pawel Osciakbee527f2010-02-22 13:10:06 -0300146 if (!vb)
147 return vb;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300148
Pawel Osciak7a022642010-03-17 04:01:04 -0300149 mem = vb->priv = ((char *)vb) + size;
150 mem->magic = MAGIC_VMAL_MEM;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300151
Pawel Osciak7a022642010-03-17 04:01:04 -0300152 dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
153 __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
154 mem, (long)sizeof(*mem));
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300155
156 return vb;
157}
158
Pawel Osciak7a022642010-03-17 04:01:04 -0300159static int __videobuf_iolock(struct videobuf_queue *q,
160 struct videobuf_buffer *vb,
161 struct v4l2_framebuffer *fbuf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300162{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300163 struct videobuf_vmalloc_memory *mem = vb->priv;
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300164 int pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300165
166 BUG_ON(!mem);
167
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300168 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300169
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300170 switch (vb->memory) {
171 case V4L2_MEMORY_MMAP:
172 dprintk(1, "%s memory method MMAP\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300173
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300174 /* All handling should be done by __videobuf_mmap_mapper() */
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300175 if (!mem->vaddr) {
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300176 printk(KERN_ERR "memory is not alloced/mmapped.\n");
177 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300178 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300179 break;
180 case V4L2_MEMORY_USERPTR:
Mauro Carvalho Chehabaa9479e2008-04-13 15:07:56 -0300181 pages = PAGE_ALIGN(vb->size);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300182
183 dprintk(1, "%s memory method USERPTR\n", __func__);
184
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300185 if (vb->baddr) {
186 printk(KERN_ERR "USERPTR is currently not supported\n");
187 return -EINVAL;
188 }
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300189
190 /* The only USERPTR currently supported is the one needed for
Pawel Osciak7a022642010-03-17 04:01:04 -0300191 * read() method.
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300192 */
193
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300194 mem->vaddr = vmalloc_user(pages);
195 if (!mem->vaddr) {
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300196 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
197 return -ENOMEM;
198 }
199 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300200 mem->vaddr, pages);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300201
202#if 0
203 int rc;
204 /* Kernel userptr is used also by read() method. In this case,
205 there's no need to remap, since data will be copied to user
206 */
207 if (!vb->baddr)
208 return 0;
209
210 /* FIXME: to properly support USERPTR, remap should occur.
Hans Verkuilde1e5752008-07-26 08:37:58 -0300211 The code below won't work, since mem->vma = NULL
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300212 */
213 /* Try to remap memory */
214 rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
215 if (rc < 0) {
Pawel Osciak7a022642010-03-17 04:01:04 -0300216 printk(KERN_ERR "mmap: remap failed with error %d", rc);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300217 return -ENOMEM;
218 }
219#endif
220
221 break;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300222 case V4L2_MEMORY_OVERLAY:
223 default:
224 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
225
226 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
227 printk(KERN_ERR "Memory method currently unsupported.\n");
228 return -EINVAL;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300229 }
230
231 return 0;
232}
233
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300234static int __videobuf_mmap_mapper(struct videobuf_queue *q,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300235 struct videobuf_buffer *buf,
236 struct vm_area_struct *vma)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300237{
Brandon Philips384b8352008-02-04 20:52:21 -0300238 struct videobuf_vmalloc_memory *mem;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300239 struct videobuf_mapping *map;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300240 int retval, pages;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300241
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300242 dprintk(1, "%s\n", __func__);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300243
244 /* create mapping + update buffer list */
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300245 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300246 if (NULL == map)
247 return -ENOMEM;
248
Hans Verkuil0b62b732010-03-28 09:09:05 -0300249 buf->map = map;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300250 map->q = q;
251
Hans Verkuil0b62b732010-03-28 09:09:05 -0300252 buf->baddr = vma->vm_start;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300253
Hans Verkuil0b62b732010-03-28 09:09:05 -0300254 mem = buf->priv;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300255 BUG_ON(!mem);
256 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
257
258 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300259 mem->vaddr = vmalloc_user(pages);
260 if (!mem->vaddr) {
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300261 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
262 goto error;
263 }
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300264 dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300265
266 /* Try to remap memory */
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300267 retval = remap_vmalloc_range(vma, mem->vaddr, 0);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300268 if (retval < 0) {
269 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300270 vfree(mem->vaddr);
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300271 goto error;
272 }
273
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300274 vma->vm_ops = &videobuf_vm_ops;
Konstantin Khlebnikov314e51b2012-10-08 16:29:02 -0700275 vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300276 vma->vm_private_data = map;
277
Pawel Osciak7a022642010-03-17 04:01:04 -0300278 dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300279 map, q, vma->vm_start, vma->vm_end,
Hans Verkuil0b62b732010-03-28 09:09:05 -0300280 (long int)buf->bsize,
281 vma->vm_pgoff, buf->i);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300282
283 videobuf_vm_open(vma);
284
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300285 return 0;
286
287error:
288 mem = NULL;
289 kfree(map);
290 return -ENOMEM;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300291}
292
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300293static struct videobuf_qtype_ops qops = {
294 .magic = MAGIC_QTYPE_OPS,
295
Pawel Osciak33c38282010-05-11 10:36:28 -0300296 .alloc_vb = __videobuf_alloc_vb,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300297 .iolock = __videobuf_iolock,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300298 .mmap_mapper = __videobuf_mmap_mapper,
Hans Verkuil037c75e2010-03-28 08:18:37 -0300299 .vaddr = videobuf_to_vmalloc,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300300};
301
Pawel Osciak7a022642010-03-17 04:01:04 -0300302void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
Jonathan Corbet38a54f32009-11-17 19:43:41 -0300303 const struct videobuf_queue_ops *ops,
Jonathan Corbetf8b0bca2009-11-23 14:29:35 -0300304 struct device *dev,
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300305 spinlock_t *irqlock,
306 enum v4l2_buf_type type,
307 enum v4l2_field field,
308 unsigned int msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300309 void *priv,
310 struct mutex *ext_lock)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300311{
Mauro Carvalho Chehabd4cae5a2007-10-08 12:20:02 -0300312 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
Hans Verkuil08bff032010-09-20 17:39:46 -0300313 priv, &qops, ext_lock);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300314}
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300315EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
316
Pawel Osciak7a022642010-03-17 04:01:04 -0300317void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300318{
Pawel Osciak7a022642010-03-17 04:01:04 -0300319 struct videobuf_vmalloc_memory *mem = buf->priv;
320 BUG_ON(!mem);
321 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300322
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300323 return mem->vaddr;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300324}
325EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
326
Pawel Osciak7a022642010-03-17 04:01:04 -0300327void videobuf_vmalloc_free(struct videobuf_buffer *buf)
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300328{
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300329 struct videobuf_vmalloc_memory *mem = buf->priv;
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300330
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300331 /* mmapped memory can't be freed here, otherwise mmapped region
332 would be released, while still needed. In this case, the memory
333 release should happen inside videobuf_vm_close().
334 So, it should free memory only if the memory were allocated for
335 read() operation.
336 */
Mauro Carvalho Chehab5993a662009-01-23 21:35:12 -0300337 if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
Mauro Carvalho Chehabaaea56a2008-04-13 14:58:43 -0300338 return;
339
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300340 if (!mem)
341 return;
342
343 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300344
Laurent Pinchartbb6dbe72010-05-11 10:36:34 -0300345 vfree(mem->vaddr);
346 mem->vaddr = NULL;
Mauro Carvalho Chehab968ced72008-04-13 14:58:21 -0300347
Mauro Carvalho Chehab87b9ad02007-08-02 23:31:33 -0300348 return;
349}
350EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
351