aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-09 06:40:03 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-22 03:53:16 -0400
commit97548ed4c4661502cdfd1aabd5d3876fa4f5cc2e (patch)
treec85b85954f53e3a97b6590de8d5d5396e7c43358 /drivers
parent1651333b09743887bc2dd3d158a11853a2be3fe7 (diff)
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/media-device.c45
-rw-r--r--drivers/media/media-entity.c155
2 files changed, 200 insertions, 0 deletions
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 648a9d892ac1..16b70b4412f7 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev,
172 return 0; 172 return 0;
173} 173}
174 174
175static 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
175static long media_device_ioctl(struct file *filp, unsigned int cmd, 213static long media_device_ioctl(struct file *filp, unsigned int cmd,
176 unsigned long arg) 214 unsigned long arg)
177{ 215{
@@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
197 mutex_unlock(&dev->graph_mutex); 235 mutex_unlock(&dev->graph_mutex);
198 break; 236 break;
199 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);
242 mutex_unlock(&dev->graph_mutex);
243 break;
244
200 default: 245 default:
201 ret = -ENOIOCTLCMD; 246 ret = -ENOIOCTLCMD;
202 } 247 }
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3e7e2d569cec..6795c920d460 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad,
306 return 0; 306 return 0;
307} 307}
308EXPORT_SYMBOL_GPL(media_entity_create_link); 308EXPORT_SYMBOL_GPL(media_entity_create_link);
309
310static 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 */
349int __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
385err:
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
392int 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}
402EXPORT_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 */
412struct media_link *
413media_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}
430EXPORT_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 */
443struct 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}
463EXPORT_SYMBOL_GPL(media_entity_remote_source);