v4l2-mc.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Media Controller ancillary functions
  4. *
  5. * Copyright (c) 2016 Mauro Carvalho Chehab <mchehab@kernel.org>
  6. * Copyright (C) 2016 Shuah Khan <shuahkh@osg.samsung.com>
  7. * Copyright (C) 2006-2010 Nokia Corporation
  8. * Copyright (c) 2016 Intel Corporation.
  9. */
  10. #include <linux/module.h>
  11. #include <linux/pci.h>
  12. #include <linux/usb.h>
  13. #include <media/media-device.h>
  14. #include <media/media-entity.h>
  15. #include <media/v4l2-fh.h>
  16. #include <media/v4l2-mc.h>
  17. #include <media/v4l2-subdev.h>
  18. #include <media/videobuf2-core.h>
  19. int v4l2_mc_create_media_graph(struct media_device *mdev)
  20. {
  21. struct media_entity *entity;
  22. struct media_entity *if_vid = NULL, *if_aud = NULL;
  23. struct media_entity *tuner = NULL, *decoder = NULL;
  24. struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL;
  25. bool is_webcam = false;
  26. u32 flags;
  27. int ret;
  28. if (!mdev)
  29. return 0;
  30. media_device_for_each_entity(entity, mdev) {
  31. switch (entity->function) {
  32. case MEDIA_ENT_F_IF_VID_DECODER:
  33. if_vid = entity;
  34. break;
  35. case MEDIA_ENT_F_IF_AUD_DECODER:
  36. if_aud = entity;
  37. break;
  38. case MEDIA_ENT_F_TUNER:
  39. tuner = entity;
  40. break;
  41. case MEDIA_ENT_F_ATV_DECODER:
  42. decoder = entity;
  43. break;
  44. case MEDIA_ENT_F_IO_V4L:
  45. io_v4l = entity;
  46. break;
  47. case MEDIA_ENT_F_IO_VBI:
  48. io_vbi = entity;
  49. break;
  50. case MEDIA_ENT_F_IO_SWRADIO:
  51. io_swradio = entity;
  52. break;
  53. case MEDIA_ENT_F_CAM_SENSOR:
  54. is_webcam = true;
  55. break;
  56. }
  57. }
  58. /* It should have at least one I/O entity */
  59. if (!io_v4l && !io_vbi && !io_swradio)
  60. return -EINVAL;
  61. /*
  62. * Here, webcams are modelled on a very simple way: the sensor is
  63. * connected directly to the I/O entity. All dirty details, like
  64. * scaler and crop HW are hidden. While such mapping is not enough
  65. * for mc-centric hardware, it is enough for v4l2 interface centric
  66. * PC-consumer's hardware.
  67. */
  68. if (is_webcam) {
  69. if (!io_v4l)
  70. return -EINVAL;
  71. media_device_for_each_entity(entity, mdev) {
  72. if (entity->function != MEDIA_ENT_F_CAM_SENSOR)
  73. continue;
  74. ret = media_create_pad_link(entity, 0,
  75. io_v4l, 0,
  76. MEDIA_LNK_FL_ENABLED);
  77. if (ret)
  78. return ret;
  79. }
  80. if (!decoder)
  81. return 0;
  82. }
  83. /* The device isn't a webcam. So, it should have a decoder */
  84. if (!decoder)
  85. return -EINVAL;
  86. /* Link the tuner and IF video output pads */
  87. if (tuner) {
  88. if (if_vid) {
  89. ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
  90. if_vid,
  91. IF_VID_DEC_PAD_IF_INPUT,
  92. MEDIA_LNK_FL_ENABLED);
  93. if (ret)
  94. return ret;
  95. ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT,
  96. decoder, DEMOD_PAD_IF_INPUT,
  97. MEDIA_LNK_FL_ENABLED);
  98. if (ret)
  99. return ret;
  100. } else {
  101. ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT,
  102. decoder, DEMOD_PAD_IF_INPUT,
  103. MEDIA_LNK_FL_ENABLED);
  104. if (ret)
  105. return ret;
  106. }
  107. if (if_aud) {
  108. ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT,
  109. if_aud,
  110. IF_AUD_DEC_PAD_IF_INPUT,
  111. MEDIA_LNK_FL_ENABLED);
  112. if (ret)
  113. return ret;
  114. } else {
  115. if_aud = tuner;
  116. }
  117. }
  118. /* Create demod to V4L, VBI and SDR radio links */
  119. if (io_v4l) {
  120. ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
  121. io_v4l, 0,
  122. MEDIA_LNK_FL_ENABLED);
  123. if (ret)
  124. return ret;
  125. }
  126. if (io_swradio) {
  127. ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT,
  128. io_swradio, 0,
  129. MEDIA_LNK_FL_ENABLED);
  130. if (ret)
  131. return ret;
  132. }
  133. if (io_vbi) {
  134. ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT,
  135. io_vbi, 0,
  136. MEDIA_LNK_FL_ENABLED);
  137. if (ret)
  138. return ret;
  139. }
  140. /* Create links for the media connectors */
  141. flags = MEDIA_LNK_FL_ENABLED;
  142. media_device_for_each_entity(entity, mdev) {
  143. switch (entity->function) {
  144. case MEDIA_ENT_F_CONN_RF:
  145. if (!tuner)
  146. continue;
  147. ret = media_create_pad_link(entity, 0, tuner,
  148. TUNER_PAD_RF_INPUT,
  149. flags);
  150. break;
  151. case MEDIA_ENT_F_CONN_SVIDEO:
  152. case MEDIA_ENT_F_CONN_COMPOSITE:
  153. ret = media_create_pad_link(entity, 0, decoder,
  154. DEMOD_PAD_IF_INPUT,
  155. flags);
  156. break;
  157. default:
  158. continue;
  159. }
  160. if (ret)
  161. return ret;
  162. flags = 0;
  163. }
  164. return 0;
  165. }
  166. EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
  167. int v4l_enable_media_source(struct video_device *vdev)
  168. {
  169. struct media_device *mdev = vdev->entity.graph_obj.mdev;
  170. int ret = 0, err;
  171. if (!mdev)
  172. return 0;
  173. mutex_lock(&mdev->graph_mutex);
  174. if (!mdev->enable_source)
  175. goto end;
  176. err = mdev->enable_source(&vdev->entity, &vdev->pipe);
  177. if (err)
  178. ret = -EBUSY;
  179. end:
  180. mutex_unlock(&mdev->graph_mutex);
  181. return ret;
  182. }
  183. EXPORT_SYMBOL_GPL(v4l_enable_media_source);
  184. void v4l_disable_media_source(struct video_device *vdev)
  185. {
  186. struct media_device *mdev = vdev->entity.graph_obj.mdev;
  187. if (mdev) {
  188. mutex_lock(&mdev->graph_mutex);
  189. if (mdev->disable_source)
  190. mdev->disable_source(&vdev->entity);
  191. mutex_unlock(&mdev->graph_mutex);
  192. }
  193. }
  194. EXPORT_SYMBOL_GPL(v4l_disable_media_source);
  195. int v4l_vb2q_enable_media_source(struct vb2_queue *q)
  196. {
  197. struct v4l2_fh *fh = q->owner;
  198. if (fh && fh->vdev)
  199. return v4l_enable_media_source(fh->vdev);
  200. return 0;
  201. }
  202. EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
  203. /* -----------------------------------------------------------------------------
  204. * Pipeline power management
  205. *
  206. * Entities must be powered up when part of a pipeline that contains at least
  207. * one open video device node.
  208. *
  209. * To achieve this use the entity use_count field to track the number of users.
  210. * For entities corresponding to video device nodes the use_count field stores
  211. * the users count of the node. For entities corresponding to subdevs the
  212. * use_count field stores the total number of users of all video device nodes
  213. * in the pipeline.
  214. *
  215. * The v4l2_pipeline_pm_use() function must be called in the open() and
  216. * close() handlers of video device nodes. It increments or decrements the use
  217. * count of all subdev entities in the pipeline.
  218. *
  219. * To react to link management on powered pipelines, the link setup notification
  220. * callback updates the use count of all entities in the source and sink sides
  221. * of the link.
  222. */
  223. /*
  224. * pipeline_pm_use_count - Count the number of users of a pipeline
  225. * @entity: The entity
  226. *
  227. * Return the total number of users of all video device nodes in the pipeline.
  228. */
  229. static int pipeline_pm_use_count(struct media_entity *entity,
  230. struct media_graph *graph)
  231. {
  232. int use = 0;
  233. media_graph_walk_start(graph, entity);
  234. while ((entity = media_graph_walk_next(graph))) {
  235. if (is_media_entity_v4l2_video_device(entity))
  236. use += entity->use_count;
  237. }
  238. return use;
  239. }
  240. /*
  241. * pipeline_pm_power_one - Apply power change to an entity
  242. * @entity: The entity
  243. * @change: Use count change
  244. *
  245. * Change the entity use count by @change. If the entity is a subdev update its
  246. * power state by calling the core::s_power operation when the use count goes
  247. * from 0 to != 0 or from != 0 to 0.
  248. *
  249. * Return 0 on success or a negative error code on failure.
  250. */
  251. static int pipeline_pm_power_one(struct media_entity *entity, int change)
  252. {
  253. struct v4l2_subdev *subdev;
  254. int ret;
  255. subdev = is_media_entity_v4l2_subdev(entity)
  256. ? media_entity_to_v4l2_subdev(entity) : NULL;
  257. if (entity->use_count == 0 && change > 0 && subdev != NULL) {
  258. ret = v4l2_subdev_call(subdev, core, s_power, 1);
  259. if (ret < 0 && ret != -ENOIOCTLCMD)
  260. return ret;
  261. }
  262. entity->use_count += change;
  263. WARN_ON(entity->use_count < 0);
  264. if (entity->use_count == 0 && change < 0 && subdev != NULL)
  265. v4l2_subdev_call(subdev, core, s_power, 0);
  266. return 0;
  267. }
  268. /*
  269. * pipeline_pm_power - Apply power change to all entities in a pipeline
  270. * @entity: The entity
  271. * @change: Use count change
  272. *
  273. * Walk the pipeline to update the use count and the power state of all non-node
  274. * entities.
  275. *
  276. * Return 0 on success or a negative error code on failure.
  277. */
  278. static int pipeline_pm_power(struct media_entity *entity, int change,
  279. struct media_graph *graph)
  280. {
  281. struct media_entity *first = entity;
  282. int ret = 0;
  283. if (!change)
  284. return 0;
  285. media_graph_walk_start(graph, entity);
  286. while (!ret && (entity = media_graph_walk_next(graph)))
  287. if (is_media_entity_v4l2_subdev(entity))
  288. ret = pipeline_pm_power_one(entity, change);
  289. if (!ret)
  290. return ret;
  291. media_graph_walk_start(graph, first);
  292. while ((first = media_graph_walk_next(graph))
  293. && first != entity)
  294. if (is_media_entity_v4l2_subdev(first))
  295. pipeline_pm_power_one(first, -change);
  296. return ret;
  297. }
  298. int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
  299. {
  300. struct media_device *mdev = entity->graph_obj.mdev;
  301. int change = use ? 1 : -1;
  302. int ret;
  303. mutex_lock(&mdev->graph_mutex);
  304. /* Apply use count to node. */
  305. entity->use_count += change;
  306. WARN_ON(entity->use_count < 0);
  307. /* Apply power change to connected non-nodes. */
  308. ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
  309. if (ret < 0)
  310. entity->use_count -= change;
  311. mutex_unlock(&mdev->graph_mutex);
  312. return ret;
  313. }
  314. EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use);
  315. int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
  316. unsigned int notification)
  317. {
  318. struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
  319. struct media_entity *source = link->source->entity;
  320. struct media_entity *sink = link->sink->entity;
  321. int source_use;
  322. int sink_use;
  323. int ret = 0;
  324. source_use = pipeline_pm_use_count(source, graph);
  325. sink_use = pipeline_pm_use_count(sink, graph);
  326. if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
  327. !(flags & MEDIA_LNK_FL_ENABLED)) {
  328. /* Powering off entities is assumed to never fail. */
  329. pipeline_pm_power(source, -sink_use, graph);
  330. pipeline_pm_power(sink, -source_use, graph);
  331. return 0;
  332. }
  333. if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
  334. (flags & MEDIA_LNK_FL_ENABLED)) {
  335. ret = pipeline_pm_power(source, sink_use, graph);
  336. if (ret < 0)
  337. return ret;
  338. ret = pipeline_pm_power(sink, source_use, graph);
  339. if (ret < 0)
  340. pipeline_pm_power(source, -sink_use, graph);
  341. }
  342. return ret;
  343. }
  344. EXPORT_SYMBOL_GPL(v4l2_pipeline_link_notify);