aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/video4linux/v4l2-framework.txt23
-rw-r--r--drivers/media/video/v4l2-device.c36
-rw-r--r--drivers/media/video/v4l2-subdev.c28
-rw-r--r--include/media/v4l2-subdev.h6
4 files changed, 87 insertions, 6 deletions
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 062708169def..77d96f4e3f50 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -268,6 +268,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
268Afterwards you need to initialize subdev->name with a unique name and set the 268Afterwards you need to initialize subdev->name with a unique name and set the
269module owner. This is done for you if you use the i2c helper functions. 269module owner. This is done for you if you use the i2c helper functions.
270 270
271If integration with the media framework is needed, you must initialize the
272media_entity struct embedded in the v4l2_subdev struct (entity field) by
273calling media_entity_init():
274
275 struct media_pad *pads = &my_sd->pads;
276 int err;
277
278 err = media_entity_init(&sd->entity, npads, pads, 0);
279
280The pads array must have been previously initialized. There is no need to
281manually set the struct media_entity type and name fields, but the revision
282field must be initialized if needed.
283
284A reference to the entity will be automatically acquired/released when the
285subdev device node (if any) is opened/closed.
286
287Don't forget to cleanup the media entity before the sub-device is destroyed:
288
289 media_entity_cleanup(&sd->entity);
290
271A device (bridge) driver needs to register the v4l2_subdev with the 291A device (bridge) driver needs to register the v4l2_subdev with the
272v4l2_device: 292v4l2_device:
273 293
@@ -277,6 +297,9 @@ This can fail if the subdev module disappeared before it could be registered.
277After this function was called successfully the subdev->dev field points to 297After this function was called successfully the subdev->dev field points to
278the v4l2_device. 298the v4l2_device.
279 299
300If the v4l2_device parent device has a non-NULL mdev field, the sub-device
301entity will be automatically registered with the media device.
302
280You can unregister a sub-device using: 303You can unregister a sub-device using:
281 304
282 v4l2_device_unregister_subdev(sd); 305 v4l2_device_unregister_subdev(sd);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index cfbd8a38991d..a1afda352d08 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -118,8 +118,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
118EXPORT_SYMBOL_GPL(v4l2_device_unregister); 118EXPORT_SYMBOL_GPL(v4l2_device_unregister);
119 119
120int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, 120int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
121 struct v4l2_subdev *sd) 121 struct v4l2_subdev *sd)
122{ 122{
123#if defined(CONFIG_MEDIA_CONTROLLER)
124 struct media_entity *entity = &sd->entity;
125#endif
123 int err; 126 int err;
124 127
125 /* Check for valid input */ 128 /* Check for valid input */
@@ -147,6 +150,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
147 return err; 150 return err;
148 } 151 }
149 152
153#if defined(CONFIG_MEDIA_CONTROLLER)
154 /* Register the entity. */
155 if (v4l2_dev->mdev) {
156 err = media_device_register_entity(v4l2_dev->mdev, entity);
157 if (err < 0) {
158 if (sd->internal_ops && sd->internal_ops->unregistered)
159 sd->internal_ops->unregistered(sd);
160 module_put(sd->owner);
161 return err;
162 }
163 }
164#endif
165
150 spin_lock(&v4l2_dev->lock); 166 spin_lock(&v4l2_dev->lock);
151 list_add_tail(&sd->list, &v4l2_dev->subdevs); 167 list_add_tail(&sd->list, &v4l2_dev->subdevs);
152 spin_unlock(&v4l2_dev->lock); 168 spin_unlock(&v4l2_dev->lock);
@@ -177,25 +193,37 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
177 sd->owner); 193 sd->owner);
178 if (err < 0) 194 if (err < 0)
179 return err; 195 return err;
196#if defined(CONFIG_MEDIA_CONTROLLER)
197 sd->entity.v4l.major = VIDEO_MAJOR;
198 sd->entity.v4l.minor = vdev->minor;
199#endif
180 } 200 }
181
182 return 0; 201 return 0;
183} 202}
184EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); 203EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
185 204
186void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) 205void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
187{ 206{
207 struct v4l2_device *v4l2_dev;
208
188 /* return if it isn't registered */ 209 /* return if it isn't registered */
189 if (sd == NULL || sd->v4l2_dev == NULL) 210 if (sd == NULL || sd->v4l2_dev == NULL)
190 return; 211 return;
191 212
192 spin_lock(&sd->v4l2_dev->lock); 213 v4l2_dev = sd->v4l2_dev;
214
215 spin_lock(&v4l2_dev->lock);
193 list_del(&sd->list); 216 list_del(&sd->list);
194 spin_unlock(&sd->v4l2_dev->lock); 217 spin_unlock(&v4l2_dev->lock);
218
195 if (sd->internal_ops && sd->internal_ops->unregistered) 219 if (sd->internal_ops && sd->internal_ops->unregistered)
196 sd->internal_ops->unregistered(sd); 220 sd->internal_ops->unregistered(sd);
197 sd->v4l2_dev = NULL; 221 sd->v4l2_dev = NULL;
198 222
223#if defined(CONFIG_MEDIA_CONTROLLER)
224 if (v4l2_dev->mdev)
225 media_device_unregister_entity(&sd->entity);
226#endif
199 video_unregister_device(&sd->devnode); 227 video_unregister_device(&sd->devnode);
200 module_put(sd->owner); 228 module_put(sd->owner);
201} 229}
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 0c67f5a278fb..85573638aa1e 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -35,7 +35,10 @@ static int subdev_open(struct file *file)
35{ 35{
36 struct video_device *vdev = video_devdata(file); 36 struct video_device *vdev = video_devdata(file);
37 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 37 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
38 struct v4l2_fh *vfh; 38#if defined(CONFIG_MEDIA_CONTROLLER)
39 struct media_entity *entity;
40#endif
41 struct v4l2_fh *vfh = NULL;
39 int ret; 42 int ret;
40 43
41 if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { 44 if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
@@ -58,11 +61,20 @@ static int subdev_open(struct file *file)
58 v4l2_fh_add(vfh); 61 v4l2_fh_add(vfh);
59 file->private_data = vfh; 62 file->private_data = vfh;
60 } 63 }
61 64#if defined(CONFIG_MEDIA_CONTROLLER)
65 if (sd->v4l2_dev->mdev) {
66 entity = media_entity_get(&sd->entity);
67 if (!entity) {
68 ret = -EBUSY;
69 goto err;
70 }
71 }
72#endif
62 return 0; 73 return 0;
63 74
64err: 75err:
65 if (vfh != NULL) { 76 if (vfh != NULL) {
77 v4l2_fh_del(vfh);
66 v4l2_fh_exit(vfh); 78 v4l2_fh_exit(vfh);
67 kfree(vfh); 79 kfree(vfh);
68 } 80 }
@@ -72,8 +84,16 @@ err:
72 84
73static int subdev_close(struct file *file) 85static int subdev_close(struct file *file)
74{ 86{
87#if defined(CONFIG_MEDIA_CONTROLLER)
88 struct video_device *vdev = video_devdata(file);
89 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
90#endif
75 struct v4l2_fh *vfh = file->private_data; 91 struct v4l2_fh *vfh = file->private_data;
76 92
93#if defined(CONFIG_MEDIA_CONTROLLER)
94 if (sd->v4l2_dev->mdev)
95 media_entity_put(&sd->entity);
96#endif
77 if (vfh != NULL) { 97 if (vfh != NULL) {
78 v4l2_fh_del(vfh); 98 v4l2_fh_del(vfh);
79 v4l2_fh_exit(vfh); 99 v4l2_fh_exit(vfh);
@@ -172,5 +192,9 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
172 sd->grp_id = 0; 192 sd->grp_id = 0;
173 sd->dev_priv = NULL; 193 sd->dev_priv = NULL;
174 sd->host_priv = NULL; 194 sd->host_priv = NULL;
195#if defined(CONFIG_MEDIA_CONTROLLER)
196 sd->entity.name = sd->name;
197 sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
198#endif
175} 199}
176EXPORT_SYMBOL(v4l2_subdev_init); 200EXPORT_SYMBOL(v4l2_subdev_init);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 0f9937be53d2..6f51ce4d7ee7 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -21,6 +21,7 @@
21#ifndef _V4L2_SUBDEV_H 21#ifndef _V4L2_SUBDEV_H
22#define _V4L2_SUBDEV_H 22#define _V4L2_SUBDEV_H
23 23
24#include <media/media-entity.h>
24#include <media/v4l2-common.h> 25#include <media/v4l2-common.h>
25#include <media/v4l2-dev.h> 26#include <media/v4l2-dev.h>
26#include <media/v4l2-mediabus.h> 27#include <media/v4l2-mediabus.h>
@@ -450,6 +451,9 @@ struct v4l2_subdev_internal_ops {
450 stand-alone or embedded in a larger struct. 451 stand-alone or embedded in a larger struct.
451 */ 452 */
452struct v4l2_subdev { 453struct v4l2_subdev {
454#if defined(CONFIG_MEDIA_CONTROLLER)
455 struct media_entity entity;
456#endif
453 struct list_head list; 457 struct list_head list;
454 struct module *owner; 458 struct module *owner;
455 u32 flags; 459 u32 flags;
@@ -472,6 +476,8 @@ struct v4l2_subdev {
472 unsigned int nevents; 476 unsigned int nevents;
473}; 477};
474 478
479#define media_entity_to_v4l2_subdev(ent) \
480 container_of(ent, struct v4l2_subdev, entity)
475#define vdev_to_v4l2_subdev(vdev) \ 481#define vdev_to_v4l2_subdev(vdev) \
476 container_of(vdev, struct v4l2_subdev, devnode) 482 container_of(vdev, struct v4l2_subdev, devnode)
477 483