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)  if (unlikely((is) != (should))) \
  34        { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
  35
  36static int debug;
  37module_param(debug, int, 0644);
  38
  39MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
  40MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
  41MODULE_LICENSE("GPL");
  42
  43#define dprintk(level, fmt, arg...)     if (debug >= level) \
  44        printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
  45
  46
  47/***************************************************************************/
  48
  49static void
  50videobuf_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
  60static 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
 119static const 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
 135static 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
 152static 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
 229static int __videobuf_sync(struct videobuf_queue *q,
 230                           struct videobuf_buffer *buf)
 231{
 232        return 0;
 233}
 234
 235static 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
 250static 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
 325error:
 326        mem = NULL;
 327        kfree(map);
 328        return -ENOMEM;
 329}
 330
 331static 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
 351static 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
 380static 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
 393void 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
 406EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
 407
 408void *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}
 416EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
 417
 418void 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}
 441EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
 442
 443/*
 444 * Local variables:
 445 * c-basic-offset: 8
 446 * End:
 447 */
 448