aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c63
-rw-r--r--drivers/media/video/uvc/uvcvideo.h2
2 files changed, 39 insertions, 26 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0d310c42241..f169f773667 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -863,9 +863,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
863 unsigned int i; 863 unsigned int i;
864 int ret; 864 int ret;
865 865
866 ret = mutex_lock_interruptible(&chain->ctrl_mutex);
867 if (ret < 0)
868 return -ERESTARTSYS;
869
866 ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); 870 ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
867 if (ctrl == NULL) 871 if (ctrl == NULL) {
868 return -EINVAL; 872 ret = -EINVAL;
873 goto done;
874 }
869 875
870 memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); 876 memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
871 v4l2_ctrl->id = mapping->id; 877 v4l2_ctrl->id = mapping->id;
@@ -881,7 +887,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
881 if (!ctrl->cached) { 887 if (!ctrl->cached) {
882 ret = uvc_ctrl_populate_cache(chain, ctrl); 888 ret = uvc_ctrl_populate_cache(chain, ctrl);
883 if (ret < 0) 889 if (ret < 0)
884 return ret; 890 goto done;
885 } 891 }
886 892
887 if (ctrl->info.flags & UVC_CONTROL_GET_DEF) { 893 if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
@@ -903,19 +909,19 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
903 } 909 }
904 } 910 }
905 911
906 return 0; 912 goto done;
907 913
908 case V4L2_CTRL_TYPE_BOOLEAN: 914 case V4L2_CTRL_TYPE_BOOLEAN:
909 v4l2_ctrl->minimum = 0; 915 v4l2_ctrl->minimum = 0;
910 v4l2_ctrl->maximum = 1; 916 v4l2_ctrl->maximum = 1;
911 v4l2_ctrl->step = 1; 917 v4l2_ctrl->step = 1;
912 return 0; 918 goto done;
913 919
914 case V4L2_CTRL_TYPE_BUTTON: 920 case V4L2_CTRL_TYPE_BUTTON:
915 v4l2_ctrl->minimum = 0; 921 v4l2_ctrl->minimum = 0;
916 v4l2_ctrl->maximum = 0; 922 v4l2_ctrl->maximum = 0;
917 v4l2_ctrl->step = 0; 923 v4l2_ctrl->step = 0;
918 return 0; 924 goto done;
919 925
920 default: 926 default:
921 break; 927 break;
@@ -933,7 +939,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
933 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, 939 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
934 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 940 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
935 941
936 return 0; 942done:
943 mutex_unlock(&chain->ctrl_mutex);
944 return ret;
937} 945}
938 946
939 947
@@ -1295,6 +1303,7 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
1295 struct uvc_entity *entity; 1303 struct uvc_entity *entity;
1296 struct uvc_control *ctrl = NULL; 1304 struct uvc_control *ctrl = NULL;
1297 unsigned int i, found = 0; 1305 unsigned int i, found = 0;
1306 int restore = 0;
1298 __u8 *data; 1307 __u8 *data;
1299 int ret; 1308 int ret;
1300 1309
@@ -1326,44 +1335,48 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
1326 return -EINVAL; 1335 return -EINVAL;
1327 } 1336 }
1328 1337
1338 if (mutex_lock_interruptible(&chain->ctrl_mutex))
1339 return -ERESTARTSYS;
1340
1329 ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl); 1341 ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
1330 if (ret < 0) 1342 if (ret < 0) {
1331 return -ENOENT; 1343 ret = -ENOENT;
1344 goto done;
1345 }
1332 1346
1333 /* Validate control data size. */ 1347 /* Validate control data size. */
1334 if (ctrl->info.size != xctrl->size) 1348 if (ctrl->info.size != xctrl->size) {
1335 return -EINVAL; 1349 ret = -EINVAL;
1350 goto done;
1351 }
1336 1352
1337 if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) || 1353 if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
1338 (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) 1354 (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
1339 return -EINVAL; 1355 ret = -EINVAL;
1340 1356 goto done;
1341 if (mutex_lock_interruptible(&chain->ctrl_mutex)) 1357 }
1342 return -ERESTARTSYS;
1343 1358
1344 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1359 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1345 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1360 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1346 xctrl->size); 1361 ctrl->info.size);
1347 data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT); 1362 data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
1363 restore = set;
1348 1364
1349 if (set && copy_from_user(data, xctrl->data, xctrl->size)) { 1365 if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
1350 ret = -EFAULT; 1366 ret = -EFAULT;
1351 goto out; 1367 goto done;
1352 } 1368 }
1353 1369
1354 ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR, 1370 ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
1355 xctrl->unit, chain->dev->intfnum, xctrl->selector, 1371 xctrl->unit, chain->dev->intfnum, xctrl->selector,
1356 data, xctrl->size); 1372 data, xctrl->size);
1357 if (ret < 0) 1373 if (ret < 0)
1358 goto out; 1374 goto done;
1359 1375
1360 if (!set && copy_to_user(xctrl->data, data, xctrl->size)) { 1376 if (!set && copy_to_user(xctrl->data, data, xctrl->size))
1361 ret = -EFAULT; 1377 ret = -EFAULT;
1362 goto out; 1378done:
1363 } 1379 if (ret && restore)
1364
1365out:
1366 if (ret)
1367 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1380 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1368 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1381 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1369 xctrl->size); 1382 xctrl->size);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 7d67d95de83..d97cf6d6a4f 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -413,7 +413,7 @@ struct uvc_video_chain {
413 struct uvc_entity *processing; /* Processing unit */ 413 struct uvc_entity *processing; /* Processing unit */
414 struct uvc_entity *selector; /* Selector unit */ 414 struct uvc_entity *selector; /* Selector unit */
415 415
416 struct mutex ctrl_mutex; 416 struct mutex ctrl_mutex; /* Protects ctrl.info */
417}; 417};
418 418
419struct uvc_streaming { 419struct uvc_streaming {