Browse Source

[media] v4l: Make v4l2_subdev inherit from media_entity

V4L2 subdevices are media entities. As such they need to inherit from
(include) the media_entity structure.

When registering/unregistering the subdevice, the media entity is
automatically registered/unregistered. The entity is acquired on device
open and released on device close.

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>
Laurent Pinchart 15 years ago
parent
commit
61f5db549d

+ 23 - 0
Documentation/video4linux/v4l2-framework.txt

@@ -268,6 +268,26 @@ A sub-device driver initializes the v4l2_subdev struct using:
 Afterwards you need to initialize subdev->name with a unique name and set the
 Afterwards you need to initialize subdev->name with a unique name and set the
 module owner. This is done for you if you use the i2c helper functions.
 module owner. This is done for you if you use the i2c helper functions.
 
 
+If integration with the media framework is needed, you must initialize the
+media_entity struct embedded in the v4l2_subdev struct (entity field) by
+calling media_entity_init():
+
+	struct media_pad *pads = &my_sd->pads;
+	int err;
+
+	err = media_entity_init(&sd->entity, npads, pads, 0);
+
+The pads array must have been previously initialized. There is no need to
+manually set the struct media_entity type and name fields, but the revision
+field must be initialized if needed.
+
+A reference to the entity will be automatically acquired/released when the
+subdev device node (if any) is opened/closed.
+
+Don't forget to cleanup the media entity before the sub-device is destroyed:
+
+	media_entity_cleanup(&sd->entity);
+
 A device (bridge) driver needs to register the v4l2_subdev with the
 A device (bridge) driver needs to register the v4l2_subdev with the
 v4l2_device:
 v4l2_device:
 
 
@@ -277,6 +297,9 @@ This can fail if the subdev module disappeared before it could be registered.
 After this function was called successfully the subdev->dev field points to
 After this function was called successfully the subdev->dev field points to
 the v4l2_device.
 the v4l2_device.
 
 
+If the v4l2_device parent device has a non-NULL mdev field, the sub-device
+entity will be automatically registered with the media device.
+
 You can unregister a sub-device using:
 You can unregister a sub-device using:
 
 
 	v4l2_device_unregister_subdev(sd);
 	v4l2_device_unregister_subdev(sd);

+ 32 - 4
drivers/media/video/v4l2-device.c

@@ -118,8 +118,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
 
 int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
-						struct v4l2_subdev *sd)
+				struct v4l2_subdev *sd)
 {
 {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct media_entity *entity = &sd->entity;
+#endif
 	int err;
 	int err;
 
 
 	/* Check for valid input */
 	/* Check for valid input */
@@ -147,6 +150,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 		return err;
 		return err;
 	}
 	}
 
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	/* Register the entity. */
+	if (v4l2_dev->mdev) {
+		err = media_device_register_entity(v4l2_dev->mdev, entity);
+		if (err < 0) {
+			if (sd->internal_ops && sd->internal_ops->unregistered)
+				sd->internal_ops->unregistered(sd);
+			module_put(sd->owner);
+			return err;
+		}
+	}
+#endif
+
 	spin_lock(&v4l2_dev->lock);
 	spin_lock(&v4l2_dev->lock);
 	list_add_tail(&sd->list, &v4l2_dev->subdevs);
 	list_add_tail(&sd->list, &v4l2_dev->subdevs);
 	spin_unlock(&v4l2_dev->lock);
 	spin_unlock(&v4l2_dev->lock);
@@ -177,25 +193,37 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
 					      sd->owner);
 					      sd->owner);
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+		sd->entity.v4l.major = VIDEO_MAJOR;
+		sd->entity.v4l.minor = vdev->minor;
+#endif
 	}
 	}
-
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);
 
 
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
 {
 {
+	struct v4l2_device *v4l2_dev;
+
 	/* return if it isn't registered */
 	/* return if it isn't registered */
 	if (sd == NULL || sd->v4l2_dev == NULL)
 	if (sd == NULL || sd->v4l2_dev == NULL)
 		return;
 		return;
 
 
-	spin_lock(&sd->v4l2_dev->lock);
+	v4l2_dev = sd->v4l2_dev;
+
+	spin_lock(&v4l2_dev->lock);
 	list_del(&sd->list);
 	list_del(&sd->list);
-	spin_unlock(&sd->v4l2_dev->lock);
+	spin_unlock(&v4l2_dev->lock);
+
 	if (sd->internal_ops && sd->internal_ops->unregistered)
 	if (sd->internal_ops && sd->internal_ops->unregistered)
 		sd->internal_ops->unregistered(sd);
 		sd->internal_ops->unregistered(sd);
 	sd->v4l2_dev = NULL;
 	sd->v4l2_dev = NULL;
 
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	if (v4l2_dev->mdev)
+		media_device_unregister_entity(&sd->entity);
+#endif
 	video_unregister_device(&sd->devnode);
 	video_unregister_device(&sd->devnode);
 	module_put(sd->owner);
 	module_put(sd->owner);
 }
 }

