Commit 6b5a9492 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a138ebcf
...@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl, ...@@ -156,6 +156,8 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
return -EINVAL; return -EINVAL;
if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED) if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
return -EBUSY; return -EBUSY;
if (qctrl->type == V4L2_CTRL_TYPE_STRING)
return 0;
if (qctrl->type == V4L2_CTRL_TYPE_BUTTON || if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
qctrl->type == V4L2_CTRL_TYPE_INTEGER64 || qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
......
...@@ -600,9 +600,35 @@ struct v4l2_ext_controls32 { ...@@ -600,9 +600,35 @@ struct v4l2_ext_controls32 {
compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */ 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) 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; struct v4l2_ext_control __user *kcontrols;
int n; int n;
compat_caddr_t p; compat_caddr_t p;
...@@ -626,15 +652,17 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext ...@@ -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)); kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
kp->controls = kcontrols; kp->controls = kcontrols;
while (--n >= 0) { while (--n >= 0) {
if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32))) if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
return -EFAULT; return -EFAULT;
if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2))) if (ctrl_is_pointer(kcontrols->id)) {
void __user *s;
if (get_user(p, &ucontrols->string))
return -EFAULT; return -EFAULT;
/* Note: if the void * part of the union ever becomes relevant s = compat_ptr(p);
then we need to know the type of the control in order to do if (put_user(s, &kcontrols->string))
the right thing here. Luckily, that is not yet an issue. */
if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
return -EFAULT; return -EFAULT;
}
ucontrols++; ucontrols++;
kcontrols++; kcontrols++;
} }
...@@ -643,7 +671,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext ...@@ -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) 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; struct v4l2_ext_control __user *kcontrols = kp->controls;
int n = kp->count; int n = kp->count;
compat_caddr_t p; compat_caddr_t p;
...@@ -664,15 +692,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext ...@@ -664,15 +692,14 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
return -EFAULT; return -EFAULT;
while (--n >= 0) { while (--n >= 0) {
if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32))) unsigned size = sizeof(*ucontrols);
return -EFAULT;
if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2, /* Do not modify the pointer when copying a pointer control.
sizeof(ucontrols->reserved2))) The contents of the pointer was changed, not the pointer
return -EFAULT; itself. */
/* Note: if the void * part of the union ever becomes relevant if (ctrl_is_pointer(kcontrols->id))
then we need to know the type of the control in order to do size -= sizeof(ucontrols->value64);
the right thing here. Luckily, that is not yet an issue. */ if (copy_in_user(ucontrols, kcontrols, size))
if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
return -EFAULT; return -EFAULT;
ucontrols++; ucontrols++;
kcontrols++; kcontrols++;
......
...@@ -513,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd, ...@@ -513,11 +513,12 @@ static inline void v4l_print_ext_ctrls(unsigned int cmd,
dbgarg(cmd, ""); dbgarg(cmd, "");
printk(KERN_CONT "class=0x%x", c->ctrl_class); printk(KERN_CONT "class=0x%x", c->ctrl_class);
for (i = 0; i < c->count; i++) { 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", printk(KERN_CONT " id/val=0x%x/0x%x",
c->controls[i].id, c->controls[i].value); c->controls[i].id, c->controls[i].value);
else 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"); printk(KERN_CONT "\n");
}; };
...@@ -528,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) ...@@ -528,10 +529,9 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
/* zero the reserved fields */ /* zero the reserved fields */
c->reserved[0] = c->reserved[1] = 0; 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[0] = 0;
c->controls[i].reserved2[1] = 0;
}
/* V4L2_CID_PRIVATE_BASE cannot be used as control class /* V4L2_CID_PRIVATE_BASE cannot be used as control class
when using extended controls. when using extended controls.
Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
......
...@@ -167,6 +167,7 @@ enum v4l2_ctrl_type { ...@@ -167,6 +167,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_BUTTON = 4, V4L2_CTRL_TYPE_BUTTON = 4,
V4L2_CTRL_TYPE_INTEGER64 = 5, V4L2_CTRL_TYPE_INTEGER64 = 5,
V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_CTRL_CLASS = 6,
V4L2_CTRL_TYPE_STRING = 7,
}; };
enum v4l2_tuner_type { enum v4l2_tuner_type {
...@@ -795,11 +796,12 @@ struct v4l2_control { ...@@ -795,11 +796,12 @@ struct v4l2_control {
struct v4l2_ext_control { struct v4l2_ext_control {
__u32 id; __u32 id;
__u32 reserved2[2]; __u32 size;
__u32 reserved2[1];
union { union {
__s32 value; __s32 value;
__s64 value64; __s64 value64;
void *reserved; char *string;
}; };
} __attribute__ ((packed)); } __attribute__ ((packed));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment