This source file includes following definitions.
- v4l2_mc_create_media_graph
- v4l_enable_media_source
- v4l_disable_media_source
- v4l_vb2q_enable_media_source
- pipeline_pm_use_count
- pipeline_pm_power_one
- pipeline_pm_power
- v4l2_pipeline_pm_use
- v4l2_pipeline_link_notify
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/module.h>
13 #include <linux/pci.h>
14 #include <linux/usb.h>
15 #include <media/media-device.h>
16 #include <media/media-entity.h>
17 #include <media/v4l2-fh.h>
18 #include <media/v4l2-mc.h>
19 #include <media/v4l2-subdev.h>
20 #include <media/videobuf2-core.h>
21
22 int v4l2_mc_create_media_graph(struct media_device *mdev)
23
24 {
25 struct media_entity *entity;
26 struct media_entity *if_vid = NULL, *if_aud = NULL;
27 struct media_entity *tuner = NULL, *decoder = NULL;
28 struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
29 bool is_webcam = false;
30 u32 flags;
31 int ret, pad_sink, pad_source;
32
33 if (!mdev)
34 return 0;
35
36 media_device_for_each_entity(entity, mdev) {
37 switch (entity->function) {
38 case MEDIA_ENT_F_IF_VID_DECODER:
39 if_vid = entity;
40 break;
41 case MEDIA_ENT_F_IF_AUD_DECODER:
42 if_aud = entity;
43 break;
44 case MEDIA_ENT_F_TUNER:
45 tuner = entity;
46 break;
47 case MEDIA_ENT_F_ATV_DECODER:
48 decoder = entity;
49 break;
50 case MEDIA_ENT_F_IO_V4L:
51 io_v4l = entity;
52 break;
53 case MEDIA_ENT_F_IO_VBI:
54 io_vbi = entity;
55 break;
56 case MEDIA_ENT_F_IO_SWRADIO:
57 io_swradio = entity;
58 break;
59 case MEDIA_ENT_F_CAM_SENSOR:
60 is_webcam = true;
61 break;
62 }
63 }
64
65
66 if (!io_v4l && !io_vbi && !io_swradio) {
67 dev_warn(mdev->dev, "Didn't find any I/O entity\n");
68 return -EINVAL;
69 }
70
71
72
73
74
75
76
77
78 if (is_webcam) {
79 if (!io_v4l) {
80 dev_warn(mdev->dev, "Didn't find a MEDIA_ENT_F_IO_V4L\n");
81 return -EINVAL;
82 }
83
84 media_device_for_each_entity(entity, mdev) {
85 if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
86 continue;
87 ret = media_create_pad_link(entity, 0,
88 io_v4l, 0,
89 MEDIA_LNK_FL_ENABLED);
90 if (ret) {
91 dev_warn(mdev->dev, "Failed to create a sensor link\n");
92 return ret;
93 }
94 }
95 if (!decoder)
96 return 0;
97 }
98
99
100 if (!decoder) {
101 dev_warn(mdev->dev, "Decoder not found\n");
102 return -EINVAL;
103 }
104
105
106 if (tuner) {
107 if (if_vid) {
108 pad_source = media_get_pad_index(tuner, false,
109 PAD_SIGNAL_ANALOG);
110 pad_sink = media_get_pad_index(if_vid, true,
111 PAD_SIGNAL_ANALOG);
112 if (pad_source < 0 || pad_sink < 0) {
113 dev_warn(mdev->dev, "Couldn't get tuner and/or PLL pad(s): (%d, %d)\n",
114 pad_source, pad_sink);
115 return -EINVAL;
116 }
117 ret = media_create_pad_link(tuner, pad_source,
118 if_vid, pad_sink,
119 MEDIA_LNK_FL_ENABLED);
120 if (ret) {
121 dev_warn(mdev->dev, "Couldn't create tuner->PLL link)\n");
122 return ret;
123 }
124
125 pad_source = media_get_pad_index(if_vid, false,
126 PAD_SIGNAL_ANALOG);
127 pad_sink = media_get_pad_index(decoder, true,
128 PAD_SIGNAL_ANALOG);
129 if (pad_source < 0 || pad_sink < 0) {
130 dev_warn(mdev->dev, "get decoder and/or PLL pad(s): (%d, %d)\n",
131 pad_source, pad_sink);
132 return -EINVAL;
133 }
134 ret = media_create_pad_link(if_vid, pad_source,
135 decoder, pad_sink,
136 MEDIA_LNK_FL_ENABLED);
137 if (ret) {
138 dev_warn(mdev->dev, "couldn't link PLL to decoder\n");
139 return ret;
140 }
141 } else {
142 pad_source = media_get_pad_index(tuner, false,
143 PAD_SIGNAL_ANALOG);
144 pad_sink = media_get_pad_index(decoder, true,
145 PAD_SIGNAL_ANALOG);
146 if (pad_source < 0 || pad_sink < 0) {
147 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s): (%d, %d)\n",
148 pad_source, pad_sink);
149 return -EINVAL;
150 }
151 ret = media_create_pad_link(tuner, pad_source,
152 decoder, pad_sink,
153 MEDIA_LNK_FL_ENABLED);
154 if (ret)
155 return ret;
156 }
157
158 if (if_aud) {
159 pad_source = media_get_pad_index(tuner, false,
160 PAD_SIGNAL_AUDIO);
161 pad_sink = media_get_pad_index(if_aud, true,
162 PAD_SIGNAL_AUDIO);
163 if (pad_source < 0 || pad_sink < 0) {
164 dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s) for audio: (%d, %d)\n",
165 pad_source, pad_sink);
166 return -EINVAL;
167 }
168 ret = media_create_pad_link(tuner, pad_source,
169 if_aud, pad_sink,
170 MEDIA_LNK_FL_ENABLED);
171 if (ret) {
172 dev_warn(mdev->dev, "couldn't link tuner->audio PLL\n");
173 return ret;
174 }
175 } else {
176 if_aud = tuner;
177 }
178
179 }
180
181
182 if (io_v4l) {
183 pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
184 if (pad_source < 0) {
185 dev_warn(mdev->dev, "couldn't get decoder output pad for V4L I/O\n");
186 return -EINVAL;
187 }
188 ret = media_create_pad_link(decoder, pad_source,
189 io_v4l, 0,
190 MEDIA_LNK_FL_ENABLED);
191 if (ret) {
192 dev_warn(mdev->dev, "couldn't link decoder output to V4L I/O\n");
193 return ret;
194 }
195 }
196
197 if (io_swradio) {
198 pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
199 if (pad_source < 0) {
200 dev_warn(mdev->dev, "couldn't get decoder output pad for SDR\n");
201 return -EINVAL;
202 }
203 ret = media_create_pad_link(decoder, pad_source,
204 io_swradio, 0,
205 MEDIA_LNK_FL_ENABLED);
206 if (ret) {
207 dev_warn(mdev->dev, "couldn't link decoder output to SDR\n");
208 return ret;
209 }
210 }
211
212 if (io_vbi) {
213 pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV);
214 if (pad_source < 0) {
215 dev_warn(mdev->dev, "couldn't get decoder output pad for VBI\n");
216 return -EINVAL;
217 }
218 ret = media_create_pad_link(decoder, pad_source,
219 io_vbi, 0,
220 MEDIA_LNK_FL_ENABLED);
221 if (ret) {
222 dev_warn(mdev->dev, "couldn't link decoder output to VBI\n");
223 return ret;
224 }
225 }
226
227
228 flags = MEDIA_LNK_FL_ENABLED;
229 media_device_for_each_entity(entity, mdev) {
230 switch (entity->function) {
231 case MEDIA_ENT_F_CONN_RF:
232 if (!tuner)
233 continue;
234 pad_sink = media_get_pad_index(tuner, true,
235 PAD_SIGNAL_ANALOG);
236 if (pad_sink < 0) {
237 dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
238 return -EINVAL;
239 }
240 ret = media_create_pad_link(entity, 0, tuner,
241 pad_sink,
242 flags);
243 break;
244 case MEDIA_ENT_F_CONN_SVIDEO:
245 case MEDIA_ENT_F_CONN_COMPOSITE:
246 pad_sink = media_get_pad_index(decoder, true,
247 PAD_SIGNAL_ANALOG);
248 if (pad_sink < 0) {
249 dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n");
250 return -EINVAL;
251 }
252 ret = media_create_pad_link(entity, 0, decoder,
253 pad_sink,
254 flags);
255 break;
256 default:
257 continue;
258 }
259 if (ret)
260 return ret;
261
262 flags = 0;
263 }
264
265 return 0;
266 }
267 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
268
269 int v4l_enable_media_source(struct video_device *vdev)
270 {
271 struct media_device *mdev = vdev->entity.graph_obj.mdev;
272 int ret = 0, err;
273
274 if (!mdev)
275 return 0;
276
277 mutex_lock(&mdev->graph_mutex);
278 if (!mdev->enable_source)
279 goto end;
280 err = mdev->enable_source(&vdev->entity, &vdev->pipe);
281 if (err)
282 ret = -EBUSY;
283 end:
284 mutex_unlock(&mdev->graph_mutex);
285 return ret;
286 }
287 EXPORT_SYMBOL_GPL(v4l_enable_media_source);
288
289 void v4l_disable_media_source(struct video_device *vdev)
290 {
291 struct media_device *mdev = vdev->entity.graph_obj.mdev;
292
293 if (mdev) {
294 mutex_lock(&mdev->graph_mutex);
295 if (mdev->disable_source)
296 mdev->disable_source(&vdev->entity);
297 mutex_unlock(&mdev->graph_mutex);
298 }
299 }
300 EXPORT_SYMBOL_GPL(v4l_disable_media_source);
301
302 int v4l_vb2q_enable_media_source(struct vb2_queue *q)
303 {
304 struct v4l2_fh *fh = q->owner;
305
306 if (fh && fh->vdev)
307 return v4l_enable_media_source(fh->vdev);
308 return 0;
309 }
310 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339 static int pipeline_pm_use_count(struct media_entity *entity,
340 struct media_graph *graph)
341 {
342 int use = 0;
343
344 media_graph_walk_start(graph, entity);
345
346 while ((entity = media_graph_walk_next(graph))) {
347 if (is_media_entity_v4l2_video_device(entity))
348 use += entity->use_count;
349 }
350
351 return use;
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365 static int pipeline_pm_power_one(struct media_entity *entity, int change)
366 {
367 struct v4l2_subdev *subdev;
368 int ret;
369
370 subdev = is_media_entity_v4l2_subdev(entity)
371 ? media_entity_to_v4l2_subdev(entity) : NULL;
372
373 if (entity->use_count == 0 && change > 0 && subdev != NULL) {
374 ret = v4l2_subdev_call(subdev, core, s_power, 1);
375 if (ret < 0 && ret != -ENOIOCTLCMD)
376 return ret;
377 }
378
379 entity->use_count += change;
380 WARN_ON(entity->use_count < 0);
381
382 if (entity->use_count == 0 && change < 0 && subdev != NULL)
383 v4l2_subdev_call(subdev, core, s_power, 0);
384
385 return 0;
386 }
387
388
389
390
391
392
393
394
395
396
397
398 static int pipeline_pm_power(struct media_entity *entity, int change,
399 struct media_graph *graph)
400 {
401 struct media_entity *first = entity;
402 int ret = 0;
403
404 if (!change)
405 return 0;
406
407 media_graph_walk_start(graph, entity);
408
409 while (!ret && (entity = media_graph_walk_next(graph)))
410 if (is_media_entity_v4l2_subdev(entity))
411 ret = pipeline_pm_power_one(entity, change);
412
413 if (!ret)
414 return ret;
415
416 media_graph_walk_start(graph, first);
417
418 while ((first = media_graph_walk_next(graph))
419 && first != entity)
420 if (is_media_entity_v4l2_subdev(first))
421 pipeline_pm_power_one(first, -change);
422
423 return ret;
424 }
425
426 int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
427 {
428 struct media_device *mdev = entity->graph_obj.mdev;
429 int change = use ? 1 : -1;
430 int ret;
431
432 mutex_lock(&mdev->graph_mutex);
433
434
435 entity->use_count += change;
436 WARN_ON(entity->use_count < 0);
437
438
439 ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
440 if (ret < 0)
441 entity->use_count -= change;
442
443 mutex_unlock(&mdev->graph_mutex);
444
445 return ret;
446 }
447 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use);
448
449 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
450 unsigned int notification)
451 {
452 struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
453 struct media_entity *source = link->source->entity;
454 struct media_entity *sink = link->sink->entity;
455 int source_use;
456 int sink_use;
457 int ret = 0;
458
459 source_use = pipeline_pm_use_count(source, graph);
460 sink_use = pipeline_pm_use_count(sink, graph);
461
462 if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
463 !(flags & MEDIA_LNK_FL_ENABLED)) {
464
465 pipeline_pm_power(source, -sink_use, graph);
466 pipeline_pm_power(sink, -source_use, graph);
467 return 0;
468 }
469
470 if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
471 (flags & MEDIA_LNK_FL_ENABLED)) {
472
473 ret = pipeline_pm_power(source, sink_use, graph);
474 if (ret < 0)
475 return ret;
476
477 ret = pipeline_pm_power(sink, source_use, graph);
478 if (ret < 0)
479 pipeline_pm_power(source, -sink_use, graph);
480 }
481
482 return ret;
483 }
484 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);