Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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)
+46 −19
Original line number Diff line number Diff line
@@ -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++;
+5 −5
Original line number Diff line number Diff line
@@ -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
+4 −2
Original line number Diff line number Diff line
@@ -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));