Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: uvcvideo: Support any size for mapping get/set

Right now, we only support mappings for v4l2 controls with a max size of
s32. This patch modifies the prototype of get/set so it can support any
size.

This is done to prepare for compound controls.

Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Yunke Cao <yunkec@google.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Tested-by: Yunke Cao <yunkec@google.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Link: https://lore.kernel.org/r/20250203-uvc-roi-v17-8-5900a9fed613@chromium.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>

authored by

Ricardo Ribalda and committed by
Hans Verkuil
4e15c535 66dcae2c

+130 -59
+126 -55
drivers/media/usb/uvc/uvc_ctrl.c
··· 367 367 368 368 static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; 369 369 370 + static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping, 371 + u8 query, const void *data_in) 372 + { 373 + s32 data_out = 0; 374 + 375 + mapping->get(mapping, query, data_in, sizeof(data_out), &data_out); 376 + 377 + return data_out; 378 + } 379 + 380 + static void uvc_mapping_set_s32(struct uvc_control_mapping *mapping, 381 + s32 data_in, void *data_out) 382 + { 383 + mapping->set(mapping, sizeof(data_in), &data_in, data_out); 384 + } 385 + 370 386 /* 371 387 * This function translates the V4L2 menu index @idx, as exposed to userspace as 372 388 * the V4L2 control value, to the corresponding UVC control value used by the ··· 421 405 return v4l2_ctrl_get_menu(mapping->id)[idx]; 422 406 } 423 407 424 - static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, 425 - u8 query, const u8 *data) 408 + static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query, 409 + const void *uvc_in, size_t v4l2_size, 410 + void *v4l2_out) 426 411 { 427 - s8 zoom = (s8)data[0]; 412 + u8 value = ((u8 *)uvc_in)[2]; 413 + s8 sign = ((s8 *)uvc_in)[0]; 414 + s32 *out = v4l2_out; 415 + 416 + if (WARN_ON(v4l2_size != sizeof(s32))) 417 + return -EINVAL; 428 418 429 419 switch (query) { 430 420 case UVC_GET_CUR: 431 - return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); 421 + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value); 422 + return 0; 432 423 433 424 case UVC_GET_MIN: 434 425 case UVC_GET_MAX: 435 426 case UVC_GET_RES: 436 427 case UVC_GET_DEF: 437 428 default: 438 - return data[2]; 429 + *out = value; 430 + return 0; 439 431 } 440 432 } 441 433 442 - static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, 443 - s32 value, u8 *data) 434 + static int uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, 435 + size_t v4l2_size, const void *v4l2_in, 436 + void *uvc_out) 444 437 { 445 - data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 446 - data[2] = min((int)abs(value), 0xff); 438 + u8 *out = uvc_out; 439 + s32 value; 440 + 441 + if (WARN_ON(v4l2_size != sizeof(s32))) 442 + return -EINVAL; 443 + 444 + value = *(u32 *)v4l2_in; 445 + out[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 446 + out[2] = min_t(int, abs(value), 0xff); 447 + 448 + return 0; 447 449 } 448 450 449 - static s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, 450 - u8 query, const u8 *data) 451 + static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, 452 + u8 query, const void *uvc_in, 453 + size_t v4l2_size, void *v4l2_out) 451 454 { 452 455 unsigned int first = mapping->offset / 8; 453 - s8 rel = (s8)data[first]; 456 + u8 value = ((u8 *)uvc_in)[first + 1]; 457 + s8 sign = ((s8 *)uvc_in)[first]; 458 + s32 *out = v4l2_out; 459 + 460 + if (WARN_ON(v4l2_size != sizeof(s32))) 461 + return -EINVAL; 454 462 455 463 switch (query) { 456 464 case UVC_GET_CUR: 457 - return (rel == 0) ? 0 : (rel > 0 ? data[first+1] 458 - : -data[first+1]); 465 + *out = (sign == 0) ? 0 : (sign > 0 ? value : -value); 466 + return 0; 459 467 case UVC_GET_MIN: 460 - return -data[first+1]; 468 + *out = -value; 469 + return 0; 461 470 case UVC_GET_MAX: 462 471 case UVC_GET_RES: 463 472 case UVC_GET_DEF: 464 473 default: 465 - return data[first+1]; 474 + *out = value; 475 + return 0; 466 476 } 467 477 } 468 478 469 - static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, 470 - s32 value, u8 *data) 479 + static int uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, 480 + size_t v4l2_size, const void *v4l2_in, 481 + void *uvc_out) 471 482 { 472 483 unsigned int first = mapping->offset / 8; 484 + u8 *out = uvc_out; 485 + s32 value; 473 486 474 - data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 475 - data[first+1] = min_t(int, abs(value), 0xff); 487 + if (WARN_ON(v4l2_size != sizeof(s32))) 488 + return -EINVAL; 489 + 490 + value = *(u32 *)v4l2_in; 491 + out[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 492 + out[first + 1] = min_t(int, abs(value), 0xff); 493 + 494 + return 0; 476 495 } 477 496 478 497 static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { ··· 938 887 * a signed 32bit integer. Sign extension will be performed if the mapping 939 888 * references a signed data type. 940 889 */ 941 - static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, 942 - u8 query, const u8 *data) 890 + static int uvc_get_le_value(struct uvc_control_mapping *mapping, 891 + u8 query, const void *uvc_in, size_t v4l2_size, 892 + void *v4l2_out) 943 893 { 944 - int bits = mapping->size; 945 894 int offset = mapping->offset; 895 + int bits = mapping->size; 896 + const u8 *data = uvc_in; 897 + s32 *out = v4l2_out; 946 898 s32 value = 0; 947 899 u8 mask; 900 + 901 + if (WARN_ON(v4l2_size != sizeof(s32))) 902 + return -EINVAL; 948 903 949 904 data += offset / 8; 950 905 offset &= 7; ··· 973 916 value |= -(value & (1 << (mapping->size - 1))); 974 917 975 918 /* If it is a menu, convert from uvc to v4l2. */ 976 - if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) 977 - return value; 919 + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { 920 + *out = value; 921 + return 0; 922 + } 978 923 979 924 switch (query) { 980 925 case UVC_GET_CUR: 981 926 case UVC_GET_DEF: 982 - return uvc_menu_to_v4l2_menu(mapping, value); 927 + *out = uvc_menu_to_v4l2_menu(mapping, value); 928 + return 0; 983 929 } 984 930 985 - return value; 931 + *out = value; 932 + return 0; 986 933 } 987 934 988 935 /* 989 936 * Set the bit string specified by mapping->offset and mapping->size 990 937 * in the little-endian data stored at 'data' to the value 'value'. 991 938 */ 992 - static void uvc_set_le_value(struct uvc_control_mapping *mapping, 993 - s32 value, u8 *data) 939 + static int uvc_set_le_value(struct uvc_control_mapping *mapping, 940 + size_t v4l2_size, const void *v4l2_in, 941 + void *uvc_out) 994 942 { 995 - int bits = mapping->size; 996 943 int offset = mapping->offset; 944 + int bits = mapping->size; 945 + u8 *data = uvc_out; 946 + s32 value; 997 947 u8 mask; 948 + 949 + if (WARN_ON(v4l2_size != sizeof(s32))) 950 + return -EINVAL; 951 + 952 + value = *(s32 *)v4l2_in; 998 953 999 954 switch (mapping->v4l2_type) { 1000 955 case V4L2_CTRL_TYPE_MENU: ··· 1035 966 bits -= 8 - offset; 1036 967 offset = 0; 1037 968 } 969 + 970 + return 0; 1038 971 } 1039 972 1040 973 /* ------------------------------------------------------------------------ ··· 1218 1147 if (ret < 0) 1219 1148 return ret; 1220 1149 1221 - *value = mapping->get(mapping, UVC_GET_CUR, 1222 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 1150 + *value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, 1151 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 1223 1152 1224 1153 return 0; 1225 1154 } ··· 1352 1281 * as supported. 1353 1282 */ 1354 1283 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) 1355 - return mapping->get(mapping, UVC_GET_RES, 1356 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 1284 + return uvc_mapping_get_s32(mapping, UVC_GET_RES, 1285 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 1357 1286 1358 1287 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) 1359 - return mapping->get(mapping, UVC_GET_MAX, 1360 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 1288 + return uvc_mapping_get_s32(mapping, UVC_GET_MAX, 1289 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 1361 1290 1362 1291 return ~0; 1363 1292 } ··· 1402 1331 } 1403 1332 1404 1333 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { 1405 - v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, 1406 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 1334 + v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping, 1335 + UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 1407 1336 } 1408 1337 1409 1338 switch (mapping->v4l2_type) { ··· 1436 1365 } 1437 1366 1438 1367 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) 1439 - v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, 1440 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 1368 + v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN, 1369 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 1441 1370 1442 1371 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) 1443 - v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, 1444 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 1372 + v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX, 1373 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 1445 1374 1446 1375 if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) 1447 - v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, 1448 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 1376 + v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES, 1377 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 1449 1378 1450 1379 return 0; 1451 1380 } ··· 1696 1625 uvc_ctrl_set_handle(handle, ctrl, NULL); 1697 1626 1698 1627 list_for_each_entry(mapping, &ctrl->info.mappings, list) { 1699 - s32 value = mapping->get(mapping, UVC_GET_CUR, data); 1628 + s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); 1700 1629 1701 1630 /* 1702 1631 * handle may be NULL here if the device sends auto-update ··· 2045 1974 if (ret < 0) 2046 1975 return ret; 2047 1976 } 2048 - xctrl->value = mapping->get(mapping, UVC_GET_DEF, 2049 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 1977 + xctrl->value = uvc_mapping_get_s32(mapping, UVC_GET_DEF, 1978 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 2050 1979 return 0; 2051 1980 } 2052 1981 ··· 2085 2014 return ret; 2086 2015 } 2087 2016 2088 - min = mapping->get(mapping, UVC_GET_MIN, 2089 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 2090 - max = mapping->get(mapping, UVC_GET_MAX, 2091 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 2092 - step = mapping->get(mapping, UVC_GET_RES, 2093 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 2017 + min = uvc_mapping_get_s32(mapping, UVC_GET_MIN, 2018 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 2019 + max = uvc_mapping_get_s32(mapping, UVC_GET_MAX, 2020 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 2021 + step = uvc_mapping_get_s32(mapping, UVC_GET_RES, 2022 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 2094 2023 if (step == 0) 2095 2024 step = 1; 2096 2025 ··· 2169 2098 ctrl->info.size); 2170 2099 } 2171 2100 2172 - mapping->set(mapping, value, 2173 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 2101 + uvc_mapping_set_s32(mapping, value, 2102 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 2174 2103 2175 2104 ctrl->dirty = 1; 2176 2105 ctrl->modified = 1;
+4 -4
drivers/media/usb/uvc/uvcvideo.h
··· 132 132 const struct uvc_control_mapping *(*filter_mapping) 133 133 (struct uvc_video_chain *chain, 134 134 struct uvc_control *ctrl); 135 - s32 (*get)(struct uvc_control_mapping *mapping, u8 query, 136 - const u8 *data); 137 - void (*set)(struct uvc_control_mapping *mapping, s32 value, 138 - u8 *data); 135 + int (*get)(struct uvc_control_mapping *mapping, u8 query, 136 + const void *uvc_in, size_t v4l2_size, void *v4l2_out); 137 + int (*set)(struct uvc_control_mapping *mapping, size_t v4l2_size, 138 + const void *v4l2_in, void *uvc_out); 139 139 }; 140 140 141 141 struct uvc_control {