linux/drivers/media/v4l2-core/videobuf-vmalloc.c
<<
>>
Prefs
   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)                                         \
  34        if (unlikely((is) != (should))) {                               \
  35                printk(KERN_ERR "magic mismatch: %x (expected %x)\n",   \
  36                                is, should);                            \
  37                BUG();                                                  \
  38        }
  39
  40static int debug;
  41module_param(debug, int, 0644);
  42
  43MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
  44MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
  45MODULE_LICENSE("GPL");
  46
  47#define dprintk(level, fmt, arg...)                                     \
  48        if (debug >= level)                                             \
  49                printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
  50
  51
  52/***************************************************************************/
  53
  54static void videobuf_vm_open(struct vm_area_struct *vma)
  55{
  56        struct videobuf_mapping *map = vma->vm_private_data;
  57
  58        dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", map,
  59                map->count, vma->vm_start, vma->vm_end);
  60
  61        map->count++;
  62}
  63
  64static void videobuf_vm_close(struct vm_area_struct *vma)
  65{
  66        struct videobuf_mapping *map = vma->vm_private_data;
  67        struct videobuf_queue *q = map->q;
  68        int i;
  69
  70        dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
  71                map->count, vma->vm_start, vma->vm_end);
  72
  73        map->count--;
  74        if (0 == map->count) {
  75                struct videobuf_vmalloc_memory *mem;
  76
  77                dprintk(1, "munmap %p q=%p\n", map, q);
  78                videobuf_queue_lock(q);
  79
  80                /* We need first to cancel streams, before unmapping */
  81                if (q->streaming)
  82                        videobuf_queue_cancel(q);
  83
  84                for (i = 0; i < VIDEO_MAX_FRAME; i++) {
  85                        if (NULL == q->bufs[i])
  86                                continue;
  87
  88                        if (q->bufs[i]->map != map)
  89                                continue;
  90
  91                        mem = q->bufs[i]->priv;
  92                        if (mem) {
  93                                /* This callback is called only if kernel has
  94                                   allocated memory and this memory is mmapped.
  95                                   In this case, memory should be freed,
  96                                   in order to do memory unmap.
  97                                 */
  98
  99                                MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 100
 101                                /* vfree is not atomic - can't be
 102                                   called with IRQ's disabled
 103                                 */
 104                                dprintk(1, "%s: buf[%d] freeing (%p)\n",
 105                                        __func__, i, mem->vaddr);
 106
 107                                vfree(mem->vaddr);
 108                                mem->vaddr = NULL;
 109                        }
 110
 111                        q->bufs[i]->map   = NULL;
 112                        q->bufs[i]->baddr = 0;
 113                }
 114
 115                kfree(map);
 116
 117                videobuf_queue_unlock(q);
 118        }
 119
 120        return;
 121}
 122
 123static const struct vm_operations_struct videobuf_vm_ops = {
 124        .open     = videobuf_vm_open,
 125        .close    = videobuf_vm_close,
 126};
 127
 128/* ---------------------------------------------------------------------
 129 * vmalloc handlers for the generic methods
 130 */
 131
 132/* Allocated area consists on 3 parts:
 133        struct video_buffer
 134        struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
 135        struct videobuf_dma_sg_memory
 136 */
 137
 138static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
 139{
 140        struct videobuf_vmalloc_memory *mem;
 141        struct videobuf_buffer *vb;
 142
 143        vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
 144        if (!vb)
 145                return vb;
 146
 147        mem = vb->priv = ((char *)vb) + size;
 148        mem->magic = MAGIC_VMAL_MEM;
 149
 150        dprintk(1, "%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
 151                __func__, vb, (long)sizeof(*vb), (long)size - sizeof(*vb),
 152                mem, (long)sizeof(*mem));
 153
 154        return vb;
 155}
 156
 157static int __videobuf_iolock(struct videobuf_queue *q,
 158                             struct videobuf_buffer *vb,
 159                             struct v4l2_framebuffer *fbuf)
 160{
 161        struct videobuf_vmalloc_memory *mem = vb->priv;
 162        int pages;
 163
 164        BUG_ON(!mem);
 165
 166        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 167
 168        switch (vb->memory) {
 169        case V4L2_MEMORY_MMAP:
 170                dprintk(1, "%s memory method MMAP\n", __func__);
 171
 172                /* All handling should be done by __videobuf_mmap_mapper() */
 173                if (!mem->vaddr) {
 174                        printk(KERN_ERR "memory is not alloced/mmapped.\n");
 175                        return -EINVAL;
 176                }
 177                break;
 178        case V4L2_MEMORY_USERPTR:
 179                pages = PAGE_ALIGN(vb->size);
 180
 181                dprintk(1, "%s memory method USERPTR\n", __func__);
 182
 183                if (vb->baddr) {
 184                        printk(KERN_ERR "USERPTR is currently not supported\n");
 185                        return -EINVAL;
 186                }
 187
 188                /* The only USERPTR currently supported is the one needed for
 189                 * read() method.
 190                 */
 191
 192                mem->vaddr = vmalloc_user(pages);
 193                if (!mem->vaddr) {
 194                        printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 195                        return -ENOMEM;
 196                }
 197                dprintk(1, "vmalloc is at addr %p (%d pages)\n",
 198                        mem->vaddr, pages);
 199
 200#if 0
 201                int rc;
 202                /* Kernel userptr is used also by read() method. In this case,
 203                   there's no need to remap, since data will be copied to user
 204                 */
 205                if (!vb->baddr)
 206                        return 0;
 207
 208                /* FIXME: to properly support USERPTR, remap should occur.
 209                   The code below won't work, since mem->vma = NULL
 210                 */
 211                /* Try to remap memory */
 212                rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
 213                if (rc < 0) {
 214                        printk(KERN_ERR "mmap: remap failed with error %d", rc);
 215                        return -ENOMEM;
 216                }
 217#endif
 218
 219                break;
 220        case V4L2_MEMORY_OVERLAY:
 221        default:
 222                dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
 223
 224                /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
 225                printk(KERN_ERR "Memory method currently unsupported.\n");
 226                return -EINVAL;
 227        }
 228
 229        return 0;
 230}
 231
 232static int __videobuf_mmap_mapper(struct videobuf_queue *q,
 233                                  struct videobuf_buffer *buf,
 234                                  struct vm_area_struct *vma)
 235{
 236        struct videobuf_vmalloc_memory *mem;
 237        struct videobuf_mapping *map;
 238        int retval, pages;
 239
 240        dprintk(1, "%s\n", __func__);
 241
 242        /* create mapping + update buffer list */
 243        map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
 244        if (NULL == map)
 245                return -ENOMEM;
 246
 247        buf->map = map;
 248        map->q     = q;
 249
 250        buf->baddr = vma->vm_start;
 251
 252        mem = buf->priv;
 253        BUG_ON(!mem);
 254        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 255
 256        pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
 257        mem->vaddr = vmalloc_user(pages);
 258        if (!mem->vaddr) {
 259                printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
 260                goto error;
 261        }
 262        dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
 263
 264        /* Try to remap memory */
 265        retval = remap_vmalloc_range(vma, mem->vaddr, 0);
 266        if (retval < 0) {
 267                printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
 268                vfree(mem->vaddr);
 269                goto error;
 270        }
 271
 272        vma->vm_ops          = &videobuf_vm_ops;
 273        vma->vm_flags       |= VM_DONTEXPAND | VM_DONTDUMP;
 274        vma->vm_private_data = map;
 275
 276        dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
 277                map, q, vma->vm_start, vma->vm_end,
 278                (long int)buf->bsize,
 279                vma->vm_pgoff, buf->i);
 280
 281        videobuf_vm_open(vma);
 282
 283        return 0;
 284
 285error:
 286        mem = NULL;
 287        kfree(map);
 288        return -ENOMEM;
 289}
 290
 291static struct videobuf_qtype_ops qops = {
 292        .magic        = MAGIC_QTYPE_OPS,
 293
 294        .alloc_vb     = __videobuf_alloc_vb,
 295        .iolock       = __videobuf_iolock,
 296        .mmap_mapper  = __videobuf_mmap_mapper,
 297        .vaddr        = videobuf_to_vmalloc,
 298};
 299
 300void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
 301                         const struct videobuf_queue_ops *ops,
 302                         struct device *dev,
 303                         spinlock_t *irqlock,
 304                         enum v4l2_buf_type type,
 305                         enum v4l2_field field,
 306                         unsigned int msize,
 307                         void *priv,
 308                         struct mutex *ext_lock)
 309{
 310        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 311                                 priv, &qops, ext_lock);
 312}
 313EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 314
 315void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
 316{
 317        struct videobuf_vmalloc_memory *mem = buf->priv;
 318        BUG_ON(!mem);
 319        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 320
 321        return mem->vaddr;
 322}
 323EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 324
 325void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 326{
 327        struct videobuf_vmalloc_memory *mem = buf->priv;
 328
 329        /* mmapped memory can't be freed here, otherwise mmapped region
 330           would be released, while still needed. In this case, the memory
 331           release should happen inside videobuf_vm_close().
 332           So, it should free memory only if the memory were allocated for
 333           read() operation.
 334         */
 335        if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
 336                return;
 337
 338        if (!mem)
 339                return;
 340
 341        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 342
 343        vfree(mem->vaddr);
 344        mem->vaddr = NULL;
 345
 346        return;
 347}
 348EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 349
 350