diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c2ee6e3..6e33bd0 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -366,58 +366,82 @@
 	{ 8, "Aperture Priority Mode" },
 };
 
-static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
-	__u8 query, const __u8 *data)
+static void uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
+	__u8 query, const __u8 *data, void *value, size_t size)
 {
 	__s8 zoom = (__s8)data[0];
+	__s32 *result = value;
+
+	if (unlikely(size != sizeof(*result))) {
+		/* At least make sure not to return random kernel bytes */
+		memset(value, 0, size);
+		return;
+	}
 
 	switch (query) {
 	case UVC_GET_CUR:
-		return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
-
+		*result = (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
+		break;
 	case UVC_GET_MIN:
 	case UVC_GET_MAX:
 	case UVC_GET_RES:
 	case UVC_GET_DEF:
 	default:
-		return data[2];
+		*result = data[2];
 	}
 }
 
 static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
-	__s32 value, __u8 *data)
+	__u8 *data, const void *value, size_t size)
 {
-	data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
-	data[2] = min((int)abs(value), 0xff);
+	const __s32 *value32 = value;
+
+	if (unlikely(size != sizeof(*value32)))
+		return;
+
+	data[0] = *value32 == 0 ? 0 : (*value32 > 0) ? 1 : 0xff;
+	data[2] = min((int)abs(*value32), 0xff);
 }
 
-static __s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
-	__u8 query, const __u8 *data)
+static void uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
+	__u8 query, const __u8 *data, void *value, size_t size)
 {
 	unsigned int first = mapping->offset / 8;
 	__s8 rel = (__s8)data[first];
+	__s32 *result = value;
+
+	if (unlikely(size != sizeof(*result))) {
+		memset(value, 0, size);
+		return;
+	}
 
 	switch (query) {
 	case UVC_GET_CUR:
-		return (rel == 0) ? 0 : (rel > 0 ? data[first+1]
+		*result = (rel == 0) ? 0 : (rel > 0 ? data[first+1]
 						 : -data[first+1]);
+		break;
 	case UVC_GET_MIN:
-		return -data[first+1];
+		*result = -data[first+1];
+		break;
 	case UVC_GET_MAX:
 	case UVC_GET_RES:
 	case UVC_GET_DEF:
 	default:
-		return data[first+1];
+		*result = data[first+1];
 	}
 }
 
 static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
-	__s32 value, __u8 *data)
+	__u8 *data, const void *value, size_t size)
 {
+	const __s32 *value32 = value;
 	unsigned int first = mapping->offset / 8;
 
-	data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
-	data[first+1] = min_t(int, abs(value), 0xff);
+	if (unlikely(size != sizeof(*value32)))
+		return;
+
+	data[first] = *value32 == 0 ? 0 : (*value32 > 0) ? 1 : 0xff;
+	data[first+1] = min_t(int, abs(*value32), 0xff);
 }
 
 static struct uvc_control_mapping uvc_ctrl_mappings[] = {
@@ -765,21 +789,27 @@ static inline void uvc_clear_bit(__u8 *data, int bit)
  * a signed 32bit integer. Sign extension will be performed if the mapping
  * references a signed data type.
  */
-static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
-	__u8 query, const __u8 *data)
+static void uvc_get_le_value(struct uvc_control_mapping *mapping,
+	__u8 query, const __u8 *data, void *value, size_t size)
 {
 	int bits = mapping->size;
 	int offset = mapping->offset;
-	__s32 value = 0;
+	__s32 *result = value;
 	__u8 mask;
 
+	if (unlikely(size != sizeof(*result))) {
+		memset(value, 0, size);
+		return;
+	}
+
 	data += offset / 8;
 	offset &= 7;
 	mask = ((1LL << bits) - 1) << offset;
+	*result = 0;
 
 	for (; bits > 0; data++) {
 		__u8 byte = *data & mask;
-		value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
+		*result |= offset > 0 ? (byte >> offset) : (byte << (-offset));
 		bits -= 8 - (offset > 0 ? offset : 0);
 		offset -= 8;
 		mask = (1 << bits) - 1;
@@ -787,36 +817,40 @@ static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
 
 	/* Sign-extend the value if needed. */
 	if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
-		value |= -(value & (1 << (mapping->size - 1)));
-
-	return value;
+		*result |= -(*result & (1 << (mapping->size - 1)));
 }
 
 /* Set the bit string specified by mapping->offset and mapping->size
  * in the little-endian data stored at 'data' to the value 'value'.
  */
 static void uvc_set_le_value(struct uvc_control_mapping *mapping,
-	__s32 value, __u8 *data)
+	__u8 *data, const void *value, size_t size)
 {
 	int bits = mapping->size;
 	int offset = mapping->offset;
+	__s32 value32;
 	__u8 mask;
 
+	if (unlikely(size != sizeof(value32)))
+		return;
+
+	value32 = *(const __s32 *)value;
+
 	/* According to the v4l2 spec, writing any value to a button control
 	 * should result in the action belonging to the button control being
 	 * triggered. UVC devices however want to see a 1 written -> override
 	 * value.
 	 */
 	if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
-		value = -1;
+		value32 = -1;
 
 	data += offset / 8;
 	offset &= 7;
 
 	for (; bits > 0; data++) {
 		mask = ((1LL << bits) - 1) << offset;
-		*data = (*data & ~mask) | ((value << offset) & mask);
-		value >>= offset ? offset : 8;
+		*data = (*data & ~mask) | ((value32 << offset) & mask);
+		value32 >>= offset ? offset : 8;
 		bits -= 8 - offset;
 		offset = 0;
 	}
@@ -993,8 +1027,9 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
 		ctrl->loaded = 1;
 	}
 
