aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-09 06:40:00 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-22 03:53:10 -0400
commit53e269c102fbaf77e7dc526b1606ad4a48e57200 (patch)
treec264a16d8058e5331ac3c0c4792be30da50e7363 /drivers
parent176fb0d108f7495ccf9aa127e1342a1a0d87e004 (diff)
[media] media: Entities, pads and links
As video hardware pipelines become increasingly complex and configurable, the current hardware description through v4l2 subdevices reaches its limits. In addition to enumerating and configuring subdevices, video camera drivers need a way to discover and modify at runtime how those subdevices are connected. This is done through new elements called entities, pads and links. An entity is a basic media hardware building block. It can correspond to a large variety of logical blocks such as physical hardware devices (CMOS sensor for instance), logical hardware devices (a building block in a System-on-Chip image processing pipeline), DMA channels or physical connectors. A pad is a connection endpoint through which an entity can interact with other entities. Data (not restricted to video) produced by an entity flows from the entity's output to one or more entity inputs. Pads should not be confused with physical pins at chip boundaries. A link is a point-to-point oriented connection between two pads, either on the same entity or on different entities. Data flows from a source pad to a sink pad. Links are stored in the source entity. To make backwards graph walk faster, a copy of all links is also stored in the sink entity. The copy is known as a backlink and is only used to help graph traversal. The entity API is made of three functions: - media_entity_init() initializes an entity. The caller must provide an array of pads as well as an estimated number of links. The links array is allocated dynamically and will be reallocated if it grows beyond the initial estimate. - media_entity_cleanup() frees resources allocated for an entity. It must be called during the cleanup phase after unregistering the entity and before freeing it. - media_entity_create_link() creates a link between two entities. An entry in the link array of each entity is allocated and stores pointers to source and sink pads. When a media device is unregistered, all its entities are unregistered automatically. The code is based on Hans Verkuil <hverkuil@xs4all.nl> initial work. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.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/Makefile2
-rw-r--r--drivers/media/media-device.c56
-rw-r--r--drivers/media/media-entity.c147
3 files changed, 204 insertions, 1 deletions
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 36731aae57ea..64755c99ded2 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the kernel multimedia device drivers. 2# Makefile for the kernel multimedia device drivers.
3# 3#
4 4
5media-objs := media-device.o media-devnode.o 5media-objs := media-device.o media-devnode.o media-entity.o
6 6
7ifeq ($(CONFIG_MEDIA_CONTROLLER),y) 7ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
8 obj-$(CONFIG_MEDIA_SUPPORT) += media.o 8 obj-$(CONFIG_MEDIA_SUPPORT) += media.o
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index bcd3985d415a..a36509a1df09 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -25,6 +25,7 @@
25 25
26#include <media/media-device.h> 26#include <media/media-device.h>
27#include <media/media-devnode.h> 27#include <media/media-devnode.h>
28#include <media/media-entity.h>
28 29
29static const struct media_file_operations media_device_fops = { 30static const struct media_file_operations media_device_fops = {
30 .owner = THIS_MODULE, 31 .owner = THIS_MODULE,
@@ -69,6 +70,10 @@ int __must_check media_device_register(struct media_device *mdev)
69 if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) 70 if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0))
70 return -EINVAL; 71 return -EINVAL;
71 72
73 mdev->entity_id = 1;
74 INIT_LIST_HEAD(&mdev->entities);
75 spin_lock_init(&mdev->lock);
76
72 /* Register the device node. */ 77 /* Register the device node. */
73 mdev->devnode.fops = &media_device_fops; 78 mdev->devnode.fops = &media_device_fops;
74 mdev->devnode.parent = mdev->dev; 79 mdev->devnode.parent = mdev->dev;
@@ -94,7 +99,58 @@ EXPORT_SYMBOL_GPL(media_device_register);
94 */ 99 */
95void media_device_unregister(struct media_device *mdev) 100void media_device_unregister(struct media_device *mdev)
96{ 101{
102 struct media_entity *entity;
103 struct media_entity *next;
104
105 list_for_each_entry_safe(entity, next, &mdev->entities, list)
106 media_device_unregister_entity(entity);
107
97 device_remove_file(&mdev->devnode.dev, &dev_attr_model); 108 device_remove_file(&mdev->devnode.dev, &dev_attr_model);
98 media_devnode_unregister(&mdev->devnode); 109 media_devnode_unregister(&mdev->devnode);
99} 110}
100EXPORT_SYMBOL_GPL(media_device_unregister); 111EXPORT_SYMBOL_GPL(media_device_unregister);
112
113/**
114 * media_device_register_entity - Register an entity with a media device
115 * @mdev: The media device
116 * @entity: The entity
117 */
118int __must_check media_device_register_entity(struct media_device *mdev,
119 struct media_entity *entity)
120{
121 /* Warn if we apparently re-register an entity */
122 WARN_ON(entity->parent != NULL);
123 entity->parent = mdev;
124
125 spin_lock(&mdev->lock);
126 if (entity->id == 0)
127 entity->id = mdev->entity_id++;
128 else
129 mdev->entity_id = max(entity->id + 1, mdev->entity_id);
130 list_add_tail(&entity->list, &mdev->entities);
131 spin_unlock(&mdev->lock);
132
133 return 0;
134}
135EXPORT_SYMBOL_GPL(media_device_register_entity);
136
137/**
138 * media_device_unregister_entity - Unregister an entity
139 * @entity: The entity
140 *
141 * If the entity has never been registered this function will return
142 * immediately.
143 */
144void media_device_unregister_entity(struct media_entity *entity)
145{
146 struct media_device *mdev = entity->parent;
147
148 if (mdev == NULL)
149 return;
150
151 spin_lock(&mdev->lock);
152 list_del(&entity->list);
153 spin_unlock(&mdev->lock);
154 entity->parent = NULL;
155}
156EXPORT_SYMBOL_GPL(media_device_unregister_entity);
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
new file mode 100644
index 000000000000..5c31df9ed765
--- /dev/null
+++ b/drivers/media/media-entity.c
@@ -0,0 +1,147 @@
1/*
2 * Media entity
3 *
4 * Copyright (C) 2010 Nokia Corporation
5 *
6 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
7 * Sakari Ailus <sakari.ailus@iki.fi>
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 version 2 as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <media/media-entity.h>
26
27/**
28 * media_entity_init - Initialize a media entity
29 *
30 * @num_pads: Total number of sink and source pads.
31 * @extra_links: Initial estimate of the number of extra links.
32 * @pads: Array of 'num_pads' pads.
33 *
34 * The total number of pads is an intrinsic property of entities known by the
35 * entity driver, while the total number of links depends on hardware design
36 * and is an extrinsic property unknown to the entity driver. However, in most
37 * use cases the entity driver can guess the number of links which can safely
38 * be assumed to be equal to or larger than the number of pads.
39 *
40 * For those reasons the links array can be preallocated based on the entity
41 * driver guess and will be reallocated later if extra links need to be
42 * created.
43 *
44 * This function allocates a links array with enough space to hold at least
45 * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will
46 * be set to the number of allocated elements.
47 *
48 * The pads array is managed by the entity driver and passed to
49 * media_entity_init() where its pointer will be stored in the entity structure.
50 */
51int
52media_entity_init(struct media_entity *entity, u16 num_pads,
53 struct media_pad *pads, u16 extra_links)
54{
55 struct media_link *links;
56 unsigned int max_links = num_pads + extra_links;
57 unsigned int i;
58
59 links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL);
60 if (links == NULL)
61 return -ENOMEM;
62
63 entity->group_id = 0;
64 entity->max_links = max_links;
65 entity->num_links = 0;
66 entity->num_backlinks = 0;
67 entity->num_pads = num_pads;
68 entity->pads = pads;
69 entity->links = links;
70
71 for (i = 0; i < num_pads; i++) {
72 pads[i].entity = entity;
73 pads[i].index = i;
74 }
75
76 return 0;
77}
78EXPORT_SYMBOL_GPL(media_entity_init);
79
80void
81media_entity_cleanup(struct media_entity *entity)
82{
83 kfree(entity->links);
84}
85EXPORT_SYMBOL_GPL(media_entity_cleanup);
86
87static struct media_link *media_entity_add_link(struct media_entity *entity)
88{
89 if (entity->num_links >= entity->max_links) {
90 struct media_link *links = entity->links;
91 unsigned int max_links = entity->max_links + 2;
92 unsigned int i;
93
94 links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL);
95 if (links == NULL)
96 return NULL;
97
98 for (i = 0; i < entity->num_links; i++)
99 links[i].reverse->reverse = &links[i];
100
101 entity->max_links = max_links;
102 entity->links = links;
103 }
104
105 return &entity->links[entity->num_links++];
106}
107
108int
109media_entity_create_link(struct media_entity *source, u16 source_pad,
110 struct media_entity *sink, u16 sink_pad, u32 flags)
111{
112 struct media_link *link;
113 struct media_link *backlink;
114
115 BUG_ON(source == NULL || sink == NULL);
116 BUG_ON(source_pad >= source->num_pads);
117 BUG_ON(sink_pad >= sink->num_pads);
118
119 link = media_entity_add_link(source);
120 if (link == NULL)
121 return -ENOMEM;
122
123 link->source = &source->pads[source_pad];
124 link->sink = &sink->pads[sink_pad];
125 link->flags = flags;
126
127 /* Create the backlink. Backlinks are used to help graph traversal and
128 * are not reported to userspace.
129 */
130 backlink = media_entity_add_link(sink);
131 if (backlink == NULL) {
132 source->num_links--;
133 return -ENOMEM;
134 }
135
136 backlink->source = &source->pads[source_pad];
137 backlink->sink = &sink->pads[sink_pad];
138 backlink->flags = flags;
139
140 link->reverse = backlink;
141 backlink->reverse = link;
142
143 sink->num_backlinks++;
144
145 return 0;
146}
147EXPORT_SYMBOL_GPL(media_entity_create_link);