Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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)  if (unlikely((is) != (should))) \
 34         { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
 35 
 36 static int debug;
 37 module_param(debug, int, 0644);
 38 
 39 MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
 40 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 41 MODULE_LICENSE("GPL");
 42 
 43 #define dprintk(level, fmt, arg...)     if (debug >= level) \
 44         printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
 45 
 46 
 47 /***************************************************************************/
 48 
 49 static void
 50 videobuf_vm_open(struct vm_area_struct *vma)
 51 {
 52         struct videobuf_mapping *map = vma->vm_private_data;
 53 
 54         dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map,
 55                 map->count,vma->vm_start,vma->vm_end);
 56 
 57         map->count++;
 58 }
 59 
 60 static void videobuf_vm_close(struct vm_area_struct *vma)
 61 {
 62         struct videobuf_mapping *map = vma->vm_private_data;
 63         struct videobuf_queue *q = map->q;
 64         int i;
 65 
 66         dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
 67                 map->count, vma->vm_start, vma->vm_end);
 68 
 69         map->count--;
 70         if (0 == map->count) {
 71                 struct videobuf_vmalloc_memory *mem;
 72 
 73                 dprintk(1, "munmap %p q=%p\n", map, q);
 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 
 80                 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 81                         if (NULL == q->bufs[i])
 82                                 continue;
 83 
 84                         if (q->bufs[i]->map != map)
 85                                 continue;
 86 
 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                         }
