diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-13 13:58:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:08:48 -0400 |
commit | 968ced78a53509a996708a14e8b9269d1dc6a61c (patch) | |
tree | f2b5603fb69a9e7cbf16b8015a6e0aa9eb94a749 /drivers/media/video/videobuf-vmalloc.c | |
parent | fbde31d54b729e4aac1d06375d4365318fd88675 (diff) |
V4L/DVB (7552): videbuf-vmalloc: Corrects mmap code
There were some bugs on videobuf-vmalloc.
Basically, remap were called with a wrong parameter. Due to that, a later remap
were needed, generating the need of some hacks on videobuf-vmalloc and
videobuf-core.
This patch fixes the remap and removes the hacks.
TODO:
- V4L2_MEMORY_USERPTR is not implemented yet. This method should be
properly implemented, in order to work with a few userspace applications.
- The driver also doesn't implement V4L2_MEMORY_OVERLAY. This method is used
only by a few applications, and are becaming obsolete, due to the increment
of cpu performance. So, most apps prefer to retrieve data to an internal
buffer, doing some processing like de-interlacing.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/videobuf-vmalloc.c')
-rw-r--r-- | drivers/media/video/videobuf-vmalloc.c | 163 |
1 files changed, 105 insertions, 58 deletions
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 9eb7982988a6..075acdf6b7c7 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c | |||
@@ -124,45 +124,75 @@ static int __videobuf_iolock (struct videobuf_queue* q, | |||
124 | struct videobuf_buffer *vb, | 124 | struct videobuf_buffer *vb, |
125 | struct v4l2_framebuffer *fbuf) | 125 | struct v4l2_framebuffer *fbuf) |
126 | { | 126 | { |
127 | int pages; | 127 | struct videobuf_vmalloc_memory *mem = vb->priv; |
128 | struct videobuf_vmalloc_memory *mem=vb->priv; | ||
129 | 128 | ||
130 | BUG_ON(!mem); | 129 | BUG_ON(!mem); |
131 | 130 | ||
132 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | 131 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); |
133 | 132 | ||
134 | pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; | 133 | switch (vb->memory) { |
134 | case V4L2_MEMORY_MMAP: | ||
135 | dprintk(1, "%s memory method MMAP\n", __func__); | ||
135 | 136 | ||
136 | /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ | 137 | /* All handling should be done by __videobuf_mmap_mapper() */ |
137 | if ((vb->memory != V4L2_MEMORY_MMAP) && | 138 | if (!mem->vmalloc) { |
138 | (vb->memory != V4L2_MEMORY_USERPTR) ) { | 139 | printk(KERN_ERR "memory is not alloced/mmapped.\n"); |
139 | printk(KERN_ERR "Method currently unsupported.\n"); | 140 | return -EINVAL; |
140 | return -EINVAL; | 141 | } |
141 | } | 142 | break; |
143 | case V4L2_MEMORY_USERPTR: | ||
144 | { | ||
145 | int pages = PAGE_ALIGN(vb->size); | ||
142 | 146 | ||
143 | /* FIXME: should be tested with kernel mmap mem */ | 147 | dprintk(1, "%s memory method USERPTR\n", __func__); |
144 | mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); | 148 | |
145 | if (NULL == mem->vmalloc) { | 149 | #if 1 |
146 | printk(KERN_ERR "vmalloc (%d pages) failed\n",pages); | 150 | if (vb->baddr) { |
147 | return -ENOMEM; | 151 | printk(KERN_ERR "USERPTR is currently not supported\n"); |
148 | } | 152 | return -EINVAL; |
153 | } | ||
154 | #endif | ||
149 | 155 | ||
150 | dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", | 156 | /* The only USERPTR currently supported is the one needed for |
151 | (unsigned long)mem->vmalloc, | 157 | read() method. |
152 | pages << PAGE_SHIFT); | 158 | */ |
153 | 159 | ||
154 | /* It seems that some kernel versions need to do remap *after* | 160 | mem->vmalloc = vmalloc_user(pages); |
155 | the mmap() call | 161 | if (!mem->vmalloc) { |
156 | */ | 162 | printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); |
157 | if (mem->vma) { | 163 | return -ENOMEM; |
158 | int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0); | ||
159 | kfree(mem->vma); | ||
160 | mem->vma=NULL; | ||
161 | if (retval<0) { | ||
162 | dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n", | ||
163 | mem->vmalloc,retval); | ||
164 | return retval; | ||
165 | } | 164 | } |
165 | dprintk(1, "vmalloc is at addr %p (%d pages)\n", | ||
166 | mem->vmalloc, pages); | ||
167 | |||
168 | #if 0 | ||
169 | int rc; | ||
170 | /* Kernel userptr is used also by read() method. In this case, | ||
171 | there's no need to remap, since data will be copied to user | ||
172 | */ | ||
173 | if (!vb->baddr) | ||
174 | return 0; | ||
175 | |||
176 | /* FIXME: to properly support USERPTR, remap should occur. | ||
177 | The code bellow won't work, since mem->vma = NULL | ||
178 | */ | ||
179 | /* Try to remap memory */ | ||
180 | rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); | ||
181 | if (rc < 0) { | ||
182 | printk(KERN_ERR "mmap: remap failed with error %d. ", rc); | ||
183 | return -ENOMEM; | ||
184 | } | ||
185 | #endif | ||
186 | |||
187 | break; | ||
188 | } | ||
189 | case V4L2_MEMORY_OVERLAY: | ||
190 | default: | ||
191 | dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); | ||
192 | |||
193 | /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ | ||
194 | printk(KERN_ERR "Memory method currently unsupported.\n"); | ||
195 | return -EINVAL; | ||
166 | } | 196 | } |
167 | 197 | ||
168 | return 0; | 198 | return 0; |
@@ -178,6 +208,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) | |||
178 | { | 208 | { |
179 | unsigned int i; | 209 | unsigned int i; |
180 | 210 | ||
211 | dprintk(1, "%s\n", __func__); | ||
181 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | 212 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
182 | if (q->bufs[i]) { | 213 | if (q->bufs[i]) { |
183 | if (q->bufs[i]->map) | 214 | if (q->bufs[i]->map) |
@@ -194,10 +225,11 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, | |||
194 | struct videobuf_vmalloc_memory *mem; | 225 | struct videobuf_vmalloc_memory *mem; |
195 | struct videobuf_mapping *map; | 226 | struct videobuf_mapping *map; |
196 | unsigned int first; | 227 | unsigned int first; |
197 | int retval; | 228 | int retval, pages; |
198 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 229 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; |
199 | 230 | ||
200 | if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) | 231 | dprintk(1, "%s\n", __func__); |
232 | if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) | ||
201 | return -EINVAL; | 233 | return -EINVAL; |
202 | 234 | ||
203 | /* look for first buffer to map */ | 235 | /* look for first buffer to map */ |
@@ -217,46 +249,55 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, | |||
217 | } | 249 | } |
218 | 250 | ||
219 | /* create mapping + update buffer list */ | 251 | /* create mapping + update buffer list */ |
220 | map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); | 252 | map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); |
221 | if (NULL == map) | 253 | if (NULL == map) |
222 | return -ENOMEM; | 254 | return -ENOMEM; |
223 | 255 | ||
256 | q->bufs[first]->map = map; | ||
224 | map->start = vma->vm_start; | 257 | map->start = vma->vm_start; |
225 | map->end = vma->vm_end; | 258 | map->end = vma->vm_end; |
226 | map->q = q; | 259 | map->q = q; |
227 | 260 | ||
228 | q->bufs[first]->baddr = vma->vm_start; | 261 | q->bufs[first]->baddr = vma->vm_start; |
229 | 262 | ||
230 | vma->vm_ops = &videobuf_vm_ops; | 263 | mem = q->bufs[first]->priv; |
231 | vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; | 264 | BUG_ON(!mem); |
232 | vma->vm_private_data = map; | 265 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); |
233 | 266 | ||
234 | mem=q->bufs[first]->priv; | 267 | pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); |
235 | BUG_ON (!mem); | 268 | mem->vmalloc = vmalloc_user(pages); |
236 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | 269 | if (!mem->vmalloc) { |
270 | printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); | ||
271 | goto error; | ||
272 | } | ||
273 | dprintk(1, "vmalloc is at addr %p (%d pages)\n", | ||
274 | mem->vmalloc, pages); | ||
237 | 275 | ||
238 | /* Try to remap memory */ | 276 | /* Try to remap memory */ |
239 | retval=remap_vmalloc_range(vma, mem->vmalloc,0); | 277 | retval = remap_vmalloc_range(vma, mem->vmalloc, 0); |
240 | if (retval<0) { | 278 | if (retval < 0) { |
241 | dprintk(1,"mmap: postponing remap_vmalloc_range\n"); | 279 | printk(KERN_ERR "mmap: remap failed with error %d. ", retval); |
242 | 280 | vfree(mem->vmalloc); | |
243 | mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL); | 281 | goto error; |
244 | if (!mem->vma) { | ||
245 | kfree(map); | ||
246 | q->bufs[first]->map=NULL; | ||
247 | return -ENOMEM; | ||
248 | } | ||
249 | memcpy(mem->vma,vma,sizeof(*vma)); | ||
250 | } | 282 | } |
251 | 283 | ||
284 | vma->vm_ops = &videobuf_vm_ops; | ||
285 | vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; | ||
286 | vma->vm_private_data = map; | ||
287 | |||
252 | dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", | 288 | dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", |
253 | map,q,vma->vm_start,vma->vm_end, | 289 | map, q, vma->vm_start, vma->vm_end, |
254 | (long int) q->bufs[first]->bsize, | 290 | (long int) q->bufs[first]->bsize, |
255 | vma->vm_pgoff,first); | 291 | vma->vm_pgoff, first); |
256 | 292 | ||
257 | videobuf_vm_open(vma); | 293 | videobuf_vm_open(vma); |
258 | 294 | ||
259 | return (0); | 295 | return 0; |
296 | |||
297 | error: | ||
298 | mem = NULL; | ||
299 | kfree(map); | ||
300 | return -ENOMEM; | ||
260 | } | 301 | } |
261 | 302 | ||
262 | static int __videobuf_copy_to_user ( struct videobuf_queue *q, | 303 | static int __videobuf_copy_to_user ( struct videobuf_queue *q, |
@@ -347,13 +388,19 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); | |||
347 | 388 | ||
348 | void videobuf_vmalloc_free (struct videobuf_buffer *buf) | 389 | void videobuf_vmalloc_free (struct videobuf_buffer *buf) |
349 | { | 390 | { |
350 | struct videobuf_vmalloc_memory *mem=buf->priv; | 391 | struct videobuf_vmalloc_memory *mem = buf->priv; |
351 | BUG_ON (!mem); | ||
352 | 392 | ||
353 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | 393 | if (!mem) |
394 | return; | ||
395 | |||
396 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); | ||
354 | 397 | ||
355 | vfree(mem->vmalloc); | 398 | vfree(mem->vmalloc); |
356 | mem->vmalloc=NULL; | 399 | mem->vmalloc = NULL; |
400 | |||
401 | |||
402 | |||
403 | /* FIXME: need to do buf->priv = NULL? */ | ||
357 | 404 | ||
358 | return; | 405 | return; |
359 | } | 406 | } |