root/drivers/media/v4l2-core/videobuf-vmalloc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. videobuf_vm_open
  2. videobuf_vm_close
  3. __videobuf_alloc_vb
  4. __videobuf_iolock
  5. __videobuf_mmap_mapper
  6. videobuf_queue_vmalloc_init
  7. videobuf_to_vmalloc
  8. videobuf_vmalloc_free

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * helper functions for vmalloc video4linux capture buffers
   4  *
   5  * The functions expect the hardware being able to scatter gather
   6  * (i.e. the buffers are not linear in physical memory, but fragmented
   7  * into PAGE_SIZE chunks).  They also assume the driver does not need
   8  * to touch the video data.
   9  *
  10  * (c) 2007 Mauro Carvalho Chehab <mchehab@kernel.org>
  11  */
  12 
  13 #include <linux/init.h>
  14 #include <linux/module.h>
  15 #include <linux/moduleparam.h>
  16 #include <linux/slab.h>
  17 #include <linux/interrupt.h>
  18 
  19 #include <linux/pci.h>
  20 #include <linux/vmalloc.h>
  21 #include <linux/pagemap.h>
  22 #include <asm/page.h>
  23 #include <asm/pgtable.h>
  24 
  25 #include <media/videobuf-vmalloc.h>
  26 
  27 #define MAGIC_DMABUF   0x17760309
  28 #define MAGIC_VMAL_MEM 0x18221223
  29 
  30 #define MAGIC_CHECK(is, should)                                         \
  31         if (unlikely((is) != (should))) {                               \
  32                 printk(KERN_ERR "magic mismatch: %x (expected %x)\n",   \
  33                                 is, should);                            \
  34                 BUG();                                                  \
  35         }
  36 
  37 static int debug;
  38 module_param(debug, int, 0644);
  39 
  40 MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
  41 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
  42 MODULE_LICENSE("GPL");
  43 
  44 #define dprintk(level, fmt, arg...)                                     \
  45         if (debug >= level)                                             \
  46                 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
  47 
  48 
  49 /***************************************************************************/
  50 
  51 static void videobuf_vm_open(struct vm_area_struct *vma)
  52 {
  53         struct videobuf_mapping *map = vma->vm_private_data;
  54 
  55         dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
  56                 map->count, vma->vm_start, vma->vm_end);
  57 
  58         map->count++;
  59 }
  60 
  61 static void videobuf_vm_close(struct vm_area_struct *vma)
  62 {
  63         struct videobuf_mapping *map = vma->vm_private_data;
  64         struct videobuf_queue *q = map->q;
  65         int i;
  66 
  67         dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
  68                 map->count, vma->vm_start, vma->vm_end);
  69 
  70         map->count--;
  71         if (0 == map->count) {
  72                 struct videobuf_vmalloc_memory *mem;
  73 
  74                 dprintk(1, "munmap %p q=%p\n", map, q);
  75                 videobuf_queue_lock(q);
  76 
  77                 /* We need first to cancel streams, before unmapping */
  78                 if (q->streaming)
  79                         videobuf_queue_cancel(q);
  80 
  81                 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
  82                         if (NULL == q->bufs[i])
  83                                 continue;
  84 
  85                         if (q->bufs[i]->map != map)
  86                                 continue;
  87 
  88                         mem = q->bufs[i]->priv;
  89                         if (mem) {
  90                                 /* This callback is called only if kernel has
  91                                    allocated memory and this memory is mmapped.
  92                                    In this case, memory should be freed,
  93                                    in order to do memory unmap.
  94                                  */
  95 
  96                                 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
  97 
  98                                 /* vfree is not atomic - can't be
  99                                    called with IRQ's disabled
 100                                  */
 101                                 dprintk(1, "%s: buf[%d] freeing (%p)\n",
 102                                         __func__, i, mem->vaddr);
 103 
 104                                 vfree(mem->vaddr);
 105                                 mem->vaddr = NULL;
 106                         }
 107 
 108                         q->bufs[i]->map   = NULL;
 109                         q->bufs[i]->baddr = 0;
 110                 }
 111 
 112                 kfree(map);
 113 
 114                 videobuf_queue_unlock(q);
 115         }
 116 
 117         return;
 118 }
 119 
 120 static const struct vm_operations_struct videobuf_vm_ops = {
 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 struct videobuf_buffer *__videobuf_alloc_vb(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         if (!vb)
 142                 return vb;
 143 
 144         mem = vb->priv = ((char *)vb) + size;
 145         mem->magic = MAGIC_VMAL_MEM;
 146 
 147         dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
 148                 __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
 149                 mem, (long)sizeof(*mem));
 150 
 151         return vb;
 152 }
 153 
 154 static int __videobuf_iolock(struct videobuf_queue *q,
 155                              struct videobuf_buffer *vb,
 156                              struct v4l2_framebuffer *fbuf)
 157 {
 158         struct videobuf_vmalloc_memory *mem = vb->priv;
 159         int pages;
 160 
 161         BUG_ON(!mem);
 162 
 163         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 164 
 165         switch (vb->memory) {
 166         case V4L2_MEMORY_MMAP:
 167                 dprintk(1, "%s memory method MMAP\n", __func__);
 168 
 169                 /* All handling should be done by __videobuf_mmap_mapper() */
 170                 if (!mem->vaddr) {
 171                         printk(KERN_ERR "memory is not allocated/mmapped.\n");
 172                         return -EINVAL;
 173                 }
 174                 break;
 175         case V4L2_MEMORY_USERPTR:
 176                 pages = PAGE_ALIGN(vb->size);
 177 
 178                 dprintk(1, "%s memory method USERPTR\n", __func__);
 179 
 180                 if (vb->baddr) {
 181                         printk(KERN_ERR "USERPTR is currently not supported\n");
 182                         return -EINVAL;
 183                 }
 184 
 185                 /* The only USERPTR currently supported is the one needed for
 186                  * read() method.
 187                  */
 188 
 189                 mem->vaddr = vmalloc_user(pages);
 190                 if (!mem->vaddr) {
 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->vaddr, pages);
 196                 break;
 197         case V4L2_MEMORY_OVERLAY:
 198         default:
 199                 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
 200 
 201                 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
 202                 printk(KERN_ERR "Memory method currently unsupported.\n");
 203                 return -EINVAL;
 204         }
 205 
 206         return 0;
 207 }
 208 
 209 static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 210                                   struct videobuf_buffer *buf,
 211                                   struct vm_area_struct *vma)
 212 {
 213         struct videobuf_vmalloc_memory *mem;
 214         struct videobuf_mapping *map;
 215         int retval, pages;
 216 
 217         dprintk(1, "%s\n", __func__);
 218 
 219         /* create mapping + update buffer list */
 220         map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 221         if (NULL == map)
 222                 return -ENOMEM;
 223 
 224         buf->map = map;
 225         map->q     = q;
 226 
 227         buf->baddr = vma->vm_start;
 228 
 229         mem = buf->priv;
 230         BUG_ON(!mem);
 231         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 232 
 233         pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
 234         mem->vaddr = vmalloc_user(pages);
 235         if (!mem->vaddr) {
 236                 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 237                 goto error;
 238         }
 239         dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
 240 
 241         /* Try to remap memory */
 242         retval = remap_vmalloc_range(vma, mem->vaddr, 0);
 243         if (retval < 0) {
 244                 printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
 245                 vfree(mem->vaddr);
 246                 goto error;
 247         }
 248 
 249         vma->vm_ops          = &videobuf_vm_ops;
 250         vma->vm_flags       |= VM_DONTEXPAND | VM_DONTDUMP;
 251         vma->vm_private_data = map;
 252 
 253         dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 254                 map, q, vma->vm_start, vma->vm_end,
 255                 (long int)buf->bsize,
 256                 vma->vm_pgoff, buf->i);
 257 
 258         videobuf_vm_open(vma);
 259 
 260         return 0;
 261 
 262 error:
 263         mem = NULL;
 264         kfree(map);
 265         return -ENOMEM;
 266 }
 267 
 268 static struct videobuf_qtype_ops qops = {
 269         .magic        = MAGIC_QTYPE_OPS,
 270 
 271         .alloc_vb     = __videobuf_alloc_vb,
 272         .iolock       = __videobuf_iolock,
 273         .mmap_mapper  = __videobuf_mmap_mapper,
 274         .vaddr        = videobuf_to_vmalloc,
 275 };
 276 
 277 void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
 278                          const struct videobuf_queue_ops *ops,
 279                          struct device *dev,
 280                          spinlock_t *irqlock,
 281                          enum v4l2_buf_type type,
 282                          enum v4l2_field field,
 283                          unsigned int msize,
 284                          void *priv,
 285                          struct mutex *ext_lock)
 286 {
 287         videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 288                                  priv, &qops, ext_lock);
 289 }
 290 EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 291 
 292 void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
 293 {
 294         struct videobuf_vmalloc_memory *mem = buf->priv;
 295         BUG_ON(!mem);
 296         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 297 
 298         return mem->vaddr;
 299 }
 300 EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 301 
 302 void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 303 {
 304         struct videobuf_vmalloc_memory *mem = buf->priv;
 305 
 306         /* mmapped memory can't be freed here, otherwise mmapped region
 307            would be released, while still needed. In this case, the memory
 308            release should happen inside videobuf_vm_close().
 309            So, it should free memory only if the memory were allocated for
 310            read() operation.
 311          */
 312         if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
 313                 return;
 314 
 315         if (!mem)
 316                 return;
 317 
 318         MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 319 
 320         vfree(mem->vaddr);
 321         mem->vaddr = NULL;
 322 
 323         return;
 324 }
 325 EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 326 

/* [<][>][^][v][top][bottom][index][help] */