diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2010-11-21 05:58:54 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-01 17:10:21 -0500 |
commit | 23d9f3ef23f0dc4bb20ccd5540b9a91ff08da08f (patch) | |
tree | a290f5b2d0bcf6553e0bfae598d86ecf09e31bac /drivers | |
parent | ca9afe6f87b569cdf8e797395381f18ae23a2905 (diff) |
[media] uvcvideo: Lock controls mutex when querying menus
uvc_find_control() must be called with the controls mutex locked. Fix
uvc_query_v4l2_menu() accordingly.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/uvc/uvc_ctrl.c | 48 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 36 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 4 |
3 files changed, 50 insertions, 38 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f169f7736677..59f8a9ad3796 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, | |||
785 | } | 785 | } |
786 | } | 786 | } |
787 | 787 | ||
788 | struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, | 788 | static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, |
789 | __u32 v4l2_id, struct uvc_control_mapping **mapping) | 789 | __u32 v4l2_id, struct uvc_control_mapping **mapping) |
790 | { | 790 | { |
791 | struct uvc_control *ctrl = NULL; | 791 | struct uvc_control *ctrl = NULL; |
@@ -944,6 +944,52 @@ done: | |||
944 | return ret; | 944 | return ret; |
945 | } | 945 | } |
946 | 946 | ||
947 | /* | ||
948 | * Mapping V4L2 controls to UVC controls can be straighforward if done well. | ||
949 | * Most of the UVC controls exist in V4L2, and can be mapped directly. Some | ||
950 | * must be grouped (for instance the Red Balance, Blue Balance and Do White | ||
951 | * Balance V4L2 controls use the White Balance Component UVC control) or | ||
952 | * otherwise translated. The approach we take here is to use a translation | ||
953 | * table for the controls that can be mapped directly, and handle the others | ||
954 | * manually. | ||
955 | */ | ||
956 | int uvc_query_v4l2_menu(struct uvc_video_chain *chain, | ||
957 | struct v4l2_querymenu *query_menu) | ||
958 | { | ||
959 | struct uvc_menu_info *menu_info; | ||
960 | struct uvc_control_mapping *mapping; | ||
961 | struct uvc_control *ctrl; | ||
962 | u32 index = query_menu->index; | ||
963 | u32 id = query_menu->id; | ||
964 | int ret; | ||
965 | |||
966 | memset(query_menu, 0, sizeof(*query_menu)); | ||
967 | query_menu->id = id; | ||
968 | query_menu->index = index; | ||
969 | |||
970 | ret = mutex_lock_interruptible(&chain->ctrl_mutex); | ||
971 | if (ret < 0) | ||
972 | return -ERESTARTSYS; | ||
973 | |||
974 | ctrl = uvc_find_control(chain, query_menu->id, &mapping); | ||
975 | if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { | ||
976 | ret = -EINVAL; | ||
977 | goto done; | ||
978 | } | ||
979 | |||
980 | if (query_menu->index >= mapping->menu_count) { | ||
981 | ret = -EINVAL; | ||
982 | goto done; | ||
983 | } | ||
984 | |||
985 | menu_info = &mapping->menu_info[query_menu->index]; | ||
986 | strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); | ||
987 | |||
988 | done: | ||
989 | mutex_unlock(&chain->ctrl_mutex); | ||
990 | return ret; | ||
991 | } | ||
992 | |||
947 | 993 | ||
948 | /* -------------------------------------------------------------------------- | 994 | /* -------------------------------------------------------------------------- |
949 | * Control transactions | 995 | * Control transactions |
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 6d15de9b5204..0f865e97cf48 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -101,40 +101,6 @@ done: | |||
101 | */ | 101 | */ |
102 | 102 | ||
103 | /* | 103 | /* |
104 | * Mapping V4L2 controls to UVC controls can be straighforward if done well. | ||
105 | * Most of the UVC controls exist in V4L2, and can be mapped directly. Some | ||
106 | * must be grouped (for instance the Red Balance, Blue Balance and Do White | ||
107 | * Balance V4L2 controls use the White Balance Component UVC control) or | ||
108 | * otherwise translated. The approach we take here is to use a translation | ||
109 | * table for the controls that can be mapped directly, and handle the others | ||
110 | * manually. | ||
111 | */ | ||
112 | static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, | ||
113 | struct v4l2_querymenu *query_menu) | ||
114 | { | ||
115 | struct uvc_menu_info *menu_info; | ||
116 | struct uvc_control_mapping *mapping; | ||
117 | struct uvc_control *ctrl; | ||
118 | u32 index = query_menu->index; | ||
119 | u32 id = query_menu->id; | ||
120 | |||
121 | ctrl = uvc_find_control(chain, query_menu->id, &mapping); | ||
122 | if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) | ||
123 | return -EINVAL; | ||
124 | |||
125 | if (query_menu->index >= mapping->menu_count) | ||
126 | return -EINVAL; | ||
127 | |||
128 | memset(query_menu, 0, sizeof(*query_menu)); | ||
129 | query_menu->id = id; | ||
130 | query_menu->index = index; | ||
131 | |||
132 | menu_info = &mapping->menu_info[query_menu->index]; | ||
133 | strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Find the frame interval closest to the requested frame interval for the | 104 | * Find the frame interval closest to the requested frame interval for the |
139 | * given frame format and size. This should be done by the device as part of | 105 | * given frame format and size. This should be done by the device as part of |
140 | * the Video Probe and Commit negotiation, but some hardware don't implement | 106 | * the Video Probe and Commit negotiation, but some hardware don't implement |
@@ -624,7 +590,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
624 | } | 590 | } |
625 | 591 | ||
626 | case VIDIOC_QUERYMENU: | 592 | case VIDIOC_QUERYMENU: |
627 | return uvc_v4l2_query_menu(chain, arg); | 593 | return uvc_query_v4l2_menu(chain, arg); |
628 | 594 | ||
629 | case VIDIOC_G_EXT_CTRLS: | 595 | case VIDIOC_G_EXT_CTRLS: |
630 | { | 596 | { |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index d97cf6d6a4f9..45209245244b 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -606,10 +606,10 @@ extern int uvc_status_suspend(struct uvc_device *dev); | |||
606 | extern int uvc_status_resume(struct uvc_device *dev); | 606 | extern int uvc_status_resume(struct uvc_device *dev); |
607 | 607 | ||
608 | /* Controls */ | 608 | /* Controls */ |
609 | extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, | ||
610 | __u32 v4l2_id, struct uvc_control_mapping **mapping); | ||
611 | extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | 609 | extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, |
612 | struct v4l2_queryctrl *v4l2_ctrl); | 610 | struct v4l2_queryctrl *v4l2_ctrl); |
611 | extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, | ||
612 | struct v4l2_querymenu *query_menu); | ||
613 | 613 | ||
614 | extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, | 614 | extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, |
615 | const struct uvc_control_mapping *mapping); | 615 | const struct uvc_control_mapping *mapping); |