Commit 97548ed4c4661502cdfd1aabd5d3876fa4f5cc2e

Authored by Laurent Pinchart
Committed by Mauro Carvalho Chehab
1 parent 1651333b09

[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>

Showing 9 changed files with 356 additions and 0 deletions Side-by-side Diff

Documentation/DocBook/media-entities.tmpl
... ... @@ -94,6 +94,7 @@
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>">
... ... @@ -348,6 +349,7 @@
348 349 <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
349 350 <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
350 351 <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
  352 +<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
351 353  
352 354 <!-- Function Reference -->
353 355 <!ENTITY close SYSTEM "v4l/func-close.xml">
Documentation/DocBook/v4l/media-controller.xml
... ... @@ -85,5 +85,6 @@
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>
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>
Documentation/media-framework.txt
... ... @@ -259,7 +259,17 @@
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
262 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 +
  272 +
263 273 Use count and power handling
264 274 ----------------------------
265 275  
... ... @@ -271,4 +281,36 @@
271 281 The use_count field is owned by media drivers and must not be touched by entity
272 282 drivers. Access to the field must be protected by the media device graph_mutex
273 283 lock.
  284 +
  285 +
  286 +Links setup
  287 +-----------
  288 +
  289 +Link properties can be modified at runtime by calling
  290 +
  291 + media_entity_setup_link(struct media_link *link, u32 flags);
  292 +
  293 +The flags argument contains the requested new link flags.
  294 +
  295 +The only configurable property is the ENABLED link flag to enable/disable a
  296 +link. Links marked with the IMMUTABLE link flag can not be enabled or disabled.
  297 +
  298 +When a link is enabled or disabled, the media framework calls the
  299 +link_setup operation for the two entities at the source and sink of the link,
  300 +in that order. If the second link_setup call fails, another link_setup call is
  301 +made on the first entity to restore the original link flags.
  302 +
  303 +Media device drivers can be notified of link setup operations by setting the
  304 +media_device::link_notify pointer to a callback function. If provided, the
  305 +notification callback will be called before enabling and after disabling
  306 +links.
  307 +
  308 +Entity drivers must implement the link_setup operation if any of their links
  309 +is non-immutable. The operation must either configure the hardware or store
  310 +the configuration information to be applied later.
  311 +
  312 +Link configuration must not have any side effect on other links. If an enabled
  313 +link at a sink pad prevents another link at the same pad from being disabled,
  314 +the link_setup operation must return -EBUSY and can't implicitly disable the
  315 +first enabled link.
drivers/media/media-device.c
... ... @@ -172,6 +172,44 @@
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 {
... ... @@ -194,6 +232,13 @@
194 232 mutex_lock(&dev->graph_mutex);
195 233 ret = media_device_enum_links(dev,
196 234 (struct media_links_enum __user *)arg);
  235 + mutex_unlock(&dev->graph_mutex);
  236 + break;
  237 +
  238 + case MEDIA_IOC_SETUP_LINK:
  239 + mutex_lock(&dev->graph_mutex);
  240 + ret = media_device_setup_link(dev,
  241 + (struct media_link_desc __user *)arg);
197 242 mutex_unlock(&dev->graph_mutex);
198 243 break;
199 244  
drivers/media/media-entity.c
... ... @@ -306,4 +306,159 @@
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);
include/linux/media.h
... ... @@ -126,6 +126,7 @@
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 */
include/media/media-device.h
... ... @@ -73,6 +73,9 @@
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 */
include/media/media-entity.h
... ... @@ -39,6 +39,12 @@
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*/
... ... @@ -59,6 +65,8 @@
59 65 struct media_pad *pads; /* Pads array (num_pads elements) */
60 66 struct media_link *links; /* Links array (max_links elements)*/
61 67  
  68 + const struct media_entity_operations *ops; /* Entity operations */
  69 +
62 70 /* Reference counts must never be negative, but are signed integers on
63 71 * purpose: a simple WARN_ON(<0) check can be used to detect reference
64 72 * count bugs that would make them negative.
... ... @@ -112,6 +120,11 @@
112 120 void media_entity_cleanup(struct media_entity *entity);
113 121 int media_entity_create_link(struct media_entity *source, u16 source_pad,
114 122 struct media_entity *sink, u16 sink_pad, u32 flags);
  123 +int __media_entity_setup_link(struct media_link *link, u32 flags);
  124 +int media_entity_setup_link(struct media_link *link, u32 flags);
  125 +struct media_link *media_entity_find_link(struct media_pad *source,
  126 + struct media_pad *sink);
  127 +struct media_pad *media_entity_remote_source(struct media_pad *pad);
115 128  
116 129 struct media_entity *media_entity_get(struct media_entity *entity);
117 130 void media_entity_put(struct media_entity *entity);
... ... @@ -120,6 +133,10 @@
120 133 struct media_entity *entity);
121 134 struct media_entity *
122 135 media_entity_graph_walk_next(struct media_entity_graph *graph);
  136 +
  137 +#define media_entity_call(entity, operation, args...) \
  138 + (((entity)->ops && (entity)->ops->operation) ? \
  139 + (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
123 140  
124 141 #endif