]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/media/v4l2-core/videobuf2-dma-contig.c
[media] v4l: vb2-dma-contig: reorder functions
[karo-tx-linux.git] / drivers / media / v4l2-core / videobuf2-dma-contig.c
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-dma-contig.h>
19 #include <media/videobuf2-memops.h>
20
21 struct vb2_dc_conf {
22         struct device           *dev;
23 };
24
25 struct vb2_dc_buf {
26         struct device                   *dev;
27         void                            *vaddr;
28         unsigned long                   size;
29         dma_addr_t                      dma_addr;
30
31         /* MMAP related */
32         struct vb2_vmarea_handler       handler;
33         atomic_t                        refcount;
34
35         /* USERPTR related */
36         struct vm_area_struct           *vma;
37 };
38
39 /*********************************************/
40 /*         callbacks for all buffers         */
41 /*********************************************/
42
43 static void *vb2_dc_cookie(void *buf_priv)
44 {
45         struct vb2_dc_buf *buf = buf_priv;
46
47         return &buf->dma_addr;
48 }
49
50 static void *vb2_dc_vaddr(void *buf_priv)
51 {
52         struct vb2_dc_buf *buf = buf_priv;
53
54         return buf->vaddr;
55 }
56
57 static unsigned int vb2_dc_num_users(void *buf_priv)
58 {
59         struct vb2_dc_buf *buf = buf_priv;
60
61         return atomic_read(&buf->refcount);
62 }
63
64 /*********************************************/
65 /*        callbacks for MMAP buffers         */
66 /*********************************************/
67
68 static void vb2_dc_put(void *buf_priv)
69 {
70         struct vb2_dc_buf *buf = buf_priv;
71
72         if (!atomic_dec_and_test(&buf->refcount))
73                 return;
74
75         dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->dma_addr);
76         kfree(buf);
77 }
78
79 static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size)
80 {
81         struct vb2_dc_conf *conf = alloc_ctx;
82         struct device *dev = conf->dev;
83         struct vb2_dc_buf *buf;
84
85         buf = kzalloc(sizeof *buf, GFP_KERNEL);
86         if (!buf)
87                 return ERR_PTR(-ENOMEM);
88
89         buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL);
90         if (!buf->vaddr) {
91                 dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
92                 kfree(buf);
93                 return ERR_PTR(-ENOMEM);
94         }
95
96         buf->dev = dev;
97         buf->size = size;
98
99         buf->handler.refcount = &buf->refcount;
100         buf->handler.put = vb2_dc_put;
101         buf->handler.arg = buf;
102
103         atomic_inc(&buf->refcount);
104
105         return buf;
106 }
107
108 static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
109 {
110         struct vb2_dc_buf *buf = buf_priv;
111
112         if (!buf) {
113                 printk(KERN_ERR "No buffer to map\n");
114                 return -EINVAL;
115         }
116
117         return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size,
118                                   &vb2_common_vm_ops, &buf->handler);
119 }
120
121 /*********************************************/
122 /*       callbacks for USERPTR buffers       */
123 /*********************************************/
124
125 static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
126                                         unsigned long size, int write)
127 {
128         struct vb2_dc_buf *buf;
129         struct vm_area_struct *vma;
130         dma_addr_t dma_addr = 0;
131         int ret;
132
133         buf = kzalloc(sizeof *buf, GFP_KERNEL);
134         if (!buf)
135                 return ERR_PTR(-ENOMEM);
136
137         ret = vb2_get_contig_userptr(vaddr, size, &vma, &dma_addr);
138         if (ret) {
139                 printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
140                                 vaddr);
141                 kfree(buf);
142                 return ERR_PTR(ret);
143         }
144
145         buf->size = size;
146         buf->dma_addr = dma_addr;
147         buf->vma = vma;
148
149         return buf;
150 }
151
152 static void vb2_dc_put_userptr(void *mem_priv)
153 {
154         struct vb2_dc_buf *buf = mem_priv;
155
156         if (!buf)
157                 return;
158
159         vb2_put_vma(buf->vma);
160         kfree(buf);
161 }
162
163 /*********************************************/
164 /*       DMA CONTIG exported functions       */
165 /*********************************************/
166
167 const struct vb2_mem_ops vb2_dma_contig_memops = {
168         .alloc          = vb2_dc_alloc,
169         .put            = vb2_dc_put,
170         .cookie         = vb2_dc_cookie,
171         .vaddr          = vb2_dc_vaddr,
172         .mmap           = vb2_dc_mmap,
173         .get_userptr    = vb2_dc_get_userptr,
174         .put_userptr    = vb2_dc_put_userptr,
175         .num_users      = vb2_dc_num_users,
176 };
177 EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
178
179 void *vb2_dma_contig_init_ctx(struct device *dev)
180 {
181         struct vb2_dc_conf *conf;
182
183         conf = kzalloc(sizeof *conf, GFP_KERNEL);
184         if (!conf)
185                 return ERR_PTR(-ENOMEM);
186
187         conf->dev = dev;
188
189         return conf;
190 }
191 EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
192
193 void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
194 {
195         kfree(alloc_ctx);
196 }
197 EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
198
199 MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2");
200 MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>");
201 MODULE_LICENSE("GPL");