forked from mirrors/linux
		
	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:
		
							parent
							
								
									a138ebcf82
								
							
						
					
					
						commit
						6b5a9492ca
					
				
					 4 changed files with 57 additions and 26 deletions
				
			
		|  | @ -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))) | ||||
| 			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++; | ||||
|  |  | |||
|  | @ -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)); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Hans Verkuil
						Hans Verkuil