linux/drivers/media/video/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                mutex_lock(&q->vb_lock);
  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->vmalloc);
 106
 107                                vfree(mem->vmalloc);
 108                                mem->vmalloc = NULL;
 109                        }
 110
 111                        q->bufs[i]->map   = NULL;
 112                        q->bufs[i]->baddr = 0;
 113                }
 114
 115                kfree(map);
 116
 117                mutex_unlock(&q->vb_lock);
 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(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->vmalloc) {
 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->vmalloc = vmalloc_user(pages);
 193                if (!mem->vmalloc) {
 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->vmalloc, 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->start = vma->vm_start;
 249        map->end   = vma->vm_end;
 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->vmalloc = vmalloc_user(pages);
 260        if (!mem->vmalloc) {
 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->vmalloc, pages);
 265
 266        /* Try to remap memory */
 267        retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
 268        if (retval < 0) {
 269                printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
 270                vfree(mem->vmalloc);
 271                goto error;
 272        }
 273
 274        vma->vm_ops          = &videobuf_vm_ops;
 275        vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
 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        = __videobuf_alloc,
 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{
 311        videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
 312                                 priv, &qops);
 313}
 314EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 315
 316void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
 317{
 318        struct videobuf_vmalloc_memory *mem = buf->priv;
 319        BUG_ON(!mem);
 320        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 321
 322        return mem->vmalloc;
 323}
 324EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 325
 326void videobuf_vmalloc_free(struct videobuf_buffer *buf)
 327{
 328        struct videobuf_vmalloc_memory *mem = buf->priv;
 329
 330        /* mmapped memory can't be freed here, otherwise mmapped region
 331           would be released, while still needed. In this case, the memory
 332           release should happen inside videobuf_vm_close().
 333           So, it should free memory only if the memory were allocated for
 334           read() operation.
 335         */
 336        if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
 337                return;
 338
 339        if (!mem)
 340                return;
 341
 342        MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
 343
 344        vfree(mem->vmalloc);
 345        mem->vmalloc = NULL;
 346
 347        return;
 348}
 349EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 350
 351