From 6b5a9492ca0c991bab1ac495624e17520e9edf18 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Aug 2009 18:47:18 -0300 Subject: 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 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 2 + drivers/media/video/v4l2-compat-ioctl32.c | 65 ++++++++++++++++++++++--------- drivers/media/video/v4l2-ioctl.c | 10 ++--- include/linux/videodev2.h | 6 ++- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b91d66a767d..536150c3406 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 0056b115b42..f788c41a3a5 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 c32e67608ad..30cc3347ae5 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 293ba181f95..9ab4cbe676f 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)); -- cgit v1.2.3