aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc/uvc_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc/uvc_ctrl.c')
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c242
1 files changed, 149 insertions, 93 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index ec8ef8c5560a..3b2e7800d56f 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -23,9 +23,13 @@
23 23
24#include "uvcvideo.h" 24#include "uvcvideo.h"
25 25
26#define UVC_CTRL_NDATA 2
27#define UVC_CTRL_DATA_CURRENT 0 26#define UVC_CTRL_DATA_CURRENT 0
28#define UVC_CTRL_DATA_BACKUP 1 27#define UVC_CTRL_DATA_BACKUP 1
28#define UVC_CTRL_DATA_MIN 2
29#define UVC_CTRL_DATA_MAX 3
30#define UVC_CTRL_DATA_RES 4
31#define UVC_CTRL_DATA_DEF 5
32#define UVC_CTRL_DATA_LAST 6
29 33
30/* ------------------------------------------------------------------------ 34/* ------------------------------------------------------------------------
31 * Controls 35 * Controls
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
755 return ctrl; 759 return ctrl;
756} 760}
757 761
762static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
763 struct uvc_control *ctrl)
764{
765 int ret;
766
767 if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
768 ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
769 chain->dev->intfnum, ctrl->info->selector,
770 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
771 ctrl->info->size);
772 if (ret < 0)
773 return ret;
774 }
775
776 if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
777 ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
778 chain->dev->intfnum, ctrl->info->selector,
779 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
780 ctrl->info->size);
781 if (ret < 0)
782 return ret;
783 }
784 if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
785 ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
786 chain->dev->intfnum, ctrl->info->selector,
787 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
788 ctrl->info->size);
789 if (ret < 0)
790 return ret;
791 }
792 if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
793 ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
794 chain->dev->intfnum, ctrl->info->selector,
795 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
796 ctrl->info->size);
797 if (ret < 0)
798 return ret;
799 }
800
801 ctrl->cached = 1;
802 return 0;
803}
804
758int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, 805int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
759 struct v4l2_queryctrl *v4l2_ctrl) 806 struct v4l2_queryctrl *v4l2_ctrl)
760{ 807{
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
762 struct uvc_control_mapping *mapping; 809 struct uvc_control_mapping *mapping;
763 struct uvc_menu_info *menu; 810 struct uvc_menu_info *menu;
764 unsigned int i; 811 unsigned int i;
765 __u8 *data;
766 int ret; 812 int ret;
767 813
768 ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); 814 ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
769 if (ctrl == NULL) 815 if (ctrl == NULL)
770 return -EINVAL; 816 return -EINVAL;
771 817
772 data = kmalloc(ctrl->info->size, GFP_KERNEL);
773 if (data == NULL)
774 return -ENOMEM;
775
776 memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); 818 memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
777 v4l2_ctrl->id = mapping->id; 819 v4l2_ctrl->id = mapping->id;
778 v4l2_ctrl->type = mapping->v4l2_type; 820 v4l2_ctrl->type = mapping->v4l2_type;
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
782 if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR)) 824 if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
783 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 825 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
784 826
785 if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { 827 if (!ctrl->cached) {
786 ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, 828 ret = uvc_ctrl_populate_cache(chain, ctrl);
787 chain->dev->intfnum, ctrl->info->selector,
788 data, ctrl->info->size);
789 if (ret < 0) 829 if (ret < 0)
790 goto out; 830 return ret;
791 v4l2_ctrl->default_value = 831 }
792 mapping->get(mapping, UVC_GET_DEF, data); 832
833 if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
834 v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
835 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
793 } 836 }
794 837
795 switch (mapping->v4l2_type) { 838 switch (mapping->v4l2_type) {
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
806 } 849 }
807 } 850 }
808 851
809 ret = 0; 852 return 0;
810 goto out;
811 853
812 case V4L2_CTRL_TYPE_BOOLEAN: 854 case V4L2_CTRL_TYPE_BOOLEAN:
813 v4l2_ctrl->minimum = 0; 855 v4l2_ctrl->minimum = 0;
814 v4l2_ctrl->maximum = 1; 856 v4l2_ctrl->maximum = 1;
815 v4l2_ctrl->step = 1; 857 v4l2_ctrl->step = 1;
816 ret = 0; 858 return 0;
817 goto out;
818 859
819 case V4L2_CTRL_TYPE_BUTTON: 860 case V4L2_CTRL_TYPE_BUTTON:
820 v4l2_ctrl->minimum = 0; 861 v4l2_ctrl->minimum = 0;
821 v4l2_ctrl->maximum = 0; 862 v4l2_ctrl->maximum = 0;
822 v4l2_ctrl->step = 0; 863 v4l2_ctrl->step = 0;
823 ret = 0; 864 return 0;
824 goto out;
825 865
826 default: 866 default:
827 break; 867 break;
828 } 868 }
829 869
830 if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { 870 if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
831 ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, 871 v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
832 chain->dev->intfnum, ctrl->info->selector, 872 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
833 data, ctrl->info->size);
834 if (ret < 0)
835 goto out;
836 v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
837 }
838 if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
839 ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
840 chain->dev->intfnum, ctrl->info->selector,
841 data, ctrl->info->size);
842 if (ret < 0)
843 goto out;
844 v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
845 }
846 if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
847 ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
848 chain->dev->intfnum, ctrl->info->selector,
849 data, ctrl->info->size);
850 if (ret < 0)
851 goto out;
852 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
853 }
854 873
855 ret = 0; 874 if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
856out: 875 v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
857 kfree(data); 876 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
858 return ret; 877
878 if (ctrl->info->flags & UVC_CONTROL_GET_RES)
879 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
880 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
881
882 return 0;
859} 883}
860 884
861 885
@@ -997,19 +1021,57 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
997{ 1021{
998 struct uvc_control *ctrl; 1022 struct uvc_control *ctrl;
999 struct uvc_control_mapping *mapping; 1023 struct uvc_control_mapping *mapping;
1000 s32 value = xctrl->value; 1024 s32 value;
1025 u32 step;
1026 s32 min;
1027 s32 max;
1001 int ret; 1028 int ret;
1002 1029
1003 ctrl = uvc_find_control(chain, xctrl->id, &mapping); 1030 ctrl = uvc_find_control(chain, xctrl->id, &mapping);
1004 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) 1031 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
1005 return -EINVAL; 1032 return -EINVAL;
1006 1033
1007 if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { 1034 /* Clamp out of range values. */
1008 if (value < 0 || value >= mapping->menu_count) 1035 switch (mapping->v4l2_type) {
1009 return -EINVAL; 1036 case V4L2_CTRL_TYPE_INTEGER:
1010 value = mapping->menu_info[value].value; 1037 if (!ctrl->cached) {
1038 ret = uvc_ctrl_populate_cache(chain, ctrl);
1039 if (ret < 0)
1040 return ret;
1041 }
1042
1043 min = mapping->get(mapping, UVC_GET_MIN,
1044 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
1045 max = mapping->get(mapping, UVC_GET_MAX,
1046 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
1047 step = mapping->get(mapping, UVC_GET_RES,
1048 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
1049
1050 xctrl->value = min + (xctrl->value - min + step/2) / step * step;
1051 xctrl->value = clamp(xctrl->value, min, max);
1052 value = xctrl->value;
1053 break;
1054
1055 case V4L2_CTRL_TYPE_BOOLEAN:
1056 xctrl->value = clamp(xctrl->value, 0, 1);
1057 value = xctrl->value;
1058 break;
1059
1060 case V4L2_CTRL_TYPE_MENU:
1061 if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
1062 return -ERANGE;
1063 value = mapping->menu_info[xctrl->value].value;
1064 break;
1065
1066 default:
1067 value = xctrl->value;
1068 break;
1011 } 1069 }
1012 1070
1071 /* If the mapping doesn't span the whole UVC control, the current value
1072 * needs to be loaded from the device to perform the read-modify-write
1073 * operation.
1074 */
1013 if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) { 1075 if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
1014 if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) { 1076 if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
1015 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1077 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1027,6 +1089,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1027 ctrl->loaded = 1; 1089 ctrl->loaded = 1;
1028 } 1090 }
1029 1091
1092 /* Backup the current value in case we need to rollback later. */
1030 if (!ctrl->dirty) { 1093 if (!ctrl->dirty) {
1031 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1094 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1032 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1095 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1080,10 +1143,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
1080 } 1143 }
1081 1144
1082 if (!found) { 1145 if (!found) {
1083 uvc_trace(UVC_TRACE_CONTROL, 1146 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
1084 "Control " UVC_GUID_FORMAT "/%u not found.\n", 1147 entity->extension.guidExtensionCode, xctrl->selector);
1085 UVC_GUID_ARGS(entity->extension.guidExtensionCode),
1086 xctrl->selector);
1087 return -EINVAL; 1148 return -EINVAL;
1088 } 1149 }
1089 1150
@@ -1159,9 +1220,9 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
1159 (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0) 1220 (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
1160 continue; 1221 continue;
1161 1222
1162 printk(KERN_INFO "restoring control " UVC_GUID_FORMAT 1223 printk(KERN_INFO "restoring control %pUl/%u/%u\n",
1163 "/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity), 1224 ctrl->info->entity, ctrl->info->index,
1164 ctrl->info->index, ctrl->info->selector); 1225 ctrl->info->selector);
1165 ctrl->dirty = 1; 1226 ctrl->dirty = 1;
1166 } 1227 }
1167 1228
@@ -1215,47 +1276,43 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
1215 ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, 1276 ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
1216 dev->intfnum, info->selector, (__u8 *)&size, 2); 1277 dev->intfnum, info->selector, (__u8 *)&size, 2);
1217 if (ret < 0) { 1278 if (ret < 0) {
1218 uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on " 1279 uvc_trace(UVC_TRACE_CONTROL,
1219 "control " UVC_GUID_FORMAT "/%u (%d).\n", 1280 "GET_LEN failed on control %pUl/%u (%d).\n",
1220 UVC_GUID_ARGS(info->entity), info->selector, 1281 info->entity, info->selector, ret);
1221 ret);
1222 return; 1282 return;
1223 } 1283 }
1224 1284
1225 if (info->size != le16_to_cpu(size)) { 1285 if (info->size != le16_to_cpu(size)) {
1226 uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT 1286 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
1227 "/%u size doesn't match user supplied " 1287 "doesn't match user supplied value.\n",
1228 "value.\n", UVC_GUID_ARGS(info->entity), 1288 info->entity, info->selector);
1229 info->selector);
1230 return; 1289 return;
1231 } 1290 }
1232 1291
1233 ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, 1292 ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
1234 dev->intfnum, info->selector, &inf, 1); 1293 dev->intfnum, info->selector, &inf, 1);
1235 if (ret < 0) { 1294 if (ret < 0) {
1236 uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on " 1295 uvc_trace(UVC_TRACE_CONTROL,
1237 "control " UVC_GUID_FORMAT "/%u (%d).\n", 1296 "GET_INFO failed on control %pUl/%u (%d).\n",
1238 UVC_GUID_ARGS(info->entity), info->selector, 1297 info->entity, info->selector, ret);
1239 ret);
1240 return; 1298 return;
1241 } 1299 }
1242 1300
1243 flags = info->flags; 1301 flags = info->flags;
1244 if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) || 1302 if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
1245 ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) { 1303 ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
1246 uvc_trace(UVC_TRACE_CONTROL, "Control " 1304 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
1247 UVC_GUID_FORMAT "/%u flags don't match " 1305 "don't match supported operations.\n",
1248 "supported operations.\n", 1306 info->entity, info->selector);
1249 UVC_GUID_ARGS(info->entity), info->selector);
1250 return; 1307 return;
1251 } 1308 }
1252 } 1309 }
1253 1310
1254 ctrl->info = info; 1311 ctrl->info = info;
1255 ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL); 1312 ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
1256 uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u " 1313 uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
1257 "to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity), 1314 "entity %u\n", ctrl->info->entity, ctrl->info->selector,
1258 ctrl->info->selector, dev->udev->devpath, entity->id); 1315 dev->udev->devpath, entity->id);
1259} 1316}
1260 1317
1261/* 1318/*
@@ -1281,17 +1338,16 @@ int uvc_ctrl_add_info(struct uvc_control_info *info)
1281 continue; 1338 continue;
1282 1339
1283 if (ctrl->selector == info->selector) { 1340 if (ctrl->selector == info->selector) {
1284 uvc_trace(UVC_TRACE_CONTROL, "Control " 1341 uvc_trace(UVC_TRACE_CONTROL,
1285 UVC_GUID_FORMAT "/%u is already defined.\n", 1342 "Control %pUl/%u is already defined.\n",
1286 UVC_GUID_ARGS(info->entity), info->selector); 1343 info->entity, info->selector);
1287 ret = -EEXIST; 1344 ret = -EEXIST;
1288 goto end; 1345 goto end;
1289 } 1346 }
1290 if (ctrl->index == info->index) { 1347 if (ctrl->index == info->index) {
1291 uvc_trace(UVC_TRACE_CONTROL, "Control " 1348 uvc_trace(UVC_TRACE_CONTROL,
1292 UVC_GUID_FORMAT "/%u would overwrite index " 1349 "Control %pUl/%u would overwrite index %d.\n",
1293 "%d.\n", UVC_GUID_ARGS(info->entity), 1350 info->entity, info->selector, info->index);
1294 info->selector, info->index);
1295 ret = -EEXIST; 1351 ret = -EEXIST;
1296 goto end; 1352 goto end;
1297 } 1353 }
@@ -1332,10 +1388,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
1332 continue; 1388 continue;
1333 1389
1334 if (info->size * 8 < mapping->size + mapping->offset) { 1390 if (info->size * 8 < mapping->size + mapping->offset) {
1335 uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would " 1391 uvc_trace(UVC_TRACE_CONTROL,
1336 "overflow control " UVC_GUID_FORMAT "/%u\n", 1392 "Mapping '%s' would overflow control %pUl/%u\n",
1337 mapping->name, UVC_GUID_ARGS(info->entity), 1393 mapping->name, info->entity, info->selector);
1338 info->selector);
1339 ret = -EOVERFLOW; 1394 ret = -EOVERFLOW;
1340 goto end; 1395 goto end;
1341 } 1396 }
@@ -1354,9 +1409,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
1354 1409
1355 mapping->ctrl = info; 1410 mapping->ctrl = info;
1356 list_add_tail(&mapping->list, &info->mappings); 1411 list_add_tail(&mapping->list, &info->mappings);
1357 uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control " 1412 uvc_trace(UVC_TRACE_CONTROL,
1358 UVC_GUID_FORMAT "/%u.\n", mapping->name, 1413 "Adding mapping %s to control %pUl/%u.\n",
1359 UVC_GUID_ARGS(info->entity), info->selector); 1414 mapping->name, info->entity, info->selector);
1360 1415
1361 ret = 0; 1416 ret = 0;
1362 break; 1417 break;
@@ -1378,6 +1433,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
1378 struct usb_device_id id; 1433 struct usb_device_id id;
1379 u8 index; 1434 u8 index;
1380 } blacklist[] = { 1435 } blacklist[] = {
1436 { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
1381 { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */ 1437 { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
1382 { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */ 1438 { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
1383 }; 1439 };