Skip to content

Commit

Permalink
[media] v4l: Create v4l2 subdev file handle structure
Browse files Browse the repository at this point in the history
Used for storing subdev information per file handle and hold V4L2 file
handle.

Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: Antti Koskipaa <akoskipa@gmail.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Stanimir Varbanov authored and Mauro Carvalho Chehab committed Mar 22, 2011
1 parent dacdde7 commit 7cd5a16
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 27 deletions.
9 changes: 9 additions & 0 deletions drivers/media/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ config VIDEO_V4L2_COMMON
depends on (I2C || I2C=n) && VIDEO_DEV
default (I2C || I2C=n) && VIDEO_DEV

config VIDEO_V4L2_SUBDEV_API
bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
---help---
Enables the V4L2 sub-device pad-level userspace API used to configure
video format, size and frame rate between hardware blocks.

This API is mostly used by camera interfaces in embedded platforms.

#
# DVB Core
#
Expand Down
85 changes: 58 additions & 27 deletions drivers/media/video/v4l2-subdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,36 +31,66 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>

static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
/* Allocate try format and crop in the same memory block */
fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
* sd->entity.num_pads, GFP_KERNEL);
if (fh->try_fmt == NULL)
return -ENOMEM;

fh->try_crop = (struct v4l2_rect *)
(fh->try_fmt + sd->entity.num_pads);
#endif
return 0;
}

static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
kfree(fh->try_fmt);
fh->try_fmt = NULL;
fh->try_crop = NULL;
#endif
}

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_subdev_fh *subdev_fh;
#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) {
vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
if (vfh == NULL)
return -ENOMEM;
subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
if (subdev_fh == NULL)
return -ENOMEM;

ret = v4l2_fh_init(vfh, vdev);
if (ret)
goto err;
ret = subdev_fh_init(subdev_fh, sd);
if (ret) {
kfree(subdev_fh);
return ret;
}

ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
if (ret)
goto err;

ret = v4l2_event_init(vfh);
if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
ret = v4l2_event_init(&subdev_fh->vfh);
if (ret)
goto err;

ret = v4l2_event_alloc(vfh, sd->nevents);
ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
if (ret)
goto err;

v4l2_fh_add(vfh);
file->private_data = vfh;
}

v4l2_fh_add(&subdev_fh->vfh);
file->private_data = &subdev_fh->vfh;
#if defined(CONFIG_MEDIA_CONTROLLER)
if (sd->v4l2_dev->mdev) {
entity = media_entity_get(&sd->entity);
Expand All @@ -70,14 +100,14 @@ static int subdev_open(struct file *file)
}
}
#endif

return 0;

err:
if (vfh != NULL) {
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
kfree(vfh);
}
v4l2_fh_del(&subdev_fh->vfh);
v4l2_fh_exit(&subdev_fh->vfh);
subdev_fh_free(subdev_fh);
kfree(subdev_fh);

return ret;
}
Expand All @@ -89,16 +119,17 @@ static int subdev_close(struct file *file)
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
#endif
struct v4l2_fh *vfh = file->private_data;
struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);

#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);
kfree(vfh);
}
v4l2_fh_del(vfh);
v4l2_fh_exit(vfh);
subdev_fh_free(subdev_fh);
kfree(subdev_fh);
file->private_data = NULL;

return 0;
}
Expand All @@ -107,7 +138,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_fh *fh = file->private_data;
struct v4l2_fh *vfh = file->private_data;

switch (cmd) {
case VIDIOC_QUERYCTRL:
Expand Down Expand Up @@ -135,13 +166,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
return -ENOIOCTLCMD;

return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);

case VIDIOC_SUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);

case VIDIOC_UNSUBSCRIBE_EVENT:
return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);

default:
return -ENOIOCTLCMD;
Expand Down
29 changes: 29 additions & 0 deletions include/media/v4l2-subdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-mediabus.h>

/* generic v4l2_device notify callback notification values */
Expand Down Expand Up @@ -481,6 +482,34 @@ struct v4l2_subdev {
#define vdev_to_v4l2_subdev(vdev) \
container_of(vdev, struct v4l2_subdev, devnode)

/*
* Used for storing subdev information per file handle
*/
struct v4l2_subdev_fh {
struct v4l2_fh vfh;
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
struct v4l2_mbus_framefmt *try_fmt;
struct v4l2_rect *try_crop;
#endif
};

#define to_v4l2_subdev_fh(fh) \
container_of(fh, struct v4l2_subdev_fh, vfh)

#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static inline struct v4l2_mbus_framefmt *
v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
{
return &fh->try_fmt[pad];
}

static inline struct v4l2_rect *
v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
{
return &fh->try_crop[pad];
}
#endif

extern const struct v4l2_file_operations v4l2_subdev_fops;

static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
Expand Down

0 comments on commit 7cd5a16

Please sign in to comment.