106 
107                         q->bufs[i]->map   = NULL;
108                         q->bufs[i]->baddr = 0;
109                 }
110 
111                 kfree(map);
112 
113                 mutex_unlock(&q->vb_lock);
114         }
115 
116         return;
117 }
118 
119 static struct vm_operations_struct videobuf_vm_ops =
120 {
121         .open     = videobuf_vm_open,
122         .close    = videobuf_vm_close,
123 };
124 
125 /* ---------------------------------------------------------------------
126  * vmalloc handlers for the generic methods
127  */
128 
129 /* Allocated area consists on 3 parts:
130         struct video_buffer
131         struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
132         struct videobuf_dma_sg_memory
133  */
134 
135 static void *__videobuf_alloc(size_t size)
136 {
137         struct videobuf_vmalloc_memory *mem;
138         struct videobuf_buffer *vb;
139 
140         vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
141 
142         mem = vb->priv = ((char *)vb)+size;
143         mem->magic=MAGIC_VMAL_MEM;
144 
145         dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
146                 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
147                 mem,(long)sizeof(*mem));
148 
149         return vb;
150 }
151 
152 static int __videobuf_iolock (struct videobuf_queue* q,
153                               struct videobuf_buffer *vb,
154                               struct v4l2_framebuffer *fbuf)
155 {
156         struct videobuf_vmalloc_memory *mem = vb->priv;
157         int pages;
158 
159         BUG_ON(!mem);
160 
161         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
162 
163         switch (vb->memory) {
164         case V4L2_MEMORY_MMAP:
165                 dprintk(1, "%s memory method MMAP\n", __func__);
166 
167                 /* All handling should be done by __videobuf_mmap_mapper() */
168                 if (!mem->vmalloc) {
169                         printk(KERN_ERR "memory is not alloced/mmapped.\n");
170                         return -EINVAL;
171                 }
172                 break;
173         case V4L2_MEMORY_USERPTR:
174                 pages = PAGE_ALIGN(vb->size);
175 
176                 dprintk(1, "%s memory method USERPTR\n", __func__);
177 
178 #if 1
179                 if (vb->baddr) {
180                         printk(KERN_ERR "USERPTR is currently not supported\n");
181                         return -EINVAL;
182                 }
183 #endif
184 
185                 /* The only USERPTR currently supported is the one needed for
186                    read() method.
187                  */
188 
189                 mem->vmalloc = vmalloc_user(pages);
190                 if (!mem->vmalloc) {
191                         printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
192                         return -ENOMEM;
193                 }
194                 dprintk(1, "vmalloc is at addr %p (%d pages)\n",
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 below 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;
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;
224         }
225 
226         return 0;
227 }
228 
229 static int __videobuf_sync(struct videobuf_queue *q,
230                            struct videobuf_buffer *buf)
231 {
232         return 0;
233 }
234 
235 static int __videobuf_mmap_free(struct videobuf_queue *q)
236 {
237         unsigned int i;
238 
239         dprintk(1, "%s\n", __func__);
240         for (i = 0; i < VIDEO_MAX_FRAME; i++) {
241                 if (q->bufs[i]) {
242                         if (q->bufs[i]->map)
243                                 return -EBUSY;
244                 }
245         }
246 
247         return 0;
248 }
249 
250 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
251                          struct vm_area_struct *vma)
252 {
253         struct videobuf_vmalloc_memory *mem;
254         struct videobuf_mapping *map;
255         unsigned int first;
256         int retval, pages;
257         unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
258 
259         dprintk(1, "%s\n", __func__);
260         if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
261                 return -EINVAL;
262 
263         /* look for first buffer to map */
264         for (first = 0; first < VIDEO_MAX_FRAME; first++) {
265                 if (NULL == q->bufs[first])
266                         continue;
267 
268                 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
269                         continue;
270                 if (q->bufs[first]->boff == offset)
271                         break;
272         }
273         if (VIDEO_MAX_FRAME == first) {
274                 dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
275                         (vma->vm_pgoff << PAGE_SHIFT));
276                 return -EINVAL;
277         }
278 
279         /* create mapping + update buffer list */
280         map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
281         if (NULL == map)
282                 return -ENOMEM;
283 
284         q->bufs[first]->map = map;
285         map->start = vma->vm_start;
286         map->end   = vma->vm_end;
287         map->q     = q;
288 
289         q->bufs[first]->baddr = vma->vm_start;
290 
291         mem = q->bufs[first]->priv;
292         BUG_ON(!mem);
293         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
294 
295         pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
296         mem->vmalloc = vmalloc_user(pages);
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);
303 
304         /* Try to remap memory */
305         retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
306         if (retval < 0) {
307                 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
308                 vfree(mem->vmalloc);
309                 goto error;
310         }
311 
312         vma->vm_ops          = &videobuf_vm_ops;
313         vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
314         vma->vm_private_data = map;
315 
316         dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
317                 map, q, vma->vm_start, vma->vm_end,
318                 (long int) q->bufs[first]->bsize,
319                 vma->vm_pgoff, first);
320 
321         videobuf_vm_open(vma);
322 
323         return 0;
324 
325 error:
326         mem = NULL;
327         kfree(map);
328         return -ENOMEM;
329 }
330 
331 static int __videobuf_copy_to_user ( struct videobuf_queue *q,
332                                 char __user *data, size_t count,
333                                 int nonblocking )
334 {
335         struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
336         BUG_ON (!mem);
337         MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
338 
339         BUG_ON (!mem->vmalloc);
340 
341         /* copy to userspace */
342         if (count > q->read_buf->size - q->read_off)
343                 count = q->read_buf->size - q->read_off;
344 
345         if (copy_to_user(data, mem->vmalloc+q->read_off, count))
346                 return -EFAULT;
347 
348         return count;
349 }
350 
351 static int __videobuf_copy_stream ( struct videobuf_queue *q,
352                                 char __user *data, size_t count, size_t pos,
353                                 int vbihack, int nonblocking )
354 {
355         unsigned int  *fc;
356         struct videobuf_vmalloc_memory *mem=q->read_buf->priv;
357         BUG_ON (!mem);
358         MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
359 
360         if (vbihack) {
361                 /* dirty, undocumented hack -- pass the frame counter
362                         * within the last four bytes of each vbi data block.
363                         * We need that one to maintain backward compatibility
364                         * to all vbi decoding software out there ... */
365                 fc  = (unsigned int*)mem->vmalloc;
366                 fc += (q->read_buf->size>>2) -1;
367                 *fc = q->read_buf->field_count >> 1;
368                 dprintk(1,"vbihack: %d\n",*fc);
369         }
370 
371         /* copy stuff using the common method */
372         count = __videobuf_copy_to_user (q,data,count,nonblocking);
373 
374         if ( (count==-EFAULT) && (0 == pos) )
375                 return -EFAULT;
376 
377         return count;
378 }
379 
380 static struct videobuf_qtype_ops qops = {
381         .magic        = MAGIC_QTYPE_OPS,
382 
383         .alloc        = __videobuf_alloc,
384         .iolock       = __videobuf_iolock,
385         .sync         = __videobuf_sync,
386         .mmap_free    = __videobuf_mmap_free,
387         .mmap_mapper  = __videobuf_mmap_mapper,
388         .video_copy_to_user = __videobuf_copy_to_user,
389         .copy_stream  = __videobuf_copy_stream,
390         .vmalloc      = videobuf_to_vmalloc,
391 };
392 
393 void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
394                          struct videobuf_queue_ops *ops,
395                          void *dev,
396                          spinlock_t *irqlock,
397                          enum v4l2_buf_type type,
398                          enum v4l2_field field,
399                          unsigned int msize,
400                          void *priv)
401 {
402         videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
403                                  priv, &qops);
404 }
405 
406 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
407 
408 void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
409 {
410         struct videobuf_vmalloc_memory *mem=buf->priv;
411         BUG_ON (!mem);
412         MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
413 
414         return mem->vmalloc;
415 }
416 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
417 
418 void videobuf_vmalloc_free (struct videobuf_buffer *buf)
419 {
420         struct videobuf_vmalloc_memory *mem = buf->priv;
421 
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)
429                 return;
430 
431         if (!mem)
432                 return;
433 
434         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
435 
436         vfree(mem->vmalloc);
437         mem->vmalloc = NULL;
438 
439         return;
440 }
441 EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
442 
443 /*
444  * Local variables:
445  * c-basic-offset: 8
446  * End:
447  */
448 
  This page was automatically generated by the LXR engine.