-	*value = mapping->get(mapping, UVC_GET_CUR,
-		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+	mapping->get(mapping, UVC_GET_CUR,
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		value, sizeof(*value));
 
 	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
 		menu = mapping->menu_info;
@@ -1050,8 +1085,10 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	}
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
-		v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
-				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
+		mapping->get(mapping, UVC_GET_DEF,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
+			     &v4l2_ctrl->default_value,
+			     sizeof(v4l2_ctrl->default_value));
 	}
 
 	switch (mapping->v4l2_type) {
@@ -1087,16 +1124,19 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 	}
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
-		v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
-				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+		mapping->get(mapping, UVC_GET_MIN,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+			     &v4l2_ctrl->minimum, sizeof(v4l2_ctrl->minimum));
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
-		v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
-				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+		mapping->get(mapping, UVC_GET_MAX,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+			     &v4l2_ctrl->maximum, sizeof(v4l2_ctrl->maximum));
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
-		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
-				  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+		mapping->get(mapping, UVC_GET_RES,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+			     &v4l2_ctrl->step, sizeof(v4l2_ctrl->step));
 
 	return 0;
 }
@@ -1174,8 +1214,9 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 				goto done;
 		}
 
-		bitmap = mapping->get(mapping, UVC_GET_RES,
-				      uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+		mapping->get(mapping, UVC_GET_RES,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+			     &bitmap, sizeof(bitmap));
 		if (!(bitmap & menu_info->value)) {
 			ret = -EINVAL;
 			goto done;
@@ -1498,12 +1539,15 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
 				return ret;
 		}
 
-		min = mapping->get(mapping, UVC_GET_MIN,
-				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
-		max = mapping->get(mapping, UVC_GET_MAX,
-				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
-		step = mapping->get(mapping, UVC_GET_RES,
-				    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+		mapping->get(mapping, UVC_GET_MIN,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+			     &min, sizeof(min));
+		mapping->get(mapping, UVC_GET_MAX,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+			     &max, sizeof(max));
+		mapping->get(mapping, UVC_GET_RES,
+			     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+			     &step, sizeof(step));
 		if (step == 0)
 			step = 1;
 
@@ -1537,8 +1581,9 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
 					return ret;
 			}
 
-			step = mapping->get(mapping, UVC_GET_RES,
-					uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+			mapping->get(mapping, UVC_GET_RES,
+				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+				     &step, sizeof(step));
 			if (!(step & value))
 				return -EINVAL;
 		}
@@ -1578,8 +1623,8 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
 		       ctrl->info.size);
 	}
 
-	mapping->set(mapping, value,
-		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+	mapping->set(mapping, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		     &value, sizeof(value));
 
 	ctrl->dirty = 1;
 	ctrl->modified = 1;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 4205e7a..47a42f6 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -222,10 +222,10 @@ struct uvc_control_mapping {
 	__s32 master_manual;
 	__u32 slave_ids[2];
 
-	__s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
-		      const __u8 *data);
-	void (*set) (struct uvc_control_mapping *mapping, __s32 value,
-		     __u8 *data);
+	void (*get) (struct uvc_control_mapping *mapping, __u8 query,
+		     const __u8 *data, void *value, size_t size);
+	void (*set) (struct uvc_control_mapping *mapping,
+		     __u8 *data, const void *value, size_t size);
 };
 
 struct uvc_control {
