Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] media: Links setup

Create the following ioctl and implement it at the media device level to
setup links.

- MEDIA_IOC_SETUP_LINK: Modify the properties of a given link

The only property that can currently be modified is the ENABLED link
flag to enable/disable a link. Links marked with the IMMUTABLE link flag
can not be enabled or disabled.

Enabling or disabling a link has effects on entities' use count. Those
changes are automatically propagated through the graph.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
97548ed4 1651333b

+356
+2
Documentation/DocBook/media-entities.tmpl
··· 94 94 <!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>"> 95 95 <!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>"> 96 96 <!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>"> 97 + <!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>"> 97 98 98 99 <!-- Types --> 99 100 <!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>"> ··· 349 348 <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml"> 350 349 <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml"> 351 350 <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml"> 351 + <!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml"> 352 352 353 353 <!-- Function Reference --> 354 354 <!ENTITY close SYSTEM "v4l/func-close.xml">
+1
Documentation/DocBook/v4l/media-controller.xml
··· 85 85 &sub-media-ioc-device-info; 86 86 &sub-media-ioc-enum-entities; 87 87 &sub-media-ioc-enum-links; 88 + &sub-media-ioc-setup-link; 88 89 </appendix>
+90
Documentation/DocBook/v4l/media-ioc-setup-link.xml
··· 1 + <refentry id="media-ioc-setup-link"> 2 + <refmeta> 3 + <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle> 4 + &manvol; 5 + </refmeta> 6 + 7 + <refnamediv> 8 + <refname>MEDIA_IOC_SETUP_LINK</refname> 9 + <refpurpose>Modify the properties of a link</refpurpose> 10 + </refnamediv> 11 + 12 + <refsynopsisdiv> 13 + <funcsynopsis> 14 + <funcprototype> 15 + <funcdef>int <function>ioctl</function></funcdef> 16 + <paramdef>int <parameter>fd</parameter></paramdef> 17 + <paramdef>int <parameter>request</parameter></paramdef> 18 + <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef> 19 + </funcprototype> 20 + </funcsynopsis> 21 + </refsynopsisdiv> 22 + 23 + <refsect1> 24 + <title>Arguments</title> 25 + 26 + <variablelist> 27 + <varlistentry> 28 + <term><parameter>fd</parameter></term> 29 + <listitem> 30 + <para>File descriptor returned by 31 + <link linkend='media-func-open'><function>open()</function></link>.</para> 32 + </listitem> 33 + </varlistentry> 34 + <varlistentry> 35 + <term><parameter>request</parameter></term> 36 + <listitem> 37 + <para>MEDIA_IOC_ENUM_LINKS</para> 38 + </listitem> 39 + </varlistentry> 40 + <varlistentry> 41 + <term><parameter>argp</parameter></term> 42 + <listitem> 43 + <para></para> 44 + </listitem> 45 + </varlistentry> 46 + </variablelist> 47 + </refsect1> 48 + 49 + <refsect1> 50 + <title>Description</title> 51 + 52 + <para>To change link properties applications fill a &media-link-desc; with 53 + link identification information (source and sink pad) and the new requested 54 + link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to 55 + that structure.</para> 56 + <para>The only configurable property is the <constant>ENABLED</constant> 57 + link flag to enable/disable a link. Links marked with the 58 + <constant>IMMUTABLE</constant> link flag can not be enabled or disabled. 59 + </para> 60 + <para>Link configuration has no side effect on other links. If an enabled 61 + link at the sink pad prevents the link from being enabled, the driver 62 + returns with an &EBUSY;.</para> 63 + <para>If the specified link can't be found the driver returns with an 64 + &EINVAL;.</para> 65 + </refsect1> 66 + 67 + <refsect1> 68 + &return-value; 69 + 70 + <variablelist> 71 + <varlistentry> 72 + <term><errorcode>EBUSY</errorcode></term> 73 + <listitem> 74 + <para>The link properties can't be changed because the link is 75 + currently busy. This can be caused, for instance, by an active media 76 + stream (audio or video) on the link. The ioctl shouldn't be retried if 77 + no other action is performed before to fix the problem.</para> 78 + </listitem> 79 + </varlistentry> 80 + <varlistentry> 81 + <term><errorcode>EINVAL</errorcode></term> 82 + <listitem> 83 + <para>The &media-link-desc; references a non-existing link, or the 84 + link is immutable and an attempt to modify its configuration was made. 85 + </para> 86 + </listitem> 87 + </varlistentry> 88 + </variablelist> 89 + </refsect1> 90 + </refentry>
+42
Documentation/media-framework.txt
··· 259 259 Graph traversal can be interrupted at any moment. No cleanup function call is 260 260 required and the graph structure can be freed normally. 261 261 262 + Helper functions can be used to find a link between two given pads, or a pad 263 + connected to another pad through an enabled link 264 + 265 + media_entity_find_link(struct media_pad *source, 266 + struct media_pad *sink); 267 + 268 + media_entity_remote_source(struct media_pad *pad); 269 + 270 + Refer to the kerneldoc documentation for more information. 271 + 262 272 263 273 Use count and power handling 264 274 ---------------------------- ··· 281 271 The use_count field is owned by media drivers and must not be touched by entity 282 272 drivers. Access to the field must be protected by the media device graph_mutex 283 273 lock. 274 + 275 + 276 + Links setup 277 + ----------- 278 + 279 + Link properties can be modified at runtime by calling 280 + 281 + media_entity_setup_link(struct media_link *link, u32 flags); 282 + 283 + The flags argument contains the requested new link flags. 284 + 285 + The only configurable property is the ENABLED link flag to enable/disable a 286 + link. Links marked with the IMMUTABLE link flag can not be enabled or disabled. 287 + 288 + When a link is enabled or disabled, the media framework calls the 289 + link_setup operation for the two entities at the source and sink of the link, 290 + in that order. If the second link_setup call fails, another link_setup call is 291 + made on the first entity to restore the original link flags. 292 + 293 + Media device drivers can be notified of link setup operations by setting the 294 + media_device::link_notify pointer to a callback function. If provided, the 295 + notification callback will be called before enabling and after disabling 296 + links. 297 + 298 + Entity drivers must implement the link_setup operation if any of their links 299 + is non-immutable. The operation must either configure the hardware or store 300 + the configuration information to be applied later. 301 + 302 + Link configuration must not have any side effect on other links. If an enabled 303 + link at a sink pad prevents another link at the same pad from being disabled, 304 + the link_setup operation must return -EBUSY and can't implicitly disable the 305 + first enabled link.
+45
drivers/media/media-device.c
··· 172 172 return 0; 173 173 } 174 174 175 + static long media_device_setup_link(struct media_device *mdev, 176 + struct media_link_desc __user *_ulink) 177 + { 178 + struct media_link *link = NULL; 179 + struct media_link_desc ulink; 180 + struct media_entity *source; 181 + struct media_entity *sink; 182 + int ret; 183 + 184 + if (copy_from_user(&ulink, _ulink, sizeof(ulink))) 185 + return -EFAULT; 186 + 187 + /* Find the source and sink entities and link. 188 + */ 189 + source = find_entity(mdev, ulink.source.entity); 190 + sink = find_entity(mdev, ulink.sink.entity); 191 + 192 + if (source == NULL || sink == NULL) 193 + return -EINVAL; 194 + 195 + if (ulink.source.index >= source->num_pads || 196 + ulink.sink.index >= sink->num_pads) 197 + return -EINVAL; 198 + 199 + link = media_entity_find_link(&source->pads[ulink.source.index], 200 + &sink->pads[ulink.sink.index]); 201 + if (link == NULL) 202 + return -EINVAL; 203 + 204 + /* Setup the link on both entities. */ 205 + ret = __media_entity_setup_link(link, ulink.flags); 206 + 207 + if (copy_to_user(_ulink, &ulink, sizeof(ulink))) 208 + return -EFAULT; 209 + 210 + return ret; 211 + } 212 + 175 213 static long media_device_ioctl(struct file *filp, unsigned int cmd, 176 214 unsigned long arg) 177 215 { ··· 232 194 mutex_lock(&dev->graph_mutex); 233 195 ret = media_device_enum_links(dev, 234 196 (struct media_links_enum __user *)arg); 197 + mutex_unlock(&dev->graph_mutex); 198 + break; 199 + 200 + case MEDIA_IOC_SETUP_LINK: 201 + mutex_lock(&dev->graph_mutex); 202 + ret = media_device_setup_link(dev, 203 + (struct media_link_desc __user *)arg); 235 204 mutex_unlock(&dev->graph_mutex); 236 205 break; 237 206
+155
drivers/media/media-entity.c
··· 306 306 return 0; 307 307 } 308 308 EXPORT_SYMBOL_GPL(media_entity_create_link); 309 + 310 + static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) 311 + { 312 + const u32 mask = MEDIA_LNK_FL_ENABLED; 313 + int ret; 314 + 315 + /* Notify both entities. */ 316 + ret = media_entity_call(link->source->entity, link_setup, 317 + link->source, link->sink, flags); 318 + if (ret < 0 && ret != -ENOIOCTLCMD) 319 + return ret; 320 + 321 + ret = media_entity_call(link->sink->entity, link_setup, 322 + link->sink, link->source, flags); 323 + if (ret < 0 && ret != -ENOIOCTLCMD) { 324 + media_entity_call(link->source->entity, link_setup, 325 + link->source, link->sink, link->flags); 326 + return ret; 327 + } 328 + 329 + link->flags = (link->flags & ~mask) | (flags & mask); 330 + link->reverse->flags = link->flags; 331 + 332 + return 0; 333 + } 334 + 335 + /** 336 + * __media_entity_setup_link - Configure a media link 337 + * @link: The link being configured 338 + * @flags: Link configuration flags 339 + * 340 + * The bulk of link setup is handled by the two entities connected through the 341 + * link. This function notifies both entities of the link configuration change. 342 + * 343 + * If the link is immutable or if the current and new configuration are 344 + * identical, return immediately. 345 + * 346 + * The user is expected to hold link->source->parent->mutex. If not, 347 + * media_entity_setup_link() should be used instead. 348 + */ 349 + int __media_entity_setup_link(struct media_link *link, u32 flags) 350 + { 351 + struct media_device *mdev; 352 + struct media_entity *source, *sink; 353 + int ret = -EBUSY; 354 + 355 + if (link == NULL) 356 + return -EINVAL; 357 + 358 + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) 359 + return link->flags == flags ? 0 : -EINVAL; 360 + 361 + if (link->flags == flags) 362 + return 0; 363 + 364 + source = link->source->entity; 365 + sink = link->sink->entity; 366 + 367 + mdev = source->parent; 368 + 369 + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { 370 + ret = mdev->link_notify(link->source, link->sink, 371 + MEDIA_LNK_FL_ENABLED); 372 + if (ret < 0) 373 + return ret; 374 + } 375 + 376 + ret = __media_entity_setup_link_notify(link, flags); 377 + if (ret < 0) 378 + goto err; 379 + 380 + if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) 381 + mdev->link_notify(link->source, link->sink, 0); 382 + 383 + return 0; 384 + 385 + err: 386 + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) 387 + mdev->link_notify(link->source, link->sink, 0); 388 + 389 + return ret; 390 + } 391 + 392 + int media_entity_setup_link(struct media_link *link, u32 flags) 393 + { 394 + int ret; 395 + 396 + mutex_lock(&link->source->entity->parent->graph_mutex); 397 + ret = __media_entity_setup_link(link, flags); 398 + mutex_unlock(&link->source->entity->parent->graph_mutex); 399 + 400 + return ret; 401 + } 402 + EXPORT_SYMBOL_GPL(media_entity_setup_link); 403 + 404 + /** 405 + * media_entity_find_link - Find a link between two pads 406 + * @source: Source pad 407 + * @sink: Sink pad 408 + * 409 + * Return a pointer to the link between the two entities. If no such link 410 + * exists, return NULL. 411 + */ 412 + struct media_link * 413 + media_entity_find_link(struct media_pad *source, struct media_pad *sink) 414 + { 415 + struct media_link *link; 416 + unsigned int i; 417 + 418 + for (i = 0; i < source->entity->num_links; ++i) { 419 + link = &source->entity->links[i]; 420 + 421 + if (link->source->entity == source->entity && 422 + link->source->index == source->index && 423 + link->sink->entity == sink->entity && 424 + link->sink->index == sink->index) 425 + return link; 426 + } 427 + 428 + return NULL; 429 + } 430 + EXPORT_SYMBOL_GPL(media_entity_find_link); 431 + 432 + /** 433 + * media_entity_remote_source - Find the source pad at the remote end of a link 434 + * @pad: Sink pad at the local end of the link 435 + * 436 + * Search for a remote source pad connected to the given sink pad by iterating 437 + * over all links originating or terminating at that pad until an enabled link 438 + * is found. 439 + * 440 + * Return a pointer to the pad at the remote end of the first found enabled 441 + * link, or NULL if no enabled link has been found. 442 + */ 443 + struct media_pad *media_entity_remote_source(struct media_pad *pad) 444 + { 445 + unsigned int i; 446 + 447 + for (i = 0; i < pad->entity->num_links; i++) { 448 + struct media_link *link = &pad->entity->links[i]; 449 + 450 + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) 451 + continue; 452 + 453 + if (link->source == pad) 454 + return link->sink; 455 + 456 + if (link->sink == pad) 457 + return link->source; 458 + } 459 + 460 + return NULL; 461 + 462 + } 463 + EXPORT_SYMBOL_GPL(media_entity_remote_source);
+1
include/linux/media.h
··· 126 126 #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info) 127 127 #define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc) 128 128 #define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum) 129 + #define MEDIA_IOC_SETUP_LINK _IOWR('M', 4, struct media_link_desc) 129 130 130 131 #endif /* __LINUX_MEDIA_H */
+3
include/media/media-device.h
··· 73 73 spinlock_t lock; 74 74 /* Serializes graph operations. */ 75 75 struct mutex graph_mutex; 76 + 77 + int (*link_notify)(struct media_pad *source, 78 + struct media_pad *sink, u32 flags); 76 79 }; 77 80 78 81 /* media_devnode to media_device */
+17
include/media/media-entity.h
··· 39 39 unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ 40 40 }; 41 41 42 + struct media_entity_operations { 43 + int (*link_setup)(struct media_entity *entity, 44 + const struct media_pad *local, 45 + const struct media_pad *remote, u32 flags); 46 + }; 47 + 42 48 struct media_entity { 43 49 struct list_head list; 44 50 struct media_device *parent; /* Media device this entity belongs to*/ ··· 64 58 65 59 struct media_pad *pads; /* Pads array (num_pads elements) */ 66 60 struct media_link *links; /* Links array (max_links elements)*/ 61 + 62 + const struct media_entity_operations *ops; /* Entity operations */ 67 63 68 64 /* Reference counts must never be negative, but are signed integers on 69 65 * purpose: a simple WARN_ON(<0) check can be used to detect reference ··· 120 112 void media_entity_cleanup(struct media_entity *entity); 121 113 int media_entity_create_link(struct media_entity *source, u16 source_pad, 122 114 struct media_entity *sink, u16 sink_pad, u32 flags); 115 + int __media_entity_setup_link(struct media_link *link, u32 flags); 116 + int media_entity_setup_link(struct media_link *link, u32 flags); 117 + struct media_link *media_entity_find_link(struct media_pad *source, 118 + struct media_pad *sink); 119 + struct media_pad *media_entity_remote_source(struct media_pad *pad); 123 120 124 121 struct media_entity *media_entity_get(struct media_entity *entity); 125 122 void media_entity_put(struct media_entity *entity); ··· 133 120 struct media_entity *entity); 134 121 struct media_entity * 135 122 media_entity_graph_walk_next(struct media_entity_graph *graph); 123 + 124 + #define media_entity_call(entity, operation, args...) \ 125 + (((entity)->ops && (entity)->ops->operation) ? \ 126 + (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD) 136 127 137 128 #endif