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>
This commit is contained in:
Hans Verkuil 2009-08-11 18:47:18 -03:00 committed by Mauro Carvalho Chehab
parent a138ebcf82
commit 6b5a9492ca
4 changed files with 57 additions and 26 deletions

View File

@ -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)

View File

@ -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++;

View File

@ -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

View File

@ -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));