Skip to content

Commit

Permalink
[media] v4l: Make v4l2_subdev inherit from media_entity
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
pinchartl authored and Mauro Carvalho Chehab committed Mar 22, 2011
1 parent 2c0ab67 commit 61f5db5
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 6 deletions.
23 changes: 23 additions & 0 deletions Documentation/video4linux/v4l2-framework.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
v4l2_device:

Expand All @@ -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
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:

v4l2_device_unregister_subdev(sd);
Expand Down
36 changes: 32 additions & 4 deletions drivers/media/video/v4l2-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
EXPORT_SYMBOL_GPL(v4l2_device_unregister);

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;

/* Check for valid input */
Expand Down Expand Up @@ -147,6 +150,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
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);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
Expand Down Expand Up @@ -177,25 +193,37 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
sd->owner);
if (err < 0)
return err;
#if defined(CONFIG_MEDIA_CONTROLLER)
sd->entity.v4l.major = VIDEO_MAJOR;
sd->entity.v4l.minor = vdev->minor;
#endif
}

return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes);

void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
{
struct v4l2_device *v4l2_dev;

/* return if it isn't registered */
if (sd == NULL || sd->v4l2_dev == NULL)
return;

spin_lock(&sd->v4l2_dev->lock);
v4l2_dev = sd->v4l2_dev;

spin_lock(&v4l2_dev->lock);
list_del(&sd->list);
spin_unlock(&sd->v4l2_dev->lock);
spin_unlock(&v4l2_dev->lock);

if (sd->internal_ops && sd->internal_ops->unregistered)
sd->internal_ops->unregistered(sd);
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);
module_put(sd->owner);
}
Expand Down
28 changes: 26 additions & 2 deletions drivers/media/video/v4l2-subdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ static int subdev_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
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;

if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
Expand All @@ -58,11 +61,20 @@ static int subdev_open(struct file *file)
v4l2_fh_add(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;

err:
if (vfh != NULL) {
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
kfree(vfh);
}
Expand All @@ -72,8 +84,16 @@ static int subdev_open(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;

#if defined(CONFIG_MEDIA_CONTROLLER)
if (sd->v4l2_dev->mdev)
media_entity_put(&sd->entity);
#endif
if (vfh != NULL) {
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
Expand Down Expand Up @@ -172,5 +192,9 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
sd->grp_id = 0;
sd->dev_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);
6 changes: 6 additions & 0 deletions include/media/v4l2-subdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#ifndef _V4L2_SUBDEV_H
#define _V4L2_SUBDEV_H

#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-mediabus.h>
Expand Down Expand Up @@ -450,6 +451,9 @@ struct v4l2_subdev_internal_ops {
stand-alone or embedded in a larger struct.
*/
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
struct list_head list;
struct module *owner;
u32 flags;
Expand All @@ -472,6 +476,8 @@ struct v4l2_subdev {
unsigned int nevents;
};

#define media_entity_to_v4l2_subdev(ent) \
container_of(ent, struct v4l2_subdev, entity)
#define vdev_to_v4l2_subdev(vdev) \
container_of(vdev, struct v4l2_subdev, devnode)

Expand Down

0 comments on commit 61f5db5

Please sign in to comment.