diff options
Diffstat (limited to 'drivers/media/video/videobuf-vmalloc.c')
-rw-r--r-- | drivers/media/video/videobuf-vmalloc.c | 349 |
1 files changed, 0 insertions, 349 deletions
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c deleted file mode 100644 index df142580e44c..000000000000 --- a/drivers/media/video/videobuf-vmalloc.c +++ /dev/null | |||
@@ -1,349 +0,0 @@ | |||
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 | |||
40 | static int debug; | ||
41 | module_param(debug, int, 0644); | ||
42 | |||
43 | MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); | ||
44 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
45 | MODULE_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 | |||
54 | static 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 | |||
64 | static 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 | videobuf_queue_lock(q); | ||
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 | videobuf_queue_unlock(q); | ||
118 | } | ||
119 | |||
120 | return; | ||
121 | } | ||
122 | |||
123 | static 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 | |||
138 | static 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 | |||
157 | static 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 | #if 0 | ||
201 | int rc; | ||
202 | /* Kernel userptr is used also by read() method. In this case, | ||
203 | there's no need to remap, since data will be copied to user | ||
204 | */ | ||
205 | if (!vb->baddr) | ||
206 | return 0; | ||
207 | |||
208 | /* FIXME: to properly support USERPTR, remap should occur. | ||
209 | The code below won't work, since mem->vma = NULL | ||
210 | */ | ||
211 | /* Try to remap memory */ | ||
212 | rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); | ||
213 | if (rc < 0) { | ||
214 | printk(KERN_ERR "mmap: remap failed with error %d", rc); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | #endif | ||
218 | |||
219 | break; | ||
220 | case V4L2_MEMORY_OVERLAY: | ||
221 | default: | ||
222 | dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); | ||
223 | |||
224 | /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ | ||
225 | printk(KERN_ERR "Memory method currently unsupported.\n"); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int __videobuf_mmap_mapper(struct videobuf_queue *q, | ||
233 | struct videobuf_buffer *buf, | ||
234 | struct vm_area_struct *vma) | ||
235 | { | ||
236 | struct videobuf_vmalloc_memory *mem; | ||
237 | struct videobuf_mapping *map; | ||
238 | int retval, pages; | ||
239 | |||
240 | dprintk(1, "%s\n", __func__); | ||
241 | |||
242 | /* create mapping + update buffer list */ | ||
243 | map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); | ||
244 | if (NULL == map) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | buf->map = map; | ||
248 | map->q = q; | ||
249 | |||
250 | buf->baddr = vma->vm_start; | ||
251 | |||
252 | mem = buf->priv; | ||
253 | BUG_ON(!mem); | ||
254 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); | ||
255 | |||
256 | pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); | ||
257 | mem->vaddr = vmalloc_user(pages); | ||
258 | if (!mem->vaddr) { | ||
259 | printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); | ||
260 | goto error; | ||
261 | } | ||
262 | dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages); | ||
263 | |||
264 | /* Try to remap memory */ | ||
265 | retval = remap_vmalloc_range(vma, mem->vaddr, 0); | ||
266 | if (retval < 0) { | ||
267 | printk(KERN_ERR "mmap: remap failed with error %d. ", retval); | ||
268 | vfree(mem->vaddr); | ||
269 | goto error; | ||
270 | } | ||
271 | |||
272 | vma->vm_ops = &videobuf_vm_ops; | ||
273 | vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; | ||
274 | vma->vm_private_data = map; | ||
275 | |||
276 | dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", | ||
277 | map, q, vma->vm_start, vma->vm_end, | ||
278 | (long int)buf->bsize, | ||
279 | vma->vm_pgoff, buf->i); | ||
280 | |||
281 | videobuf_vm_open(vma); | ||
282 | |||
283 | return 0; | ||
284 | |||
285 | error: | ||
286 | mem = NULL; | ||
287 | kfree(map); | ||
288 | return -ENOMEM; | ||
289 | } | ||
290 | |||
291 | static struct videobuf_qtype_ops qops = { | ||
292 | .magic = MAGIC_QTYPE_OPS, | ||
293 | |||
294 | .alloc_vb = __videobuf_alloc_vb, | ||
295 | .iolock = __videobuf_iolock, | ||
296 | .mmap_mapper = __videobuf_mmap_mapper, | ||
297 | .vaddr = videobuf_to_vmalloc, | ||
298 | }; | ||
299 | |||
300 | void videobuf_queue_vmalloc_init(struct videobuf_queue *q, | ||
301 | const struct videobuf_queue_ops *ops, | ||
302 | struct device *dev, | ||
303 | spinlock_t *irqlock, | ||
304 | enum v4l2_buf_type type, | ||
305 | enum v4l2_field field, | ||
306 | unsigned int msize, | ||
307 | void *priv, | ||
308 | struct mutex *ext_lock) | ||
309 | { | ||
310 | videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, | ||
311 | priv, &qops, ext_lock); | ||
312 | } | ||
313 | EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); | ||
314 | |||
315 | void *videobuf_to_vmalloc(struct videobuf_buffer *buf) | ||
316 | { | ||
317 | struct videobuf_vmalloc_memory *mem = buf->priv; | ||
318 | BUG_ON(!mem); | ||
319 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); | ||
320 | |||
321 | return mem->vaddr; | ||
322 | } | ||
323 | EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); | ||
324 | |||
325 | void videobuf_vmalloc_free(struct videobuf_buffer *buf) | ||
326 | { | ||
327 | struct videobuf_vmalloc_memory *mem = buf->priv; | ||
328 | |||
329 | /* mmapped memory can't be freed here, otherwise mmapped region | ||
330 | would be released, while still needed. In this case, the memory | ||
331 | release should happen inside videobuf_vm_close(). | ||
332 | So, it should free memory only if the memory were allocated for | ||
333 | read() operation. | ||
334 | */ | ||
335 | if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) | ||
336 | return; | ||
337 | |||
338 | if (!mem) | ||
339 | return; | ||
340 | |||
341 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); | ||
342 | |||
343 | vfree(mem->vaddr); | ||
344 | mem->vaddr = NULL; | ||
345 | |||
346 | return; | ||
347 | } | ||
348 | EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); | ||
349 | |||