1 /* 2 * Media Controller ancillary functions 3 * 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. 8 * 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. 13 * 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. 18 */ 19 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> 29 30 int v4l2_mc_create_media_graph(struct media_device *mdev) 31 32 { 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; 40 41 if (!mdev) 42 return 0; 43 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; 70 } 71 } 72 73 /* It should have at least one I/O entity */ 74 if (!io_v4l && !io_vbi && !io_swradio) 75 return -EINVAL; 76 77 /* 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. 83 */ 84 if (is_webcam) { 85 if (!io_v4l) 86 return -EINVAL; 87 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; 96 } 97 if (!decoder) 98 return 0; 99 } 100 101 /* The device isn't a webcam. So, it should have a decoder */ 102 if (!decoder) 103 return -EINVAL; 104 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; 125 } 126 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; 136 } 137 138 } 139 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; 147 } 148 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; 155 } 156 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; 163 } 164 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; 172 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; 185 } 186 if (ret) 187 return ret; 188 189 flags = 0; 190 } 191 192 return 0; 193 } 194 EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph); 195 196 int v4l_enable_media_source(struct video_device *vdev) 197 { 198 struct media_device *mdev = vdev->entity.graph_obj.mdev; 199 int ret = 0, err; 200 201 if (!mdev) 202 return 0; 203 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; 213 } 214 EXPORT_SYMBOL_GPL(v4l_enable_media_source); 215 216 void v4l_disable_media_source(struct video_device *vdev) 217 { 218 struct media_device *mdev = vdev->entity.graph_obj.mdev; 219 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); 225 } 226 } 227 EXPORT_SYMBOL_GPL(v4l_disable_media_source); 228 229 int v4l_vb2q_enable_media_source(struct vb2_queue *q) 230 { 231 struct v4l2_fh *fh = q->owner; 232 233 if (fh && fh->vdev) 234 return v4l_enable_media_source(fh->vdev); 235 return 0; 236 } 237 EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source); 238 239 /* ----------------------------------------------------------------------------- 240 * Pipeline power management 241 * 242 * Entities must be powered up when part of a pipeline that contains at least 243 * one open video device node. 244 * 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. 250 * 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. 254 * 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. 258 */ 259 260 /* 261 * pipeline_pm_use_count - Count the number of users of a pipeline 262 * @entity: The entity 263 * 264 * Return the total number of users of all video device nodes in the pipeline. 265 */ 266 static int pipeline_pm_use_count(struct media_entity *entity, 267 struct media_graph *graph) 268 { 269 int use = 0; 270 271 media_graph_walk_start(graph, entity); 272 273 while ((entity = media_graph_walk_next(graph))) { 274 if (is_media_entity_v4l2_video_device(entity)) 275 use += entity->use_count; 276 } 277 278 return use; 279 } 280 281 /* 282 * pipeline_pm_power_one - Apply power change to an entity 283 * @entity: The entity 284 * @change: Use count change 285 * 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. 289 * 290 * Return 0 on success or a negative error code on failure. 291 */ 292 static int pipeline_pm_power_one(struct media_entity *entity, int change) 293 { 294 struct v4l2_subdev *subdev; 295 int ret; 296 297 subdev = is_media_entity_v4l2_subdev(entity) 298 ? media_entity_to_v4l2_subdev(entity) : NULL; 299 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; 304 } 305 306 entity->use_count += change; 307 WARN_ON(entity->use_count < 0); 308 309 if (entity->use_count == 0 && change < 0 && subdev != NULL) 310 v4l2_subdev_call(subdev, core, s_power, 0); 311 312 return 0; 313 } 314 315 /* 316 * pipeline_pm_power - Apply power change to all entities in a pipeline 317 * @entity: The entity 318 * @change: Use count change 319 * 320 * Walk the pipeline to update the use count and the power state of all non-node 321 * entities. 322 * 323 * Return 0 on success or a negative error code on failure. 324 */ 325 static int pipeline_pm_power(struct media_entity *entity, int change, 326 struct media_graph *graph) 327 { 328 struct media_entity *first = entity; 329 int ret = 0; 330 331 if (!change) 332 return 0; 333 334 media_graph_walk_start(graph, entity); 335 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); 339 340 if (!ret) 341 return ret; 342 343 media_graph_walk_start(graph, first); 344 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); 349 350 return ret; 351 } 352 353 int v4l2_pipeline_pm_use(struct media_entity *entity, int use) 354 { 355 struct media_device *mdev = entity->graph_obj.mdev; 356 int change = use ? 1 : -1; 357 int ret; 358 359 mutex_lock(&mdev->graph_mutex); 360 361 /* Apply use count to node. */ 362 entity->use_count += change; 363 WARN_ON(entity->use_count < 0); 364 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; 369 370 mutex_unlock(&mdev->graph_mutex); 371 372 return ret; 373 } 374 EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use); 375 376 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags, 377 unsigned int notification) 378 { 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; 385 386 source_use = pipeline_pm_use_count(source, graph); 387 sink_use = pipeline_pm_use_count(sink, graph); 388 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; 395 } 396 397 if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && 398 (flags & MEDIA_LNK_FL_ENABLED)) { 399 400 ret = pipeline_pm_power(source, sink_use, graph); 401 if (ret < 0) 402 return ret; 403 404 ret = pipeline_pm_power(sink, source_use, graph); 405 if (ret < 0) 406 pipeline_pm_power(source, -sink_use, graph); 407 } 408 409 return ret; 410 } 411 EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify); 412