| From cebbert@redhat.com Thu Oct 16 16:06:03 2008 |
| From: Laurent Pinchart <laurent.pinchart@skynet.be> |
| Date: Mon, 13 Oct 2008 19:33:49 -0400 |
| Subject: V4L/DVB (8617): uvcvideo: don't use stack-based buffers for USB transfers. |
| To: stable@kernel.org |
| Cc: Mauro Carvalho Chehab <mchehab@infradead.org> |
| Message-ID: <20081013193349.071ff299@redhat.com> |
| |
| From: Laurent Pinchart <laurent.pinchart@skynet.be> |
| |
| commit 04793dd041bbb88a39b768b714c725de2c339b51 upstream |
| |
| Data buffers on the stack are not allowed for USB I/O. Use dynamically |
| allocated buffers instead. |
| |
| Signed-off-by: Bruce Schmid <duck@freescale.com> |
| Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org> |
| Cc: Chuck Ebbert <cebbert@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/media/video/uvc/uvc_ctrl.c | 33 +++++++++++++++++++++------------ |
| drivers/media/video/uvc/uvc_video.c | 33 ++++++++++++++++++++++----------- |
| 2 files changed, 43 insertions(+), 23 deletions(-) |
| |
| --- a/drivers/media/video/uvc/uvc_ctrl.c |
| +++ b/drivers/media/video/uvc/uvc_ctrl.c |
| @@ -585,13 +585,17 @@ int uvc_query_v4l2_ctrl(struct uvc_video |
| struct uvc_control_mapping *mapping; |
| struct uvc_menu_info *menu; |
| unsigned int i; |
| - __u8 data[8]; |
| + __u8 *data; |
| int ret; |
| |
| ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); |
| if (ctrl == NULL) |
| return -EINVAL; |
| |
| + data = kmalloc(8, GFP_KERNEL); |
| + if (data == NULL) |
| + return -ENOMEM; |
| + |
| memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); |
| v4l2_ctrl->id = mapping->id; |
| v4l2_ctrl->type = mapping->v4l2_type; |
| @@ -604,8 +608,8 @@ int uvc_query_v4l2_ctrl(struct uvc_video |
| if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { |
| if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id, |
| video->dev->intfnum, ctrl->info->selector, |
| - &data, ctrl->info->size)) < 0) |
| - return ret; |
| + data, ctrl->info->size)) < 0) |
| + goto out; |
| v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); |
| } |
| |
| @@ -623,13 +627,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video |
| } |
| } |
| |
| - return 0; |
| + ret = 0; |
| + goto out; |
| |
| case V4L2_CTRL_TYPE_BOOLEAN: |
| v4l2_ctrl->minimum = 0; |
| v4l2_ctrl->maximum = 1; |
| v4l2_ctrl->step = 1; |
| - return 0; |
| + ret = 0; |
| + goto out; |
| |
| default: |
| break; |
| @@ -638,26 +644,29 @@ int uvc_query_v4l2_ctrl(struct uvc_video |
| if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { |
| if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id, |
| video->dev->intfnum, ctrl->info->selector, |
| - &data, ctrl->info->size)) < 0) |
| - return ret; |
| + data, ctrl->info->size)) < 0) |
| + goto out; |
| v4l2_ctrl->minimum = uvc_get_le_value(data, mapping); |
| } |
| if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { |
| if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, |
| video->dev->intfnum, ctrl->info->selector, |
| - &data, ctrl->info->size)) < 0) |
| - return ret; |
| + data, ctrl->info->size)) < 0) |
| + goto out; |
| v4l2_ctrl->maximum = uvc_get_le_value(data, mapping); |
| } |
| if (ctrl->info->flags & UVC_CONTROL_GET_RES) { |
| if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, |
| video->dev->intfnum, ctrl->info->selector, |
| - &data, ctrl->info->size)) < 0) |
| - return ret; |
| + data, ctrl->info->size)) < 0) |
| + goto out; |
| v4l2_ctrl->step = uvc_get_le_value(data, mapping); |
| } |
| |
| - return 0; |
| + ret = 0; |
| +out: |
| + kfree(data); |
| + return ret; |
| } |
| |
| |
| --- a/drivers/media/video/uvc/uvc_video.c |
| +++ b/drivers/media/video/uvc/uvc_video.c |
| @@ -90,17 +90,20 @@ static void uvc_fixup_buffer_size(struct |
| static int uvc_get_video_ctrl(struct uvc_video_device *video, |
| struct uvc_streaming_control *ctrl, int probe, __u8 query) |
| { |
| - __u8 data[34]; |
| - __u8 size; |
| + __u8 *data; |
| + __u16 size; |
| int ret; |
| |
| size = video->dev->uvc_version >= 0x0110 ? 34 : 26; |
| + data = kmalloc(size, GFP_KERNEL); |
| + if (data == NULL) |
| + return -ENOMEM; |
| + |
| ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, |
| - probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, |
| + probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, |
| UVC_CTRL_STREAMING_TIMEOUT); |
| - |
| if (ret < 0) |
| - return ret; |
| + goto out; |
| |
| ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); |
| ctrl->bFormatIndex = data[2]; |
| @@ -136,17 +139,22 @@ static int uvc_get_video_ctrl(struct uvc |
| */ |
| uvc_fixup_buffer_size(video, ctrl); |
| |
| - return 0; |
| +out: |
| + kfree(data); |
| + return ret; |
| } |
| |
| int uvc_set_video_ctrl(struct uvc_video_device *video, |
| struct uvc_streaming_control *ctrl, int probe) |
| { |
| - __u8 data[34]; |
| - __u8 size; |
| + __u8 *data; |
| + __u16 size; |
| + int ret; |
| |
| size = video->dev->uvc_version >= 0x0110 ? 34 : 26; |
| - memset(data, 0, sizeof data); |
| + data = kzalloc(size, GFP_KERNEL); |
| + if (data == NULL) |
| + return -ENOMEM; |
| |
| *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); |
| data[2] = ctrl->bFormatIndex; |
| @@ -174,10 +182,13 @@ int uvc_set_video_ctrl(struct uvc_video_ |
| data[33] = ctrl->bMaxVersion; |
| } |
| |
| - return __uvc_query_ctrl(video->dev, SET_CUR, 0, |
| + ret = __uvc_query_ctrl(video->dev, SET_CUR, 0, |
| video->streaming->intfnum, |
| - probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, |
| + probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, |
| UVC_CTRL_STREAMING_TIMEOUT); |
| + |
| + kfree(data); |
| + return ret; |
| } |
| |
| int uvc_probe_video(struct uvc_video_device *video, |