aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/videobuf-vmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/videobuf-vmalloc.c')
-rw-r--r--drivers/media/video/videobuf-vmalloc.c211
1 files changed, 145 insertions, 66 deletions
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 5266ecc91dab..c91e1d8e3802 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -33,7 +33,7 @@
33#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ 33#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
34 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } 34 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
35 35
36static int debug = 0; 36static int debug;
37module_param(debug, int, 0644); 37module_param(debug, int, 0644);
38 38
39MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); 39MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
@@ -57,20 +57,26 @@ videobuf_vm_open(struct vm_area_struct *vma)
57 map->count++; 57 map->count++;
58} 58}
59 59
60static void 60static void videobuf_vm_close(struct vm_area_struct *vma)
61videobuf_vm_close(struct vm_area_struct *vma)
62{ 61{
63 struct videobuf_mapping *map = vma->vm_private_data; 62 struct videobuf_mapping *map = vma->vm_private_data;
64 struct videobuf_queue *q = map->q; 63 struct videobuf_queue *q = map->q;
65 int i; 64 int i;
66 65
67 dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n",map, 66 dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
68 map->count,vma->vm_start,vma->vm_end); 67 map->count, vma->vm_start, vma->vm_end);
69 68
70 map->count--; 69 map->count--;
71 if (0 == map->count) { 70 if (0 == map->count) {
72 dprintk(1,"munmap %p q=%p\n",map,q); 71 struct videobuf_vmalloc_memory *mem;
72
73 dprintk(1, "munmap %p q=%p\n", map, q);
73 mutex_lock(&q->vb_lock); 74 mutex_lock(&q->vb_lock);
75
76 /* We need first to cancel streams, before unmapping */
77 if (q->streaming)
78 videobuf_queue_cancel(q);
79
74 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 80 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
75 if (NULL == q->bufs[i]) 81 if (NULL == q->bufs[i])
76 continue; 82 continue;
@@ -78,14 +84,35 @@ videobuf_vm_close(struct vm_area_struct *vma)
78 if (q->bufs[i]->map != map) 84 if (q->bufs[i]->map != map)
79 continue; 85 continue;
80 86
81 q->ops->buf_release(q,q->bufs[i]); 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.
93 */
94
95 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
96
97 /* vfree is not atomic - can't be
98 called with IRQ's disabled
99 */
100 dprintk(1, "%s: buf[%d] freeing (%p)\n",
101 __func__, i, mem->vmalloc);
102
103 vfree(mem->vmalloc);
104 mem->vmalloc = NULL;
105 }
82 106
83 q->bufs[i]->map = NULL; 107 q->bufs[i]->map = NULL;
84 q->bufs[i]->baddr = 0; 108 q->bufs[i]->baddr = 0;
85 } 109 }
86 mutex_unlock(&q->vb_lock); 110
87 kfree(map); 111 kfree(map);
112
113 mutex_unlock(&q->vb_lock);
88 } 114 }
115
89 return; 116 return;
90} 117}
91 118
@@ -102,7 +129,7 @@ static struct vm_operations_struct videobuf_vm_ops =
102/* Allocated area consists on 3 parts: 129/* Allocated area consists on 3 parts:
103 struct video_buffer 130 struct video_buffer
104 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...) 131 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
105 struct videobuf_pci_sg_memory 132 struct videobuf_dma_sg_memory
106 */ 133 */
107 134
108static void *__videobuf_alloc(size_t size) 135static void *__videobuf_alloc(size_t size)
@@ -116,7 +143,7 @@ static void *__videobuf_alloc(size_t size)
116 mem->magic=MAGIC_VMAL_MEM; 143 mem->magic=MAGIC_VMAL_MEM;
117 144
118 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", 145 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
119 __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), 146 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
120 mem,(long)sizeof(*mem)); 147 mem,(long)sizeof(*mem));
121 148
122 return vb; 149 return vb;
@@ -126,45 +153,74 @@ static int __videobuf_iolock (struct videobuf_queue* q,
126 struct videobuf_buffer *vb, 153 struct videobuf_buffer *vb,
127 struct v4l2_framebuffer *fbuf) 154 struct v4l2_framebuffer *fbuf)
128{ 155{
156 struct videobuf_vmalloc_memory *mem = vb->priv;
129 int pages; 157 int pages;
130 struct videobuf_vmalloc_memory *mem=vb->priv;
131 158
132 BUG_ON(!mem); 159 BUG_ON(!mem);
133 160
134 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 161 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
135 162
136 pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; 163 switch (vb->memory) {
164 case V4L2_MEMORY_MMAP:
165 dprintk(1, "%s memory method MMAP\n", __func__);
137 166
138 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ 167 /* All handling should be done by __videobuf_mmap_mapper() */
139 if ((vb->memory != V4L2_MEMORY_MMAP) && 168 if (!mem->vmalloc) {
140 (vb->memory != V4L2_MEMORY_USERPTR) ) { 169 printk(KERN_ERR "memory is not alloced/mmapped.\n");
141 printk(KERN_ERR "Method currently unsupported.\n"); 170 return -EINVAL;
142 return -EINVAL; 171 }
143 } 172 break;
173 case V4L2_MEMORY_USERPTR:
174 pages = PAGE_ALIGN(vb->size);
144 175
145 /* FIXME: should be tested with kernel mmap mem */ 176 dprintk(1, "%s memory method USERPTR\n", __func__);
146 mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
147 if (NULL == mem->vmalloc) {
148 printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
149 return -ENOMEM;
150 }
151 177
152 dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", 178#if 1
153 (unsigned long)mem->vmalloc, 179 if (vb->baddr) {
154 pages << PAGE_SHIFT); 180 printk(KERN_ERR "USERPTR is currently not supported\n");
181 return -EINVAL;
182 }
183#endif
155 184
156 /* It seems that some kernel versions need to do remap *after* 185 /* The only USERPTR currently supported is the one needed for
157 the mmap() call 186 read() method.
158 */ 187 */
159 if (mem->vma) { 188
160 int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); 189 mem->vmalloc = vmalloc_user(pages);
161 kfree(mem->vma); 190 if (!mem->vmalloc) {
162 mem->vma=NULL; 191 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
163 if (retval<0) { 192 return -ENOMEM;
164 dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", 193 }
165 mem->vmalloc,retval); 194 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
166 return retval; 195 mem->vmalloc, pages);
196
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
201 */
202 if (!vb->baddr)
203 return 0;
204
205 /* FIXME: to properly support USERPTR, remap should occur.
206 The code bellow won't work, since mem->vma = NULL
207 */
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;
167 } 213 }
214#endif
215
216 break;
217 case V4L2_MEMORY_OVERLAY:
218 default:
219 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
220
221 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
222 printk(KERN_ERR "Memory method currently unsupported.\n");
223 return -EINVAL;
168 } 224 }
169 225
170 return 0; 226 return 0;
@@ -180,6 +236,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
180{ 236{
181 unsigned int i; 237 unsigned int i;
182 238
239 dprintk(1, "%s\n", __func__);
183 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 240 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
184 if (q->bufs[i]) { 241 if (q->bufs[i]) {
185 if (q->bufs[i]->map) 242 if (q->bufs[i]->map)
@@ -196,10 +253,11 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
196 struct videobuf_vmalloc_memory *mem; 253 struct videobuf_vmalloc_memory *mem;
197 struct videobuf_mapping *map; 254 struct videobuf_mapping *map;
198 unsigned int first; 255 unsigned int first;
199 int retval; 256 int retval, pages;
200 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 257 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
201 258
202 if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) 259 dprintk(1, "%s\n", __func__);
260 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
203 return -EINVAL; 261 return -EINVAL;
204 262
205 /* look for first buffer to map */ 263 /* look for first buffer to map */
@@ -219,46 +277,55 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
219 } 277 }
220 278
221 /* create mapping + update buffer list */ 279 /* create mapping + update buffer list */
222 map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); 280 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
223 if (NULL == map) 281 if (NULL == map)
224 return -ENOMEM; 282 return -ENOMEM;
225 283
284 q->bufs[first]->map = map;
226 map->start = vma->vm_start; 285 map->start = vma->vm_start;
227 map->end = vma->vm_end; 286 map->end = vma->vm_end;
228 map->q = q; 287 map->q = q;
229 288
230 q->bufs[first]->baddr = vma->vm_start; 289 q->bufs[first]->baddr = vma->vm_start;
231 290
232 vma->vm_ops = &videobuf_vm_ops; 291 mem = q->bufs[first]->priv;
233 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; 292 BUG_ON(!mem);
234 vma->vm_private_data = map; 293 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
235 294
236 mem=q->bufs[first]->priv; 295 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
237 BUG_ON (!mem); 296 mem->vmalloc = vmalloc_user(pages);
238 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 297 if (!mem->vmalloc) {
298 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
299 goto error;
300 }
301 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
302 mem->vmalloc, pages);
239 303
240 /* Try to remap memory */ 304 /* Try to remap memory */
241 retval=remap_vmalloc_range(vma, mem->vmalloc,0); 305 retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
242 if (retval<0) { 306 if (retval < 0) {
243 dprintk(1,"mmap: postponing remap_vmalloc_range\n"); 307 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
244 308 vfree(mem->vmalloc);
245 mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); 309 goto error;
246 if (!mem->vma) {
247 kfree(map);
248 q->bufs[first]->map=NULL;
249 return -ENOMEM;
250 }
251 memcpy(mem->vma,vma,sizeof(*vma));
252 } 310 }
253 311
312 vma->vm_ops = &videobuf_vm_ops;
313 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
314 vma->vm_private_data = map;
315
254 dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", 316 dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
255 map,q,vma->vm_start,vma->vm_end, 317 map, q, vma->vm_start, vma->vm_end,
256 (long int) q->bufs[first]->bsize, 318 (long int) q->bufs[first]->bsize,
257 vma->vm_pgoff,first); 319 vma->vm_pgoff, first);
258 320
259 videobuf_vm_open(vma); 321 videobuf_vm_open(vma);
260 322
261 return (0); 323 return 0;
324
325error:
326 mem = NULL;
327 kfree(map);
328 return -ENOMEM;
262} 329}
263 330
264static int __videobuf_copy_to_user ( struct videobuf_queue *q, 331static int __videobuf_copy_to_user ( struct videobuf_queue *q,
@@ -320,6 +387,7 @@ static struct videobuf_qtype_ops qops = {
320 .mmap_mapper = __videobuf_mmap_mapper, 387 .mmap_mapper = __videobuf_mmap_mapper,
321 .video_copy_to_user = __videobuf_copy_to_user, 388 .video_copy_to_user = __videobuf_copy_to_user,
322 .copy_stream = __videobuf_copy_stream, 389 .copy_stream = __videobuf_copy_stream,
390 .vmalloc = videobuf_to_vmalloc,
323}; 391};
324 392
325void videobuf_queue_vmalloc_init(struct videobuf_queue* q, 393void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
@@ -349,13 +417,24 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
349 417
350void videobuf_vmalloc_free (struct videobuf_buffer *buf) 418void videobuf_vmalloc_free (struct videobuf_buffer *buf)
351{ 419{
352 struct videobuf_vmalloc_memory *mem=buf->priv; 420 struct videobuf_vmalloc_memory *mem = buf->priv;
353 BUG_ON (!mem);
354 421
355 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 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.
427 */
428 if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
429 return;
430
431 if (!mem)
432 return;
433
434 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
356 435
357 vfree(mem->vmalloc); 436 vfree(mem->vmalloc);
358 mem->vmalloc=NULL; 437 mem->vmalloc = NULL;
359 438
360 return; 439 return;
361} 440}