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