diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ctrls-api.c')
| -rw-r--r-- | drivers/media/v4l2-core/v4l2-ctrls-api.c | 63 | 
1 files changed, 45 insertions, 18 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index 50d012ba3c02..3d3b6dc24ca6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -89,10 +89,7 @@ static int req_to_user(struct v4l2_ext_control *c,  /* Helper function: copy the initial control value back to the caller */  static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)  { -	int idx; - -	for (idx = 0; idx < ctrl->elems; idx++) -		ctrl->type_ops->init(ctrl, idx, ctrl->p_new); +	ctrl->type_ops->init(ctrl, 0, ctrl->p_new);  	return ptr_to_user(c, ctrl, ctrl->p_new);  } @@ -105,8 +102,8 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)  	ctrl->is_new = 0;  	if (ctrl->is_dyn_array && -	    c->size > ctrl->p_dyn_alloc_elems * ctrl->elem_size) { -		void *old = ctrl->p_dyn; +	    c->size > ctrl->p_array_alloc_elems * ctrl->elem_size) { +		void *old = ctrl->p_array;  		void *tmp = kvzalloc(2 * c->size, GFP_KERNEL);  		if (!tmp) @@ -115,14 +112,13 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)  		memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);  		ctrl->p_new.p = tmp;  		ctrl->p_cur.p = tmp + c->size; -		ctrl->p_dyn = tmp; -		ctrl->p_dyn_alloc_elems = c->size / ctrl->elem_size; +		ctrl->p_array = tmp; +		ctrl->p_array_alloc_elems = c->size / ctrl->elem_size;  		kvfree(old);  	}  	if (ctrl->is_ptr && !ctrl->is_string) {  		unsigned int elems = c->size / ctrl->elem_size; -		unsigned int idx;  		if (copy_from_user(ctrl->p_new.p, c->ptr, c->size))  			return -EFAULT; @@ -130,8 +126,7 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)  		if (ctrl->is_dyn_array)  			ctrl->new_elems = elems;  		else if (ctrl->is_array) -			for (idx = elems; idx < ctrl->elems; idx++) -				ctrl->type_ops->init(ctrl, idx, ctrl->p_new); +			ctrl->type_ops->init(ctrl, elems, ctrl->p_new);  		return 0;  	} @@ -155,6 +150,7 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)  			 * then return an error.  			 */  			if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last) +			ctrl->is_new = 1;  				return -ERANGE;  		}  		return ret; @@ -467,7 +463,7 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,  			if (is_default)  				ret = def_to_user(cs->controls + idx, ref->ctrl); -			else if (is_request && ref->p_req_dyn_enomem) +			else if (is_request && ref->p_req_array_enomem)  				ret = -ENOMEM;  			else if (is_request && ref->p_req_valid)  				ret = req_to_user(cs->controls + idx, ref); @@ -499,12 +495,7 @@ EXPORT_SYMBOL(v4l2_g_ext_ctrls);  /* Validate a new control */  static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)  { -	unsigned int idx; -	int err = 0; - -	for (idx = 0; !err && idx < ctrl->new_elems; idx++) -		err = ctrl->type_ops->validate(ctrl, idx, p_new); -	return err; +	return ctrl->type_ops->validate(ctrl, p_new);  }  /* Validate controls. */ @@ -989,6 +980,42 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,  }  EXPORT_SYMBOL(__v4l2_ctrl_modify_range); +int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, +				  u32 dims[V4L2_CTRL_MAX_DIMS]) +{ +	unsigned int elems = 1; +	unsigned int i; +	void *p_array; + +	lockdep_assert_held(ctrl->handler->lock); + +	if (!ctrl->is_array || ctrl->is_dyn_array) +		return -EINVAL; + +	for (i = 0; i < ctrl->nr_of_dims; i++) +		elems *= dims[i]; +	if (elems == 0) +		return -EINVAL; +	p_array = kvzalloc(2 * elems * ctrl->elem_size, GFP_KERNEL); +	if (!p_array) +		return -ENOMEM; +	kvfree(ctrl->p_array); +	ctrl->p_array_alloc_elems = elems; +	ctrl->elems = elems; +	ctrl->new_elems = elems; +	ctrl->p_array = p_array; +	ctrl->p_new.p = p_array; +	ctrl->p_cur.p = p_array + elems * ctrl->elem_size; +	for (i = 0; i < ctrl->nr_of_dims; i++) +		ctrl->dims[i] = dims[i]; +	ctrl->type_ops->init(ctrl, 0, ctrl->p_cur); +	cur_to_new(ctrl); +	send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_VALUE | +			       V4L2_EVENT_CTRL_CH_DIMENSIONS); +	return 0; +} +EXPORT_SYMBOL(__v4l2_ctrl_modify_dimensions); +  /* Implement VIDIOC_QUERY_EXT_CTRL */  int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)  {  |