2 * Media Controller ancillary functions
4 * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@kernel.org>
5 * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
6 * Copyright (C) 2006-2010 Nokia Corporation
7 * Copyright (c) 2016 Intel Corporation.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <linux/usb.h>
23 #include <media/media-device.h>
24 #include <media/media-entity.h>
25 #include <media/v4l2-fh.h>
26 #include <media/v4l2-mc.h>
27 #include <media/v4l2-subdev.h>
28 #include <media/videobuf2-core.h>
30 int v4l2_mc_create_media_graph(struct media_device
*mdev
)
33 struct media_entity
*entity
;
34 struct media_entity
*if_vid
= NULL
, *if_aud
= NULL
;
35 struct media_entity
*tuner
= NULL
, *decoder
= NULL
;
36 struct media_entity
*io_v4l
= NULL
, *io_vbi
= NULL
, *io_swradio
= NULL
;
37 bool is_webcam
= false;
44 media_device_for_each_entity(entity
, mdev
) {
45 switch (entity
->function
) {
46 case MEDIA_ENT_F_IF_VID_DECODER
:
49 case MEDIA_ENT_F_IF_AUD_DECODER
:
52 case MEDIA_ENT_F_TUNER
:
55 case MEDIA_ENT_F_ATV_DECODER
:
58 case MEDIA_ENT_F_IO_V4L
:
61 case MEDIA_ENT_F_IO_VBI
:
64 case MEDIA_ENT_F_IO_SWRADIO
:
67 case MEDIA_ENT_F_CAM_SENSOR
:
73 /* It should have at least one I/O entity */
74 if (!io_v4l
&& !io_vbi
&& !io_swradio
)
78 * Here, webcams are modelled on a very simple way: the sensor is
79 * connected directly to the I/O entity. All dirty details, like
80 * scaler and crop HW are hidden. While such mapping is not enough
81 * for mc-centric hardware, it is enough for v4l2 interface centric
82 * PC-consumer's hardware.
88 media_device_for_each_entity(entity
, mdev
) {
89 if (entity
->function
!= MEDIA_ENT_F_CAM_SENSOR
)
91 ret
= media_create_pad_link(entity
, 0,
93 MEDIA_LNK_FL_ENABLED
);
101 /* The device isn't a webcam. So, it should have a decoder */
105 /* Link the tuner and IF video output pads */
108 ret
= media_create_pad_link(tuner
, TUNER_PAD_OUTPUT
,
110 IF_VID_DEC_PAD_IF_INPUT
,
111 MEDIA_LNK_FL_ENABLED
);
114 ret
= media_create_pad_link(if_vid
, IF_VID_DEC_PAD_OUT
,
115 decoder
, DEMOD_PAD_IF_INPUT
,
116 MEDIA_LNK_FL_ENABLED
);
120 ret
= media_create_pad_link(tuner
, TUNER_PAD_OUTPUT
,
121 decoder
, DEMOD_PAD_IF_INPUT
,
122 MEDIA_LNK_FL_ENABLED
);
128 ret
= media_create_pad_link(tuner
, TUNER_PAD_AUD_OUT
,
130 IF_AUD_DEC_PAD_IF_INPUT
,
131 MEDIA_LNK_FL_ENABLED
);
140 /* Create demod to V4L, VBI and SDR radio links */
142 ret
= media_create_pad_link(decoder
, DEMOD_PAD_VID_OUT
,
144 MEDIA_LNK_FL_ENABLED
);
150 ret
= media_create_pad_link(decoder
, DEMOD_PAD_VID_OUT
,
152 MEDIA_LNK_FL_ENABLED
);
158 ret
= media_create_pad_link(decoder
, DEMOD_PAD_VBI_OUT
,
160 MEDIA_LNK_FL_ENABLED
);
165 /* Create links for the media connectors */
166 flags
= MEDIA_LNK_FL_ENABLED
;
167 media_device_for_each_entity(entity
, mdev
) {
168 switch (entity
->function
) {
169 case MEDIA_ENT_F_CONN_RF
:
173 ret
= media_create_pad_link(entity
, 0, tuner
,
177 case MEDIA_ENT_F_CONN_SVIDEO
:
178 case MEDIA_ENT_F_CONN_COMPOSITE
:
179 ret
= media_create_pad_link(entity
, 0, decoder
,
194 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph
);
196 int v4l_enable_media_source(struct video_device
*vdev
)
198 struct media_device
*mdev
= vdev
->entity
.graph_obj
.mdev
;
204 mutex_lock(&mdev
->graph_mutex
);
205 if (!mdev
->enable_source
)
207 err
= mdev
->enable_source(&vdev
->entity
, &vdev
->pipe
);
211 mutex_unlock(&mdev
->graph_mutex
);
214 EXPORT_SYMBOL_GPL(v4l_enable_media_source
);
216 void v4l_disable_media_source(struct video_device
*vdev
)
218 struct media_device
*mdev
= vdev
->entity
.graph_obj
.mdev
;
221 mutex_lock(&mdev
->graph_mutex
);
222 if (mdev
->disable_source
)
223 mdev
->disable_source(&vdev
->entity
);
224 mutex_unlock(&mdev
->graph_mutex
);
227 EXPORT_SYMBOL_GPL(v4l_disable_media_source
);
229 int v4l_vb2q_enable_media_source(struct vb2_queue
*q
)
231 struct v4l2_fh
*fh
= q
->owner
;
234 return v4l_enable_media_source(fh
->vdev
);
237 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source
);
239 /* -----------------------------------------------------------------------------
240 * Pipeline power management
242 * Entities must be powered up when part of a pipeline that contains at least
243 * one open video device node.
245 * To achieve this use the entity use_count field to track the number of users.
246 * For entities corresponding to video device nodes the use_count field stores
247 * the users count of the node. For entities corresponding to subdevs the
248 * use_count field stores the total number of users of all video device nodes
251 * The v4l2_pipeline_pm_use() function must be called in the open() and
252 * close() handlers of video device nodes. It increments or decrements the use
253 * count of all subdev entities in the pipeline.
255 * To react to link management on powered pipelines, the link setup notification
256 * callback updates the use count of all entities in the source and sink sides
261 * pipeline_pm_use_count - Count the number of users of a pipeline
262 * @entity: The entity
264 * Return the total number of users of all video device nodes in the pipeline.
266 static int pipeline_pm_use_count(struct media_entity
*entity
,
267 struct media_graph
*graph
)
271 media_graph_walk_start(graph
, entity
);
273 while ((entity
= media_graph_walk_next(graph
))) {
274 if (is_media_entity_v4l2_video_device(entity
))
275 use
+= entity
->use_count
;
282 * pipeline_pm_power_one - Apply power change to an entity
283 * @entity: The entity
284 * @change: Use count change
286 * Change the entity use count by @change. If the entity is a subdev update its
287 * power state by calling the core::s_power operation when the use count goes
288 * from 0 to != 0 or from != 0 to 0.
290 * Return 0 on success or a negative error code on failure.
292 static int pipeline_pm_power_one(struct media_entity
*entity
, int change
)
294 struct v4l2_subdev
*subdev
;
297 subdev
= is_media_entity_v4l2_subdev(entity
)
298 ? media_entity_to_v4l2_subdev(entity
) : NULL
;
300 if (entity
->use_count
== 0 && change
> 0 && subdev
!= NULL
) {
301 ret
= v4l2_subdev_call(subdev
, core
, s_power
, 1);
302 if (ret
< 0 && ret
!= -ENOIOCTLCMD
)
306 entity
->use_count
+= change
;
307 WARN_ON(entity
->use_count
< 0);
309 if (entity
->use_count
== 0 && change
< 0 && subdev
!= NULL
)
310 v4l2_subdev_call(subdev
, core
, s_power
, 0);
316 * pipeline_pm_power - Apply power change to all entities in a pipeline
317 * @entity: The entity
318 * @change: Use count change
320 * Walk the pipeline to update the use count and the power state of all non-node
323 * Return 0 on success or a negative error code on failure.
325 static int pipeline_pm_power(struct media_entity
*entity
, int change
,
326 struct media_graph
*graph
)
328 struct media_entity
*first
= entity
;
334 media_graph_walk_start(graph
, entity
);
336 while (!ret
&& (entity
= media_graph_walk_next(graph
)))
337 if (is_media_entity_v4l2_subdev(entity
))
338 ret
= pipeline_pm_power_one(entity
, change
);
343 media_graph_walk_start(graph
, first
);
345 while ((first
= media_graph_walk_next(graph
))
347 if (is_media_entity_v4l2_subdev(first
))
348 pipeline_pm_power_one(first
, -change
);
353 int v4l2_pipeline_pm_use(struct media_entity
*entity
, int use
)
355 struct media_device
*mdev
= entity
->graph_obj
.mdev
;
356 int change
= use
? 1 : -1;
359 mutex_lock(&mdev
->graph_mutex
);
361 /* Apply use count to node. */
362 entity
->use_count
+= change
;
363 WARN_ON(entity
->use_count
< 0);
365 /* Apply power change to connected non-nodes. */
366 ret
= pipeline_pm_power(entity
, change
, &mdev
->pm_count_walk
);
368 entity
->use_count
-= change
;
370 mutex_unlock(&mdev
->graph_mutex
);
374 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use
);
376 int v4l2_pipeline_link_notify(struct media_link
*link
, u32 flags
,
377 unsigned int notification
)
379 struct media_graph
*graph
= &link
->graph_obj
.mdev
->pm_count_walk
;
380 struct media_entity
*source
= link
->source
->entity
;
381 struct media_entity
*sink
= link
->sink
->entity
;
386 source_use
= pipeline_pm_use_count(source
, graph
);
387 sink_use
= pipeline_pm_use_count(sink
, graph
);
389 if (notification
== MEDIA_DEV_NOTIFY_POST_LINK_CH
&&
390 !(flags
& MEDIA_LNK_FL_ENABLED
)) {
391 /* Powering off entities is assumed to never fail. */
392 pipeline_pm_power(source
, -sink_use
, graph
);
393 pipeline_pm_power(sink
, -source_use
, graph
);
397 if (notification
== MEDIA_DEV_NOTIFY_PRE_LINK_CH
&&
398 (flags
& MEDIA_LNK_FL_ENABLED
)) {
400 ret
= pipeline_pm_power(source
, sink_use
, graph
);
404 ret
= pipeline_pm_power(sink
, source_use
, graph
);
406 pipeline_pm_power(source
, -sink_use
, graph
);
411 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify
);