diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/Kconfig | 5 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/videobuf2-dma-contig.c | 185 |
3 files changed, 191 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b8c21a729b86..b64183e06348 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -50,6 +50,11 @@ config VIDEOBUF2_CORE | |||
50 | config VIDEOBUF2_MEMOPS | 50 | config VIDEOBUF2_MEMOPS |
51 | tristate | 51 | tristate |
52 | 52 | ||
53 | config VIDEOBUF2_DMA_CONTIG | ||
54 | select VIDEOBUF2_CORE | ||
55 | select VIDEOBUF2_MEMOPS | ||
56 | tristate | ||
57 | |||
53 | config VIDEOBUF2_VMALLOC | 58 | config VIDEOBUF2_VMALLOC |
54 | select VIDEOBUF2_CORE | 59 | select VIDEOBUF2_CORE |
55 | select VIDEOBUF2_MEMOPS | 60 | select VIDEOBUF2_MEMOPS |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index e31c88e9ca76..106d40bbe724 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -114,6 +114,7 @@ obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o | |||
114 | obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o | 114 | obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o |
115 | obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o | 115 | obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o |
116 | obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o | 116 | obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o |
117 | obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o | ||
117 | 118 | ||
118 | obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o | 119 | obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o |
119 | 120 | ||
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c new file mode 100644 index 000000000000..bb6a5602cf94 --- /dev/null +++ b/drivers/media/video/videobuf2-dma-contig.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2 | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics | ||
5 | * | ||
6 | * Author: Pawel Osciak <p.osciak@samsung.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 | |||
20 | struct vb2_dc_conf { | ||
21 | struct device *dev; | ||
22 | }; | ||
23 | |||
24 | struct 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 | |||
34 | static void vb2_dma_contig_put(void *buf_priv); | ||
35 | |||
36 | static 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 | buf->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 | |||
66 | static 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 | |||
77 | static void *vb2_dma_contig_cookie(void *buf_priv) | ||
78 | { | ||
79 | struct vb2_dc_buf *buf = buf_priv; | ||
80 | |||
81 | return (void *)buf->paddr; | ||
82 | } | ||
83 | |||
84 | static 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 | |||
93 | static 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 | |||
100 | static 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 | |||
113 | static 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 | |||
140 | static 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 | |||
151 | const 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 | }; | ||
161 | EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); | ||
162 | |||
163 | void *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 | } | ||
175 | EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); | ||
176 | |||
177 | void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) | ||
178 | { | ||
179 | kfree(alloc_ctx); | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); | ||
182 | |||
183 | MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); | ||
184 | MODULE_AUTHOR("Pawel Osciak"); | ||
185 | MODULE_LICENSE("GPL"); | ||