+ 26 - 2
drivers/media/video/v4l2-subdev.c

@@ -35,7 +35,10 @@ static int subdev_open(struct file *file)
 {
 {
 	struct video_device *vdev = video_devdata(file);
 	struct video_device *vdev = video_devdata(file);
 	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
 	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
-	struct v4l2_fh *vfh;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct media_entity *entity;
+#endif
+	struct v4l2_fh *vfh = NULL;
 	int ret;
 	int ret;
 
 
 	if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
 	if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
@@ -58,11 +61,20 @@ static int subdev_open(struct file *file)
 		v4l2_fh_add(vfh);
 		v4l2_fh_add(vfh);
 		file->private_data = vfh;
 		file->private_data = vfh;
 	}
 	}
-
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	if (sd->v4l2_dev->mdev) {
+		entity = media_entity_get(&sd->entity);
+		if (!entity) {
+			ret = -EBUSY;
+			goto err;
+		}
+	}
+#endif
 	return 0;
 	return 0;
 
 
 err:
 err:
 	if (vfh != NULL) {
 	if (vfh != NULL) {
+		v4l2_fh_del(vfh);
 		v4l2_fh_exit(vfh);
 		v4l2_fh_exit(vfh);
 		kfree(vfh);
 		kfree(vfh);
 	}
 	}
@@ -72,8 +84,16 @@ err:
 
 
 static int subdev_close(struct file *file)
 static int subdev_close(struct file *file)
 {
 {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+#endif
 	struct v4l2_fh *vfh = file->private_data;
 	struct v4l2_fh *vfh = file->private_data;
 
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	if (sd->v4l2_dev->mdev)
+		media_entity_put(&sd->entity);
+#endif
 	if (vfh != NULL) {
 	if (vfh != NULL) {
 		v4l2_fh_del(vfh);
 		v4l2_fh_del(vfh);
 		v4l2_fh_exit(vfh);
 		v4l2_fh_exit(vfh);
@@ -172,5 +192,9 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
 	sd->grp_id = 0;
 	sd->grp_id = 0;
 	sd->dev_priv = NULL;
 	sd->dev_priv = NULL;
 	sd->host_priv = NULL;
 	sd->host_priv = NULL;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.name = sd->name;
+	sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+#endif
 }
 }
 EXPORT_SYMBOL(v4l2_subdev_init);
 EXPORT_SYMBOL(v4l2_subdev_init);

+ 6 - 0
include/media/v4l2-subdev.h

@@ -21,6 +21,7 @@
 #ifndef _V4L2_SUBDEV_H
 #ifndef _V4L2_SUBDEV_H
 #define _V4L2_SUBDEV_H
 #define _V4L2_SUBDEV_H
 
 
+#include <media/media-entity.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-mediabus.h>
@@ -450,6 +451,9 @@ struct v4l2_subdev_internal_ops {
    stand-alone or embedded in a larger struct.
    stand-alone or embedded in a larger struct.
  */
  */
 struct v4l2_subdev {
 struct v4l2_subdev {
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct media_entity entity;
+#endif
 	struct list_head list;
 	struct list_head list;
 	struct module *owner;
 	struct module *owner;
 	u32 flags;
 	u32 flags;
@@ -472,6 +476,8 @@ struct v4l2_subdev {
 	unsigned int nevents;
 	unsigned int nevents;
 };
 };
 
 
+#define media_entity_to_v4l2_subdev(ent) \
+	container_of(ent, struct v4l2_subdev, entity)
 #define vdev_to_v4l2_subdev(vdev) \
 #define vdev_to_v4l2_subdev(vdev) \
 	container_of(vdev, struct v4l2_subdev, devnode)
 	container_of(vdev, struct v4l2_subdev, devnode)