PageRenderTime 36ms CodeModel.GetById 22ms app.highlight 13ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/media/video/videobuf2-dma-contig.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 185 lines | 136 code | 38 blank | 11 comment | 9 complexity | 2f16fc4af2606fb66315fc850a6238b8 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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");