Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cris-mirror.git] / drivers / media / v4l2-core / v4l2-mc.c
blob1d550afeda13f97e4f31325954e262c604bba687
1 /*
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;
38 u32 flags;
39 int ret;
41 if (!mdev)
42 return 0;
44 media_device_for_each_entity(entity, mdev) {
45 switch (entity->function) {
46 case MEDIA_ENT_F_IF_VID_DECODER:
47 if_vid = entity;
48 break;
49 case MEDIA_ENT_F_IF_AUD_DECODER:
50 if_aud = entity;
51 break;
52 case MEDIA_ENT_F_TUNER:
53 tuner = entity;
54 break;
55 case MEDIA_ENT_F_ATV_DECODER:
56 decoder = entity;
57 break;
58 case MEDIA_ENT_F_IO_V4L:
59 io_v4l = entity;
60 break;
61 case MEDIA_ENT_F_IO_VBI:
62 io_vbi = entity;
63 break;
64 case MEDIA_ENT_F_IO_SWRADIO:
65 io_swradio = entity;
66 break;
67 case MEDIA_ENT_F_CAM_SENSOR:
68 is_webcam = true;
69 break;
73 /* It should have at least one I/O entity */
74 if (!io_v4l && !io_vbi && !io_swradio)
75 return -EINVAL;
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.
84 if (is_webcam) {
85 if (!io_v4l)
86 return -EINVAL;
88 media_device_for_each_entity(entity, mdev) {
89 if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
90 continue;
91 ret = media_create_pad_link(entity, 0,
92 io_v4l, 0,
93 MEDIA_LNK_FL_ENABLED);
94 if (ret)
95 return ret;
97 if (!decoder)
98 return 0;
101 /* The device isn't a webcam. So, it should have a decoder */
102 if (!decoder)
103 return -EINVAL;
105 /* Link the tuner and IF video output pads */
106 if (tuner) {
107 if (if_vid) {
108 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
109 if_vid,
110 IF_VID_DEC_PAD_IF_INPUT,
111 MEDIA_LNK_FL_ENABLED);
112 if (ret)
113 return ret;
114 ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT,
115 decoder, DEMOD_PAD_IF_INPUT,
116 MEDIA_LNK_FL_ENABLED);
117 if (ret)
118 return ret;
119 } else {
120 ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
121 decoder, DEMOD_PAD_IF_INPUT,
122 MEDIA_LNK_FL_ENABLED);
123 if (ret)
124 return ret;
127 if (if_aud) {
128 ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT,
129 if_aud,
130 IF_AUD_DEC_PAD_IF_INPUT,
131 MEDIA_LNK_FL_ENABLED);
132 if (ret)
133 return ret;
134 } else {
135 if_aud = tuner;
140 /* Create demod to V4L, VBI and SDR radio links */
141 if (io_v4l) {
142 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
143 io_v4l, 0,
144 MEDIA_LNK_FL_ENABLED);
145 if (ret)
146 return ret;
149 if (io_swradio) {
150 ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
151 io_swradio, 0,
152 MEDIA_LNK_FL_ENABLED);
153 if (ret)
154 return ret;
157 if (io_vbi) {
158 ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT,
159 io_vbi, 0,
160 MEDIA_LNK_FL_ENABLED);
161 if (ret)
162 return ret;
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:
170 if (!tuner)
171 continue;
173 ret = media_create_pad_link(entity, 0, tuner,
174 TUNER_PAD_RF_INPUT,
175 flags);
176 break;
177 case MEDIA_ENT_F_CONN_SVIDEO:
178 case MEDIA_ENT_F_CONN_COMPOSITE:
179 ret = media_create_pad_link(entity, 0, decoder,
180 DEMOD_PAD_IF_INPUT,
181 flags);
182 break;
183 default:
184 continue;
186 if (ret)
187 return ret;
189 flags = 0;
192 return 0;
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;
199 int ret = 0, err;
201 if (!mdev)
202 return 0;
204 mutex_lock(&mdev->graph_mutex);
205 if (!mdev->enable_source)
206 goto end;
207 err = mdev->enable_source(&vdev->entity, &vdev->pipe);
208 if (err)
209 ret = -EBUSY;
210 end:
211 mutex_unlock(&mdev->graph_mutex);
212 return ret;
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;
220 if (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;
233 if (fh && fh->vdev)
234 return v4l_enable_media_source(fh->vdev);
235 return 0;
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
249 * in the pipeline.
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
257 * of the link.
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)
269 int use = 0;
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;
278 return use;
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;
295 int ret;
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)
303 return ret;
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);
312 return 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
321 * entities.
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;
329 int ret = 0;
331 if (!change)
332 return 0;
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);
340 if (!ret)
341 return ret;
343 media_graph_walk_start(graph, first);
345 while ((first = media_graph_walk_next(graph))
346 && first != entity)
347 if (is_media_entity_v4l2_subdev(first))
348 pipeline_pm_power_one(first, -change);
350 return ret;
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;
357 int ret;
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);
367 if (ret < 0)
368 entity->use_count -= change;
370 mutex_unlock(&mdev->graph_mutex);
372 return ret;
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;
382 int source_use;
383 int sink_use;
384 int ret = 0;
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);
394 return 0;
397 if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
398 (flags & MEDIA_LNK_FL_ENABLED)) {
400 ret = pipeline_pm_power(source, sink_use, graph);
401 if (ret < 0)
402 return ret;
404 ret = pipeline_pm_power(sink, source_use, graph);
405 if (ret < 0)
406 pipeline_pm_power(source, -sink_use, graph);
409 return ret;
411 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);