linux/drivers/media/video/videobuf2-dma-contig.c
<<
>>
Prefs
   1/*
   2 * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2
   3 *
   4 * Copyright (C) 2010 Samsung Electronics
   5 *
   6 * Author: Pawel Osciak <pawel@osciak.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/slab.h>
  15#include <linux/dma-mapping.h>
  16
  17#include <media/videobuf2-core.h>
  18#include <media/videobuf2-memops.h>
  19
  20struct vb2_dc_conf {
  21        struct device           *dev;
  22};
  23
  24struct vb2_dc_buf {
  25        struct vb2_dc_conf              *conf;
  26        void                            *vaddr;
  27        dma_addr_t                      paddr;
  28        unsigned long                   size;
  29        struct vm_area_struct           *vma;
  30        atomic_t                        refcount;
  31        struct vb2_vmarea_handler       handler;
  32};
  33
  34static void vb2_dma_contig_put(void *buf_priv);
  35
  36static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
  37{
  38        struct vb2_dc_conf *conf = alloc_ctx;
  39        struct vb2_dc_buf *buf;
  40
  41        buf = kzalloc(sizeof *buf, GFP_KERNEL);
  42        if (!buf)
  43                return ERR_PTR(-ENOMEM);
  44
  45        buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr,
  46                                        GFP_KERNEL);
  47        if (!buf->vaddr) {
  48                dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n",
  49                        size);
  50                kfree(buf);
  51                return ERR_PTR(-ENOMEM);
  52        }
  53
  54        buf->conf = conf;
  55        buf->size = size;
  56
  57        buf->handler.refcount = &buf->refcount;
  58        buf->handler.put = vb2_dma_contig_put;
  59        buf->handler.arg = buf;
  60
  61        atomic_inc(&buf->refcount);
  62
  63        return buf;
  64}
  65
  66static void vb2_dma_contig_put(void *buf_priv)
  67{
  68        struct vb2_dc_buf *buf = buf_priv;
  69
  70        if (atomic_dec_and_test(&buf->refcount)) {
  71                dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr,
  72                                  buf->paddr);
  73                kfree(buf);
  74        }
  75}
  76
  77static void *vb2_dma_contig_cookie(void *buf_priv)
  78{
  79        struct vb2_dc_buf *buf = buf_priv;
  80
  81        return &buf->paddr;
  82}
  83
  84static void *vb2_dma_contig_vaddr(void *buf_priv)
  85{
  86        struct vb2_dc_buf *buf = buf_priv;
  87        if (!buf)
  88                return 0;
  89
  90        return buf->vaddr;
  91}
  92
  93static unsigned int vb2_dma_contig_num_users(void *buf_priv)
  94{
  95        struct vb2_dc_buf *buf = buf_priv;
  96
  97        return atomic_read(&buf->refcount);
  98}
  99
 100static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
 101{
 102        struct vb2_dc_buf *buf = buf_priv;
 103
 104        if (!buf) {
 105                printk(KERN_ERR "No buffer to map\n");
 106                return -EINVAL;
 107        }
 108
 109        return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
 110                                  &vb2_common_vm_ops, &buf->handler);
 111}
 112
 113static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
 114                                        unsigned long size, int write)
 115{
 116        struct vb2_dc_buf *buf;
 117        struct vm_area_struct *vma;
 118        dma_addr_t paddr = 0;
 119        int ret;
 120
 121        buf = kzalloc(sizeof *buf, GFP_KERNEL);
 122        if (!buf)
 123                return ERR_PTR(-ENOMEM);
 124
 125        ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
 126        if (ret) {
 127                printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
 128                                vaddr);
 129                kfree(buf);
 130                return ERR_PTR(ret);
 131        }
 132
 133        buf->size = size;
 134        buf->paddr = paddr;
 135        buf->vma = vma;
 136
 137        return buf;
 138}
 139
 140static void vb2_dma_contig_put_userptr(void *mem_priv)
 141{
 142        struct vb2_dc_buf *buf = mem_priv;
 143
 144        if (!buf)
 145                return;
 146
 147        vb2_put_vma(buf->vma);
 148        kfree(buf);
 149}
 150
 151const struct vb2_mem_ops vb2_dma_contig_memops = {
 152        .alloc          = vb2_dma_contig_alloc,
 153        .put            = vb2_dma_contig_put,
 154        .cookie         = vb2_dma_contig_cookie,
 155        .vaddr          = vb2_dma_contig_vaddr,
 156        .mmap           = vb2_dma_contig_mmap,
 157        .get_userptr    = vb2_dma_contig_get_userptr,
 158        .put_userptr    = vb2_dma_contig_put_userptr,
 159        .num_users      = vb2_dma_contig_num_users,
 160};
 161EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
 162
 163void *vb2_dma_contig_init_ctx(struct device *dev)
 164{
 165        struct vb2_dc_conf *conf;
 166
 167        conf = kzalloc(sizeof *conf, GFP_KERNEL);
 168        if (!conf)
 169                return ERR_PTR(-ENOMEM);
 170
 171        conf->dev = dev;
 172
 173        return conf;
 174}
 175EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
 176
 177void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
 178{
 179        kfree(alloc_ctx);
 180}
 181EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
 182
 183MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2");
 184MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
 185MODULE_LICENSE("GPL");
 186