aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/Kconfig9
-rw-r--r--drivers/media/video/v4l2-subdev.c85
-rw-r--r--include/media/v4l2-subdev.h29
3 files changed, 96 insertions, 27 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 2466f2b2ecfa..6995940b633a 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -53,6 +53,15 @@ config VIDEO_V4L2_COMMON
53 depends on (I2C || I2C=n) && VIDEO_DEV 53 depends on (I2C || I2C=n) && VIDEO_DEV
54 default (I2C || I2C=n) && VIDEO_DEV 54 default (I2C || I2C=n) && VIDEO_DEV
55 55
56config VIDEO_V4L2_SUBDEV_API
57 bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
58 depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
59 ---help---
60 Enables the V4L2 sub-device pad-level userspace API used to configure
61 video format, size and frame rate between hardware blocks.
62
63 This API is mostly used by camera interfaces in embedded platforms.
64
56# 65#
57# DVB Core 66# DVB Core
58# 67#
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 85573638aa1e..6cef6ad3c9ce 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -31,36 +31,66 @@
31#include <media/v4l2-fh.h> 31#include <media/v4l2-fh.h>
32#include <media/v4l2-event.h> 32#include <media/v4l2-event.h>
33 33
34static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
35{
36#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
37 /* Allocate try format and crop in the same memory block */
38 fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
39 * sd->entity.num_pads, GFP_KERNEL);
40 if (fh->try_fmt == NULL)
41 return -ENOMEM;
42
43 fh->try_crop = (struct v4l2_rect *)
44 (fh->try_fmt + sd->entity.num_pads);
45#endif
46 return 0;
47}
48
49static void subdev_fh_free(struct v4l2_subdev_fh *fh)
50{
51#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
52 kfree(fh->try_fmt);
53 fh->try_fmt = NULL;
54 fh->try_crop = NULL;
55#endif
56}
57
34static int subdev_open(struct file *file) 58static int subdev_open(struct file *file)
35{ 59{
36 struct video_device *vdev = video_devdata(file); 60 struct video_device *vdev = video_devdata(file);
37 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 61 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
62 struct v4l2_subdev_fh *subdev_fh;
38#if defined(CONFIG_MEDIA_CONTROLLER) 63#if defined(CONFIG_MEDIA_CONTROLLER)
39 struct media_entity *entity; 64 struct media_entity *entity;
40#endif 65#endif
41 struct v4l2_fh *vfh = NULL;
42 int ret; 66 int ret;
43 67
44 if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { 68 subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
45 vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); 69 if (subdev_fh == NULL)
46 if (vfh == NULL) 70 return -ENOMEM;
47 return -ENOMEM;
48 71
49 ret = v4l2_fh_init(vfh, vdev); 72 ret = subdev_fh_init(subdev_fh, sd);
50 if (ret) 73 if (ret) {
51 goto err; 74 kfree(subdev_fh);
75 return ret;
76 }
77
78 ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
79 if (ret)
80 goto err;
52 81
53 ret = v4l2_event_init(vfh); 82 if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
83 ret = v4l2_event_init(&subdev_fh->vfh);
54 if (ret) 84 if (ret)
55 goto err; 85 goto err;
56 86
57 ret = v4l2_event_alloc(vfh, sd->nevents); 87 ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
58 if (ret) 88 if (ret)
59 goto err; 89 goto err;
60
61 v4l2_fh_add(vfh);
62 file->private_data = vfh;
63 } 90 }
91
92 v4l2_fh_add(&subdev_fh->vfh);
93 file->private_data = &subdev_fh->vfh;
64#if defined(CONFIG_MEDIA_CONTROLLER) 94#if defined(CONFIG_MEDIA_CONTROLLER)
65 if (sd->v4l2_dev->mdev) { 95 if (sd->v4l2_dev->mdev) {
66 entity = media_entity_get(&sd->entity); 96 entity = media_entity_get(&sd->entity);
@@ -70,14 +100,14 @@ static int subdev_open(struct file *file)
70 } 100 }
71 } 101 }
72#endif 102#endif
103
73 return 0; 104 return 0;
74 105
75err: 106err:
76 if (vfh != NULL) { 107 v4l2_fh_del(&subdev_fh->vfh);
77 v4l2_fh_del(vfh); 108 v4l2_fh_exit(&subdev_fh->vfh);
78 v4l2_fh_exit(vfh); 109 subdev_fh_free(subdev_fh);
79 kfree(vfh); 110 kfree(subdev_fh);
80 }
81 111
82 return ret; 112 return ret;
83} 113}
@@ -89,16 +119,17 @@ static int subdev_close(struct file *file)
89 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 119 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
90#endif 120#endif
91 struct v4l2_fh *vfh = file->private_data; 121 struct v4l2_fh *vfh = file->private_data;
122 struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
92 123
93#if defined(CONFIG_MEDIA_CONTROLLER) 124#if defined(CONFIG_MEDIA_CONTROLLER)
94 if (sd->v4l2_dev->mdev) 125 if (sd->v4l2_dev->mdev)
95 media_entity_put(&sd->entity); 126 media_entity_put(&sd->entity);
96#endif 127#endif
97 if (vfh != NULL) { 128 v4l2_fh_del(vfh);
98 v4l2_fh_del(vfh); 129 v4l2_fh_exit(vfh);
99 v4l2_fh_exit(vfh); 130 subdev_fh_free(subdev_fh);
100 kfree(vfh); 131 kfree(subdev_fh);
101 } 132 file->private_data = NULL;
102 133
103 return 0; 134 return 0;
104} 135}
@@ -107,7 +138,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
107{ 138{
108 struct video_device *vdev = video_devdata(file); 139 struct video_device *vdev = video_devdata(file);
109 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 140 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
110 struct v4l2_fh *fh = file->private_data; 141 struct v4l2_fh *vfh = file->private_data;
111 142
112 switch (cmd) { 143 switch (cmd) {
113 case VIDIOC_QUERYCTRL: 144 case VIDIOC_QUERYCTRL:
@@ -135,13 +166,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
135 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 166 if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
136 return -ENOIOCTLCMD; 167 return -ENOIOCTLCMD;
137 168
138 return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); 169 return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
139 170
140 case VIDIOC_SUBSCRIBE_EVENT: 171 case VIDIOC_SUBSCRIBE_EVENT:
141 return v4l2_subdev_call(sd, core, subscribe_event, fh, arg); 172 return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
142 173
143 case VIDIOC_UNSUBSCRIBE_EVENT: 174 case VIDIOC_UNSUBSCRIBE_EVENT:
144 return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg); 175 return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
145 176
146 default: 177 default:
147 return -ENOIOCTLCMD; 178 return -ENOIOCTLCMD;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 6f51ce4d7ee7..72f49eb3002b 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -24,6 +24,7 @@
24#include <media/media-entity.h> 24#include <media/media-entity.h>
25#include <media/v4l2-common.h> 25#include <media/v4l2-common.h>
26#include <media/v4l2-dev.h> 26#include <media/v4l2-dev.h>
27#include <media/v4l2-fh.h>
27#include <media/v4l2-mediabus.h> 28#include <media/v4l2-mediabus.h>
28 29
29/* generic v4l2_device notify callback notification values */ 30/* generic v4l2_device notify callback notification values */
@@ -481,6 +482,34 @@ struct v4l2_subdev {
481#define vdev_to_v4l2_subdev(vdev) \ 482#define vdev_to_v4l2_subdev(vdev) \
482 container_of(vdev, struct v4l2_subdev, devnode) 483 container_of(vdev, struct v4l2_subdev, devnode)
483 484
485/*
486 * Used for storing subdev information per file handle
487 */
488struct v4l2_subdev_fh {
489 struct v4l2_fh vfh;
490#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
491 struct v4l2_mbus_framefmt *try_fmt;
492 struct v4l2_rect *try_crop;
493#endif
494};
495
496#define to_v4l2_subdev_fh(fh) \
497 container_of(fh, struct v4l2_subdev_fh, vfh)
498
499#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
500static inline struct v4l2_mbus_framefmt *
501v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
502{
503 return &fh->try_fmt[pad];
504}
505
506static inline struct v4l2_rect *
507v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
508{
509 return &fh->try_crop[pad];
510}
511#endif
512
484extern const struct v4l2_file_operations v4l2_subdev_fops; 513extern const struct v4l2_file_operations v4l2_subdev_fops;
485 514
486static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p) 515static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)