diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-10-09 07:01:05 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-04-16 17:59:29 -0400 |
commit | 701b57ee3387b8e3749845b02310b5625fbd8da0 (patch) | |
tree | 359260df9fa9bad7c82eaf9374a5e1bf502b9401 | |
parent | 3415a89f48dce655ae353bc70a8e292764e8e931 (diff) |
[media] vb2: Add videobuf2-dvb support
With the new vb2_thread_start/stop core code it is very easy to implement
videobuf2-dvb. This should simplify converting existing videobuf drivers to
vb2.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r-- | drivers/media/v4l2-core/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/v4l2-core/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-dvb.c | 336 | ||||
-rw-r--r-- | include/media/videobuf2-dvb.h | 58 |
4 files changed, 399 insertions, 0 deletions
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 2189bfb2e828..9ca0f8d59a14 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig | |||
@@ -83,3 +83,7 @@ config VIDEOBUF2_DMA_SG | |||
83 | #depends on HAS_DMA | 83 | #depends on HAS_DMA |
84 | select VIDEOBUF2_CORE | 84 | select VIDEOBUF2_CORE |
85 | select VIDEOBUF2_MEMOPS | 85 | select VIDEOBUF2_MEMOPS |
86 | |||
87 | config VIDEOBUF2_DVB | ||
88 | tristate | ||
89 | select VIDEOBUF2_CORE | ||
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index c6ae7bad951e..63d29f27538c 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile | |||
@@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o | |||
33 | obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o | 33 | obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o |
34 | obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o | 34 | obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o |
35 | obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o | 35 | obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o |
36 | obj-$(CONFIG_VIDEOBUF2_DVB) += videobuf2-dvb.o | ||
36 | 37 | ||
37 | ccflags-y += -I$(srctree)/drivers/media/dvb-core | 38 | ccflags-y += -I$(srctree)/drivers/media/dvb-core |
38 | ccflags-y += -I$(srctree)/drivers/media/dvb-frontends | 39 | ccflags-y += -I$(srctree)/drivers/media/dvb-frontends |
diff --git a/drivers/media/v4l2-core/videobuf2-dvb.c b/drivers/media/v4l2-core/videobuf2-dvb.c new file mode 100644 index 000000000000..d09269846b7e --- /dev/null +++ b/drivers/media/v4l2-core/videobuf2-dvb.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * | ||
3 | * some helper function for simple DVB cards which simply DMA the | ||
4 | * complete transport stream and let the computer sort everything else | ||
5 | * (i.e. we are using the software demux, ...). Also uses the | ||
6 | * video-buf to manage DMA buffers. | ||
7 | * | ||
8 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <media/videobuf2-dvb.h> | ||
22 | |||
23 | /* ------------------------------------------------------------------ */ | ||
24 | |||
25 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | /* ------------------------------------------------------------------ */ | ||
29 | |||
30 | static int dvb_fnc(struct vb2_buffer *vb, void *priv) | ||
31 | { | ||
32 | struct vb2_dvb *dvb = priv; | ||
33 | |||
34 | dvb_dmx_swfilter(&dvb->demux, vb2_plane_vaddr(vb, 0), | ||
35 | vb2_get_plane_payload(vb, 0)); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int vb2_dvb_start_feed(struct dvb_demux_feed *feed) | ||
40 | { | ||
41 | struct dvb_demux *demux = feed->demux; | ||
42 | struct vb2_dvb *dvb = demux->priv; | ||
43 | int rc = 0; | ||
44 | |||
45 | if (!demux->dmx.frontend) | ||
46 | return -EINVAL; | ||
47 | |||
48 | mutex_lock(&dvb->lock); | ||
49 | dvb->nfeeds++; | ||
50 | |||
51 | if (!dvb->dvbq.threadio) { | ||
52 | rc = vb2_thread_start(&dvb->dvbq, dvb_fnc, dvb, dvb->name); | ||
53 | if (rc) | ||
54 | dvb->nfeeds--; | ||
55 | } | ||
56 | if (!rc) | ||
57 | rc = dvb->nfeeds; | ||
58 | mutex_unlock(&dvb->lock); | ||
59 | return rc; | ||
60 | } | ||
61 | |||
62 | static int vb2_dvb_stop_feed(struct dvb_demux_feed *feed) | ||
63 | { | ||
64 | struct dvb_demux *demux = feed->demux; | ||
65 | struct vb2_dvb *dvb = demux->priv; | ||
66 | int err = 0; | ||
67 | |||
68 | mutex_lock(&dvb->lock); | ||
69 | dvb->nfeeds--; | ||
70 | if (0 == dvb->nfeeds) | ||
71 | err = vb2_thread_stop(&dvb->dvbq); | ||
72 | mutex_unlock(&dvb->lock); | ||
73 | return err; | ||
74 | } | ||
75 | |||
76 | static int vb2_dvb_register_adapter(struct vb2_dvb_frontends *fe, | ||
77 | struct module *module, | ||
78 | void *adapter_priv, | ||
79 | struct device *device, | ||
80 | char *adapter_name, | ||
81 | short *adapter_nr, | ||
82 | int mfe_shared) | ||
83 | { | ||
84 | int result; | ||
85 | |||
86 | mutex_init(&fe->lock); | ||
87 | |||
88 | /* register adapter */ | ||
89 | result = dvb_register_adapter(&fe->adapter, adapter_name, module, | ||
90 | device, adapter_nr); | ||
91 | if (result < 0) { | ||
92 | pr_warn("%s: dvb_register_adapter failed (errno = %d)\n", | ||
93 | adapter_name, result); | ||
94 | } | ||
95 | fe->adapter.priv = adapter_priv; | ||
96 | fe->adapter.mfe_shared = mfe_shared; | ||
97 | |||
98 | return result; | ||
99 | } | ||
100 | |||
101 | static int vb2_dvb_register_frontend(struct dvb_adapter *adapter, | ||
102 | struct vb2_dvb *dvb) | ||
103 | { | ||
104 | int result; | ||
105 | |||
106 | /* register frontend */ | ||
107 | result = dvb_register_frontend(adapter, dvb->frontend); | ||
108 | if (result < 0) { | ||
109 | pr_warn("%s: dvb_register_frontend failed (errno = %d)\n", | ||
110 | dvb->name, result); | ||
111 | goto fail_frontend; | ||
112 | } | ||
113 | |||
114 | /* register demux stuff */ | ||
115 | dvb->demux.dmx.capabilities = | ||
116 | DMX_TS_FILTERING | DMX_SECTION_FILTERING | | ||
117 | DMX_MEMORY_BASED_FILTERING; | ||
118 | dvb->demux.priv = dvb; | ||
119 | dvb->demux.filternum = 256; | ||
120 | dvb->demux.feednum = 256; | ||
121 | dvb->demux.start_feed = vb2_dvb_start_feed; | ||
122 | dvb->demux.stop_feed = vb2_dvb_stop_feed; | ||
123 | result = dvb_dmx_init(&dvb->demux); | ||
124 | if (result < 0) { | ||
125 | pr_warn("%s: dvb_dmx_init failed (errno = %d)\n", | ||
126 | dvb->name, result); | ||
127 | goto fail_dmx; | ||
128 | } | ||
129 | |||
130 | dvb->dmxdev.filternum = 256; | ||
131 | dvb->dmxdev.demux = &dvb->demux.dmx; | ||
132 | dvb->dmxdev.capabilities = 0; | ||
133 | result = dvb_dmxdev_init(&dvb->dmxdev, adapter); | ||
134 | |||
135 | if (result < 0) { | ||
136 | pr_warn("%s: dvb_dmxdev_init failed (errno = %d)\n", | ||
137 | dvb->name, result); | ||
138 | goto fail_dmxdev; | ||
139 | } | ||
140 | |||
141 | dvb->fe_hw.source = DMX_FRONTEND_0; | ||
142 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
143 | if (result < 0) { | ||
144 | pr_warn("%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", | ||
145 | dvb->name, result); | ||
146 | goto fail_fe_hw; | ||
147 | } | ||
148 | |||
149 | dvb->fe_mem.source = DMX_MEMORY_FE; | ||
150 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
151 | if (result < 0) { | ||
152 | pr_warn("%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", | ||
153 | dvb->name, result); | ||
154 | goto fail_fe_mem; | ||
155 | } | ||
156 | |||
157 | result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
158 | if (result < 0) { | ||
159 | pr_warn("%s: connect_frontend failed (errno = %d)\n", | ||
160 | dvb->name, result); | ||
161 | goto fail_fe_conn; | ||
162 | } | ||
163 | |||
164 | /* register network adapter */ | ||
165 | result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); | ||
166 | if (result < 0) { | ||
167 | pr_warn("%s: dvb_net_init failed (errno = %d)\n", | ||
168 | dvb->name, result); | ||
169 | goto fail_fe_conn; | ||
170 | } | ||
171 | return 0; | ||
172 | |||
173 | fail_fe_conn: | ||
174 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | ||
175 | fail_fe_mem: | ||
176 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | ||
177 | fail_fe_hw: | ||
178 | dvb_dmxdev_release(&dvb->dmxdev); | ||
179 | fail_dmxdev: | ||
180 | dvb_dmx_release(&dvb->demux); | ||
181 | fail_dmx: | ||
182 | dvb_unregister_frontend(dvb->frontend); | ||
183 | fail_frontend: | ||
184 | dvb_frontend_detach(dvb->frontend); | ||
185 | dvb->frontend = NULL; | ||
186 | |||
187 | return result; | ||
188 | } | ||
189 | |||
190 | /* ------------------------------------------------------------------ */ | ||
191 | /* Register a single adapter and one or more frontends */ | ||
192 | int vb2_dvb_register_bus(struct vb2_dvb_frontends *f, | ||
193 | struct module *module, | ||
194 | void *adapter_priv, | ||
195 | struct device *device, | ||
196 | short *adapter_nr, | ||
197 | int mfe_shared) | ||
198 | { | ||
199 | struct list_head *list, *q; | ||
200 | struct vb2_dvb_frontend *fe; | ||
201 | int res; | ||
202 | |||
203 | fe = vb2_dvb_get_frontend(f, 1); | ||
204 | if (!fe) { | ||
205 | pr_warn("Unable to register the adapter which has no frontends\n"); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | /* Bring up the adapter */ | ||
210 | res = vb2_dvb_register_adapter(f, module, adapter_priv, device, | ||
211 | fe->dvb.name, adapter_nr, mfe_shared); | ||
212 | if (res < 0) { | ||
213 | pr_warn("vb2_dvb_register_adapter failed (errno = %d)\n", res); | ||
214 | return res; | ||
215 | } | ||
216 | |||
217 | /* Attach all of the frontends to the adapter */ | ||
218 | mutex_lock(&f->lock); | ||
219 | list_for_each_safe(list, q, &f->felist) { | ||
220 | fe = list_entry(list, struct vb2_dvb_frontend, felist); | ||
221 | res = vb2_dvb_register_frontend(&f->adapter, &fe->dvb); | ||
222 | if (res < 0) { | ||
223 | pr_warn("%s: vb2_dvb_register_frontend failed (errno = %d)\n", | ||
224 | fe->dvb.name, res); | ||
225 | goto err; | ||
226 | } | ||
227 | } | ||
228 | mutex_unlock(&f->lock); | ||
229 | return 0; | ||
230 | |||
231 | err: | ||
232 | mutex_unlock(&f->lock); | ||
233 | vb2_dvb_unregister_bus(f); | ||
234 | return res; | ||
235 | } | ||
236 | EXPORT_SYMBOL(vb2_dvb_register_bus); | ||
237 | |||
238 | void vb2_dvb_unregister_bus(struct vb2_dvb_frontends *f) | ||
239 | { | ||
240 | vb2_dvb_dealloc_frontends(f); | ||
241 | |||
242 | dvb_unregister_adapter(&f->adapter); | ||
243 | } | ||
244 | EXPORT_SYMBOL(vb2_dvb_unregister_bus); | ||
245 | |||
246 | struct vb2_dvb_frontend *vb2_dvb_get_frontend( | ||
247 | struct vb2_dvb_frontends *f, int id) | ||
248 | { | ||
249 | struct list_head *list, *q; | ||
250 | struct vb2_dvb_frontend *fe, *ret = NULL; | ||
251 | |||
252 | mutex_lock(&f->lock); | ||
253 | |||
254 | list_for_each_safe(list, q, &f->felist) { | ||
255 | fe = list_entry(list, struct vb2_dvb_frontend, felist); | ||
256 | if (fe->id == id) { | ||
257 | ret = fe; | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | mutex_unlock(&f->lock); | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | EXPORT_SYMBOL(vb2_dvb_get_frontend); | ||
267 | |||
268 | int vb2_dvb_find_frontend(struct vb2_dvb_frontends *f, | ||
269 | struct dvb_frontend *p) | ||
270 | { | ||
271 | struct list_head *list, *q; | ||
272 | struct vb2_dvb_frontend *fe = NULL; | ||
273 | int ret = 0; | ||
274 | |||
275 | mutex_lock(&f->lock); | ||
276 | |||
277 | list_for_each_safe(list, q, &f->felist) { | ||
278 | fe = list_entry(list, struct vb2_dvb_frontend, felist); | ||
279 | if (fe->dvb.frontend == p) { | ||
280 | ret = fe->id; | ||
281 | break; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | mutex_unlock(&f->lock); | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | EXPORT_SYMBOL(vb2_dvb_find_frontend); | ||
290 | |||
291 | struct vb2_dvb_frontend *vb2_dvb_alloc_frontend( | ||
292 | struct vb2_dvb_frontends *f, int id) | ||
293 | { | ||
294 | struct vb2_dvb_frontend *fe; | ||
295 | |||
296 | fe = kzalloc(sizeof(struct vb2_dvb_frontend), GFP_KERNEL); | ||
297 | if (fe == NULL) | ||
298 | return NULL; | ||
299 | |||
300 | fe->id = id; | ||
301 | mutex_init(&fe->dvb.lock); | ||
302 | |||
303 | mutex_lock(&f->lock); | ||
304 | list_add_tail(&fe->felist, &f->felist); | ||
305 | mutex_unlock(&f->lock); | ||
306 | return fe; | ||
307 | } | ||
308 | EXPORT_SYMBOL(vb2_dvb_alloc_frontend); | ||
309 | |||
310 | void vb2_dvb_dealloc_frontends(struct vb2_dvb_frontends *f) | ||
311 | { | ||
312 | struct list_head *list, *q; | ||
313 | struct vb2_dvb_frontend *fe; | ||
314 | |||
315 | mutex_lock(&f->lock); | ||
316 | list_for_each_safe(list, q, &f->felist) { | ||
317 | fe = list_entry(list, struct vb2_dvb_frontend, felist); | ||
318 | if (fe->dvb.net.dvbdev) { | ||
319 | dvb_net_release(&fe->dvb.net); | ||
320 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, | ||
321 | &fe->dvb.fe_mem); | ||
322 | fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, | ||
323 | &fe->dvb.fe_hw); | ||
324 | dvb_dmxdev_release(&fe->dvb.dmxdev); | ||
325 | dvb_dmx_release(&fe->dvb.demux); | ||
326 | dvb_unregister_frontend(fe->dvb.frontend); | ||
327 | } | ||
328 | if (fe->dvb.frontend) | ||
329 | /* always allocated, may have been reset */ | ||
330 | dvb_frontend_detach(fe->dvb.frontend); | ||
331 | list_del(list); /* remove list entry */ | ||
332 | kfree(fe); /* free frontend allocation */ | ||
333 | } | ||
334 | mutex_unlock(&f->lock); | ||
335 | } | ||
336 | EXPORT_SYMBOL(vb2_dvb_dealloc_frontends); | ||
diff --git a/include/media/videobuf2-dvb.h b/include/media/videobuf2-dvb.h new file mode 100644 index 000000000000..8f61456f1394 --- /dev/null +++ b/include/media/videobuf2-dvb.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef _VIDEOBUF2_DVB_H_ | ||
2 | #define _VIDEOBUF2_DVB_H_ | ||
3 | |||
4 | #include <dvbdev.h> | ||
5 | #include <dmxdev.h> | ||
6 | #include <dvb_demux.h> | ||
7 | #include <dvb_net.h> | ||
8 | #include <dvb_frontend.h> | ||
9 | #include <media/videobuf2-core.h> | ||
10 | |||
11 | struct vb2_dvb { | ||
12 | /* filling that the job of the driver */ | ||
13 | char *name; | ||
14 | struct dvb_frontend *frontend; | ||
15 | struct vb2_queue dvbq; | ||
16 | |||
17 | /* video-buf-dvb state info */ | ||
18 | struct mutex lock; | ||
19 | int nfeeds; | ||
20 | |||
21 | /* vb2_dvb_(un)register manages this */ | ||
22 | struct dvb_demux demux; | ||
23 | struct dmxdev dmxdev; | ||
24 | struct dmx_frontend fe_hw; | ||
25 | struct dmx_frontend fe_mem; | ||
26 | struct dvb_net net; | ||
27 | }; | ||
28 | |||
29 | struct vb2_dvb_frontend { | ||
30 | struct list_head felist; | ||
31 | int id; | ||
32 | struct vb2_dvb dvb; | ||
33 | }; | ||
34 | |||
35 | struct vb2_dvb_frontends { | ||
36 | struct list_head felist; | ||
37 | struct mutex lock; | ||
38 | struct dvb_adapter adapter; | ||
39 | int active_fe_id; /* Indicates which frontend in the felist is in use */ | ||
40 | int gate; /* Frontend with gate control 0=!MFE,1=fe0,2=fe1 etc */ | ||
41 | }; | ||
42 | |||
43 | int vb2_dvb_register_bus(struct vb2_dvb_frontends *f, | ||
44 | struct module *module, | ||
45 | void *adapter_priv, | ||
46 | struct device *device, | ||
47 | short *adapter_nr, | ||
48 | int mfe_shared); | ||
49 | |||
50 | void vb2_dvb_unregister_bus(struct vb2_dvb_frontends *f); | ||
51 | |||
52 | struct vb2_dvb_frontend *vb2_dvb_alloc_frontend(struct vb2_dvb_frontends *f, int id); | ||
53 | void vb2_dvb_dealloc_frontends(struct vb2_dvb_frontends *f); | ||
54 | |||
55 | struct vb2_dvb_frontend *vb2_dvb_get_frontend(struct vb2_dvb_frontends *f, int id); | ||
56 | int vb2_dvb_find_frontend(struct vb2_dvb_frontends *f, struct dvb_frontend *p); | ||
57 | |||
58 | #endif /* _VIDEOBUF2_DVB_H_ */ | ||