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,
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)
......
......@@ -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)))
if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
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;
/* 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)))
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++;
......
......@@ -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
......
......@@ -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));
......
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