diff options
Diffstat (limited to 'drivers/media/video/videobuf-vmalloc.c')
-rw-r--r-- | drivers/media/video/videobuf-vmalloc.c | 183 |
1 files changed, 42 insertions, 141 deletions
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 136e09383c06..583728f4c221 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c | |||
@@ -30,8 +30,12 @@ | |||
30 | #define MAGIC_DMABUF 0x17760309 | 30 | #define MAGIC_DMABUF 0x17760309 |
31 | #define MAGIC_VMAL_MEM 0x18221223 | 31 | #define MAGIC_VMAL_MEM 0x18221223 |
32 | 32 | ||
33 | #define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ | 33 | #define MAGIC_CHECK(is, should) \ |
34 | { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } | 34 | if (unlikely((is) != (should))) { \ |
35 | printk(KERN_ERR "magic mismatch: %x (expected %x)\n", \ | ||
36 | is, should); \ | ||
37 | BUG(); \ | ||
38 | } | ||
35 | 39 | ||
36 | static int debug; | 40 | static int debug; |
37 | module_param(debug, int, 0644); | 41 | module_param(debug, int, 0644); |
@@ -40,19 +44,19 @@ MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); | |||
40 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | 44 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); |
41 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
42 | 46 | ||
43 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | 47 | #define dprintk(level, fmt, arg...) \ |
44 | printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) | 48 | if (debug >= level) \ |
49 | printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) | ||
45 | 50 | ||
46 | 51 | ||
47 | /***************************************************************************/ | 52 | /***************************************************************************/ |
48 | 53 | ||
49 | static void | 54 | static void videobuf_vm_open(struct vm_area_struct *vma) |
50 | videobuf_vm_open(struct vm_area_struct *vma) | ||
51 | { | 55 | { |
52 | struct videobuf_mapping *map = vma->vm_private_data; | 56 | struct videobuf_mapping *map = vma->vm_private_data; |
53 | 57 | ||
54 | dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map, | 58 | dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map, |
55 | map->count,vma->vm_start,vma->vm_end); | 59 | map->count, vma->vm_start, vma->vm_end); |
56 | 60 | ||
57 | map->count++; | 61 | map->count++; |
58 | } | 62 | } |
@@ -63,7 +67,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
63 | struct videobuf_queue *q = map->q; | 67 | struct videobuf_queue *q = map->q; |
64 | int i; | 68 | int i; |
65 | 69 | ||
66 | dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, | 70 | dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, |
67 | map->count, vma->vm_start, vma->vm_end); | 71 | map->count, vma->vm_start, vma->vm_end); |
68 | 72 | ||
69 | map->count--; | 73 | map->count--; |
@@ -116,8 +120,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma) | |||
116 | return; | 120 | return; |
117 | } | 121 | } |
118 | 122 | ||
119 | static const struct vm_operations_struct videobuf_vm_ops = | 123 | static const struct vm_operations_struct videobuf_vm_ops = { |
120 | { | ||
121 | .open = videobuf_vm_open, | 124 | .open = videobuf_vm_open, |
122 | .close = videobuf_vm_close, | 125 | .close = videobuf_vm_close, |
123 | }; | 126 | }; |
@@ -132,28 +135,28 @@ static const struct vm_operations_struct videobuf_vm_ops = | |||
132 | struct videobuf_dma_sg_memory | 135 | struct videobuf_dma_sg_memory |
133 | */ | 136 | */ |
134 | 137 | ||
135 | static void *__videobuf_alloc(size_t size) | 138 | static struct videobuf_buffer *__videobuf_alloc(size_t size) |
136 | { | 139 | { |
137 | struct videobuf_vmalloc_memory *mem; | 140 | struct videobuf_vmalloc_memory *mem; |
138 | struct videobuf_buffer *vb; | 141 | struct videobuf_buffer *vb; |
139 | 142 | ||
140 | vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); | 143 | vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); |
141 | if (!vb) | 144 | if (!vb) |
142 | return vb; | 145 | return vb; |
143 | 146 | ||
144 | mem = vb->priv = ((char *)vb)+size; | 147 | mem = vb->priv = ((char *)vb) + size; |
145 | mem->magic=MAGIC_VMAL_MEM; | 148 | mem->magic = MAGIC_VMAL_MEM; |
146 | 149 | ||
147 | dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", | 150 | dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n", |
148 | __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), | 151 | __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb), |
149 | mem,(long)sizeof(*mem)); | 152 | mem, (long)sizeof(*mem)); |
150 | 153 | ||
151 | return vb; | 154 | return vb; |
152 | } | 155 | } |
153 | 156 | ||
154 | static int __videobuf_iolock (struct videobuf_queue* q, | 157 | static int __videobuf_iolock(struct videobuf_queue *q, |
155 | struct videobuf_buffer *vb, | 158 | struct videobuf_buffer *vb, |
156 | struct v4l2_framebuffer *fbuf) | 159 | struct v4l2_framebuffer *fbuf) |
157 | { | 160 | { |
158 | struct videobuf_vmalloc_memory *mem = vb->priv; | 161 | struct videobuf_vmalloc_memory *mem = vb->priv; |
159 | int pages; | 162 | int pages; |
@@ -177,15 +180,13 @@ static int __videobuf_iolock (struct videobuf_queue* q, | |||
177 | 180 | ||
178 | dprintk(1, "%s memory method USERPTR\n", __func__); | 181 | dprintk(1, "%s memory method USERPTR\n", __func__); |
179 | 182 | ||
180 | #if 1 | ||
181 | if (vb->baddr) { | 183 | if (vb->baddr) { |
182 | printk(KERN_ERR "USERPTR is currently not supported\n"); | 184 | printk(KERN_ERR "USERPTR is currently not supported\n"); |
183 | return -EINVAL; | 185 | return -EINVAL; |
184 | } | 186 | } |
185 | #endif | ||
186 | 187 | ||
187 | /* The only USERPTR currently supported is the one needed for | 188 | /* The only USERPTR currently supported is the one needed for |
188 | read() method. | 189 | * read() method. |
189 | */ | 190 | */ |
190 | 191 | ||
191 | mem->vmalloc = vmalloc_user(pages); | 192 | mem->vmalloc = vmalloc_user(pages); |
@@ -210,7 +211,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, | |||
210 | /* Try to remap memory */ | 211 | /* Try to remap memory */ |
211 | rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); | 212 | rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); |
212 | if (rc < 0) { | 213 | if (rc < 0) { |
213 | printk(KERN_ERR "mmap: remap failed with error %d. ", rc); | 214 | printk(KERN_ERR "mmap: remap failed with error %d", rc); |
214 | return -ENOMEM; | 215 | return -ENOMEM; |
215 | } | 216 | } |
216 | #endif | 217 | #endif |
@@ -228,69 +229,29 @@ static int __videobuf_iolock (struct videobuf_queue* q, | |||
228 | return 0; | 229 | return 0; |
229 | } | 230 | } |
230 | 231 | ||
231 | static int __videobuf_sync(struct videobuf_queue *q, | ||
232 | struct videobuf_buffer *buf) | ||
233 | { | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int __videobuf_mmap_free(struct videobuf_queue *q) | ||
238 | { | ||
239 | unsigned int i; | ||
240 | |||
241 | dprintk(1, "%s\n", __func__); | ||
242 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | ||
243 | if (q->bufs[i]) { | ||
244 | if (q->bufs[i]->map) | ||
245 | return -EBUSY; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int __videobuf_mmap_mapper(struct videobuf_queue *q, | 232 | static int __videobuf_mmap_mapper(struct videobuf_queue *q, |
253 | struct vm_area_struct *vma) | 233 | struct videobuf_buffer *buf, |
234 | struct vm_area_struct *vma) | ||
254 | { | 235 | { |
255 | struct videobuf_vmalloc_memory *mem; | 236 | struct videobuf_vmalloc_memory *mem; |
256 | struct videobuf_mapping *map; | 237 | struct videobuf_mapping *map; |
257 | unsigned int first; | ||
258 | int retval, pages; | 238 | int retval, pages; |
259 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
260 | 239 | ||
261 | dprintk(1, "%s\n", __func__); | 240 | dprintk(1, "%s\n", __func__); |
262 | if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) | ||
263 | return -EINVAL; | ||
264 | |||
265 | /* look for first buffer to map */ | ||
266 | for (first = 0; first < VIDEO_MAX_FRAME; first++) { | ||
267 | if (NULL == q->bufs[first]) | ||
268 | continue; | ||
269 | |||
270 | if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) | ||
271 | continue; | ||
272 | if (q->bufs[first]->boff == offset) | ||
273 | break; | ||
274 | } | ||
275 | if (VIDEO_MAX_FRAME == first) { | ||
276 | dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", | ||
277 | (vma->vm_pgoff << PAGE_SHIFT)); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | 241 | ||
281 | /* create mapping + update buffer list */ | 242 | /* create mapping + update buffer list */ |
282 | map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); | 243 | map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); |
283 | if (NULL == map) | 244 | if (NULL == map) |
284 | return -ENOMEM; | 245 | return -ENOMEM; |
285 | 246 | ||
286 | q->bufs[first]->map = map; | 247 | buf->map = map; |
287 | map->start = vma->vm_start; | 248 | map->start = vma->vm_start; |
288 | map->end = vma->vm_end; | 249 | map->end = vma->vm_end; |
289 | map->q = q; | 250 | map->q = q; |
290 | 251 | ||
291 | q->bufs[first]->baddr = vma->vm_start; | 252 | buf->baddr = vma->vm_start; |
292 | 253 | ||
293 | mem = q->bufs[first]->priv; | 254 | mem = buf->priv; |
294 | BUG_ON(!mem); | 255 | BUG_ON(!mem); |
295 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); | 256 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); |
296 | 257 | ||
@@ -300,8 +261,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, | |||
300 | printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); | 261 | printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); |
301 | goto error; | 262 | goto error; |
302 | } | 263 | } |
303 | dprintk(1, "vmalloc is at addr %p (%d pages)\n", | 264 | dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages); |
304 | mem->vmalloc, pages); | ||
305 | 265 | ||
306 | /* Try to remap memory */ | 266 | /* Try to remap memory */ |
307 | retval = remap_vmalloc_range(vma, mem->vmalloc, 0); | 267 | retval = remap_vmalloc_range(vma, mem->vmalloc, 0); |
@@ -315,10 +275,10 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, | |||
315 | vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; | 275 | vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; |
316 | vma->vm_private_data = map; | 276 | vma->vm_private_data = map; |
317 | 277 | ||
318 | dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", | 278 | dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", |
319 | map, q, vma->vm_start, vma->vm_end, | 279 | map, q, vma->vm_start, vma->vm_end, |
320 | (long int) q->bufs[first]->bsize, | 280 | (long int)buf->bsize, |
321 | vma->vm_pgoff, first); | 281 | vma->vm_pgoff, buf->i); |
322 | 282 | ||
323 | videobuf_vm_open(vma); | 283 | videobuf_vm_open(vma); |
324 | 284 | ||
@@ -330,69 +290,16 @@ error: | |||
330 | return -ENOMEM; | 290 | return -ENOMEM; |
331 | } | 291 | } |
332 | 292 | ||
333 | static int __videobuf_copy_to_user ( struct videobuf_queue *q, | ||
334 | char __user *data, size_t count, | ||
335 | int nonblocking ) | ||
336 | { | ||
337 | struct videobuf_vmalloc_memory *mem=q->read_buf->priv; | ||
338 | BUG_ON (!mem); | ||
339 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | ||
340 | |||
341 | BUG_ON (!mem->vmalloc); | ||
342 | |||
343 | /* copy to userspace */ | ||
344 | if (count > q->read_buf->size - q->read_off) | ||
345 | count = q->read_buf->size - q->read_off; | ||
346 | |||
347 | if (copy_to_user(data, mem->vmalloc+q->read_off, count)) | ||
348 | return -EFAULT; | ||
349 | |||
350 | return count; | ||
351 | } | ||
352 | |||
353 | static int __videobuf_copy_stream ( struct videobuf_queue *q, | ||
354 | char __user *data, size_t count, size_t pos, | ||
355 | int vbihack, int nonblocking ) | ||
356 | { | ||
357 | unsigned int *fc; | ||
358 | struct videobuf_vmalloc_memory *mem=q->read_buf->priv; | ||
359 | BUG_ON (!mem); | ||
360 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | ||
361 | |||
362 | if (vbihack) { | ||
363 | /* dirty, undocumented hack -- pass the frame counter | ||
364 | * within the last four bytes of each vbi data block. | ||
365 | * We need that one to maintain backward compatibility | ||
366 | * to all vbi decoding software out there ... */ | ||
367 | fc = (unsigned int*)mem->vmalloc; | ||
368 | fc += (q->read_buf->size>>2) -1; | ||
369 | *fc = q->read_buf->field_count >> 1; | ||
370 | dprintk(1,"vbihack: %d\n",*fc); | ||
371 | } | ||
372 | |||
373 | /* copy stuff using the common method */ | ||
374 | count = __videobuf_copy_to_user (q,data,count,nonblocking); | ||
375 | |||
376 | if ( (count==-EFAULT) && (0 == pos) ) | ||
377 | return -EFAULT; | ||
378 | |||
379 | return count; | ||
380 | } | ||
381 | |||
382 | static struct videobuf_qtype_ops qops = { | 293 | static struct videobuf_qtype_ops qops = { |
383 | .magic = MAGIC_QTYPE_OPS, | 294 | .magic = MAGIC_QTYPE_OPS, |
384 | 295 | ||
385 | .alloc = __videobuf_alloc, | 296 | .alloc = __videobuf_alloc, |
386 | .iolock = __videobuf_iolock, | 297 | .iolock = __videobuf_iolock, |
387 | .sync = __videobuf_sync, | ||
388 | .mmap_free = __videobuf_mmap_free, | ||
389 | .mmap_mapper = __videobuf_mmap_mapper, | 298 | .mmap_mapper = __videobuf_mmap_mapper, |
390 | .video_copy_to_user = __videobuf_copy_to_user, | 299 | .vaddr = videobuf_to_vmalloc, |
391 | .copy_stream = __videobuf_copy_stream, | ||
392 | .vmalloc = videobuf_to_vmalloc, | ||
393 | }; | 300 | }; |
394 | 301 | ||
395 | void videobuf_queue_vmalloc_init(struct videobuf_queue* q, | 302 | void videobuf_queue_vmalloc_init(struct videobuf_queue *q, |
396 | const struct videobuf_queue_ops *ops, | 303 | const struct videobuf_queue_ops *ops, |
397 | struct device *dev, | 304 | struct device *dev, |
398 | spinlock_t *irqlock, | 305 | spinlock_t *irqlock, |
@@ -404,20 +311,19 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q, | |||
404 | videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, | 311 | videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, |
405 | priv, &qops); | 312 | priv, &qops); |
406 | } | 313 | } |
407 | |||
408 | EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); | 314 | EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); |
409 | 315 | ||
410 | void *videobuf_to_vmalloc (struct videobuf_buffer *buf) | 316 | void *videobuf_to_vmalloc(struct videobuf_buffer *buf) |
411 | { | 317 | { |
412 | struct videobuf_vmalloc_memory *mem=buf->priv; | 318 | struct videobuf_vmalloc_memory *mem = buf->priv; |
413 | BUG_ON (!mem); | 319 | BUG_ON(!mem); |
414 | MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); | 320 | MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); |
415 | 321 | ||
416 | return mem->vmalloc; | 322 | return mem->vmalloc; |
417 | } | 323 | } |
418 | EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); | 324 | EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); |
419 | 325 | ||
420 | void videobuf_vmalloc_free (struct videobuf_buffer *buf) | 326 | void videobuf_vmalloc_free(struct videobuf_buffer *buf) |
421 | { | 327 | { |
422 | struct videobuf_vmalloc_memory *mem = buf->priv; | 328 | struct videobuf_vmalloc_memory *mem = buf->priv; |
423 | 329 | ||
@@ -442,8 +348,3 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf) | |||
442 | } | 348 | } |
443 | EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); | 349 | EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); |
444 | 350 | ||
445 | /* | ||
446 | * Local variables: | ||
447 | * c-basic-offset: 8 | ||
448 | * End: | ||
449 | */ | ||