summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2009-08-11 18:47:18 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-12 12:19:17 -0300
commit6b5a9492ca0c991bab1ac495624e17520e9edf18 (patch)
tree4ee2bc89d42ceae84989df965ce426932d3a6fbe
parenta138ebcf826b9cbf6683e1db25905d7cd89e2dd1 (diff)
V4L/DVB (12543): v4l: introduce string control support.
The upcoming RDS encoder needs support for string controls. This patch implements the core implementation. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/v4l2-common.c2
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c65
-rw-r--r--drivers/media/video/v4l2-ioctl.c10
-rw-r--r--include/linux/videodev2.h6
4 files changed, 57 insertions, 26 deletions
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index b91d66a767d7..536150c34067 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
return -EINVAL;
if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 0056b115b42e..f788c41a3a5c 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -600,9 +600,35 @@ struct v4l2_ext_controls32 {
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
};
+struct v4l2_ext_control32 {
+ __u32 id;
+ __u32 size;
+ __u32 reserved2[1];
+ union {
+ __s32 value;
+ __s64 value64;
+ compat_caddr_t string; /* actually char * */
+ };
+} __attribute__ ((packed));
+
+/* The following function really belong in v4l2-common, but that causes
+ a circular dependency between modules. We need to think about this, but
+ for now this will do. */
+
+/* Return non-zero if this control is a pointer type. Currently only
+ * type STRING is a pointer type.
+ *
+ * Note that there are currently no controls of this type, but at least the
+ * compat32 code is in place to properly handle such controls. Please
+ * remove this note once the first pointer controls are added. */
+static inline int ctrl_is_pointer(u32 id)
+{
+ return 0;
+}
+
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols;
int n;
compat_caddr_t p;
@@ -626,15 +652,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
kp->controls = kcontrols;
while (--n >= 0) {
- if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+ if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
return -EFAULT;
+ if (ctrl_is_pointer(kcontrols->id)) {
+ void __user *s;
+
+ if (get_user(p, &ucontrols->string))
+ return -EFAULT;
+ s = compat_ptr(p);
+ if (put_user(s, &kcontrols->string))
+ return -EFAULT;
+ }
ucontrols++;
kcontrols++;
}
@@ -643,7 +671,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
{
- struct v4l2_ext_control __user *ucontrols;
+ struct v4l2_ext_control32 __user *ucontrols;
struct v4l2_ext_control __user *kcontrols = kp->controls;
int n = kp->count;
compat_caddr_t p;
@@ -664,15 +692,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
return -EFAULT;
while (--n >= 0) {
- if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
- return -EFAULT;
- if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
- sizeof(ucontrols->reserved2)))
- return -EFAULT;
- /* Note: if the void * part of the union ever becomes relevant
- then we need to know the type of the control in order to do
- the right thing here. Luckily, that is not yet an issue. */
- if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+ unsigned size = sizeof(*ucontrols);
+
+ /* Do not modify the pointer when copying a pointer control.
+ The contents of the pointer was changed, not the pointer
+ itself. */
+ if (ctrl_is_pointer(kcontrols->id))
+ size -= sizeof(ucontrols->value64);
+ if (copy_in_user(ucontrols, kcontrols, size))
return -EFAULT;
ucontrols++;
kcontrols++;
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index c32e67608ad4..30cc3347ae52 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -513,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
dbgarg(cmd, "");
printk(KERN_CONT "class=0x%x", c->ctrl_class);
for (i = 0; i < c->count; i++) {
- if (show_vals)
+ if (show_vals && !c->controls[i].size)
printk(KERN_CONT " id/val=0x%x/0x%x",
c->controls[i].id, c->controls[i].value);
else
- printk(KERN_CONT " id=0x%x", c->controls[i].id);
+ printk(KERN_CONT " id=0x%x,size=%u",
+ c->controls[i].id, c->controls[i].size);
}
printk(KERN_CONT "\n");
};
@@ -528,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
/* zero the reserved fields */
c->reserved[0] = c->reserved[1] = 0;
- for (i = 0; i < c->count; i++) {
+ for (i = 0; i < c->count; i++)
c->controls[i].reserved2[0] = 0;
- c->controls[i].reserved2[1] = 0;
- }
+
/* V4L2_CID_PRIVATE_BASE cannot be used as control class
when using extended controls.
Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 293ba181f95a..9ab4cbe676fd 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -167,6 +167,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_BUTTON = 4,
V4L2_CTRL_TYPE_INTEGER64 = 5,
V4L2_CTRL_TYPE_CTRL_CLASS = 6,
+ V4L2_CTRL_TYPE_STRING = 7,
};
enum v4l2_tuner_type {
@@ -795,11 +796,12 @@ struct v4l2_control {
struct v4l2_ext_control {
__u32 id;
- __u32 reserved2[2];
+ __u32 size;
+ __u32 reserved2[1];
union {
__s32 value;
__s64 value64;
- void *reserved;
+ char *string;
};
} __attribute__ ((packed));