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: add support for compound controls

This patch adds support for compound controls. This is required to
support controls that cannot be represented with a s64 data, such as the
Region of Interest.

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

authored by

Yunke Cao and committed by
Hans Verkuil
8c3d9d4d 813b0156

+189 -28
+184 -28
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 bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping) 371 + { 372 + return mapping->v4l2_type >= V4L2_CTRL_COMPOUND_TYPES; 373 + } 374 + 370 375 static s32 uvc_mapping_get_s32(struct uvc_control_mapping *mapping, 371 376 u8 query, const void *data_in) 372 377 { ··· 1060 1055 1061 1056 static void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, 1062 1057 struct uvc_control_mapping **mapping, struct uvc_control **control, 1063 - int next) 1058 + int next, int next_compound) 1064 1059 { 1065 1060 struct uvc_control *ctrl; 1066 1061 struct uvc_control_mapping *map; ··· 1075 1070 continue; 1076 1071 1077 1072 list_for_each_entry(map, &ctrl->info.mappings, list) { 1078 - if ((map->id == v4l2_id) && !next) { 1073 + if (map->id == v4l2_id && !next && !next_compound) { 1079 1074 *control = ctrl; 1080 1075 *mapping = map; 1081 1076 return; 1082 1077 } 1083 1078 1084 1079 if ((*mapping == NULL || (*mapping)->id > map->id) && 1085 - (map->id > v4l2_id) && next) { 1080 + (map->id > v4l2_id) && 1081 + (uvc_ctrl_mapping_is_compound(map) ? 1082 + next_compound : next)) { 1086 1083 *control = ctrl; 1087 1084 *mapping = map; 1088 1085 } ··· 1098 1091 struct uvc_control *ctrl = NULL; 1099 1092 struct uvc_entity *entity; 1100 1093 int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL; 1094 + int next_compound = v4l2_id & V4L2_CTRL_FLAG_NEXT_COMPOUND; 1101 1095 1102 1096 *mapping = NULL; 1103 1097 ··· 1107 1099 1108 1100 /* Find the control. */ 1109 1101 list_for_each_entry(entity, &chain->entities, chain) { 1110 - __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); 1111 - if (ctrl && !next) 1102 + __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next, 1103 + next_compound); 1104 + if (ctrl && !next && !next_compound) 1112 1105 return ctrl; 1113 1106 } 1114 1107 1115 - if (ctrl == NULL && !next) 1108 + if (!ctrl && !next && !next_compound) 1116 1109 uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n", 1117 1110 v4l2_id); 1118 1111 ··· 1236 1227 static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, 1237 1228 u32 found_id) 1238 1229 { 1239 - bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL; 1230 + bool find_next = req_id & 1231 + (V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND); 1240 1232 unsigned int i; 1241 1233 1242 1234 req_id &= V4L2_CTRL_ID_MASK; ··· 1327 1317 } 1328 1318 1329 1319 __uvc_find_control(ctrl->entity, mapping->master_id, &master_map, 1330 - &master_ctrl, 0); 1320 + &master_ctrl, 0, 0); 1331 1321 1332 1322 if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) 1333 1323 return 0; 1324 + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) 1325 + return -EIO; 1334 1326 1335 1327 ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); 1336 1328 if (ret >= 0 && val != mapping->master_manual) ··· 1396 1384 1397 1385 if (mapping->master_id) 1398 1386 __uvc_find_control(ctrl->entity, mapping->master_id, 1399 - &master_map, &master_ctrl, 0); 1387 + &master_map, &master_ctrl, 0, 0); 1400 1388 if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { 1401 1389 s32 val; 1402 - int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); 1390 + int ret; 1391 + 1392 + if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) 1393 + return -EIO; 1394 + 1395 + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); 1403 1396 if (ret < 0) 1404 1397 return ret; 1405 1398 1406 1399 if (val != mapping->master_manual) 1407 1400 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; 1401 + } 1402 + 1403 + if (v4l2_ctrl->type >= V4L2_CTRL_COMPOUND_TYPES) { 1404 + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; 1405 + v4l2_ctrl->default_value = 0; 1406 + v4l2_ctrl->minimum = 0; 1407 + v4l2_ctrl->maximum = 0; 1408 + v4l2_ctrl->step = 0; 1409 + return 0; 1408 1410 } 1409 1411 1410 1412 if (!ctrl->cached) { ··· 1661 1635 u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; 1662 1636 s32 val = 0; 1663 1637 1664 - __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0); 1638 + __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0, 0); 1665 1639 if (ctrl == NULL) 1666 1640 return; 1667 1641 1668 - if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) 1642 + if (uvc_ctrl_mapping_is_compound(mapping) || 1643 + __uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) 1669 1644 changes |= V4L2_EVENT_CTRL_CH_VALUE; 1670 1645 1671 1646 uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); ··· 1723 1696 uvc_ctrl_set_handle(handle, ctrl, NULL); 1724 1697 1725 1698 list_for_each_entry(mapping, &ctrl->info.mappings, list) { 1726 - s32 value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); 1699 + s32 value; 1700 + 1701 + if (uvc_ctrl_mapping_is_compound(mapping)) 1702 + value = 0; 1703 + else 1704 + value = uvc_mapping_get_s32(mapping, UVC_GET_CUR, data); 1727 1705 1728 1706 /* 1729 1707 * handle may be NULL here if the device sends auto-update ··· 1812 1780 1813 1781 for (i = 0; i < xctrls_count; ++i) { 1814 1782 u32 changes = V4L2_EVENT_CTRL_CH_VALUE; 1783 + s32 value; 1815 1784 1816 1785 ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); 1817 1786 if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) ··· 1837 1804 slave_id); 1838 1805 } 1839 1806 1807 + if (uvc_ctrl_mapping_is_compound(mapping)) 1808 + value = 0; 1809 + else 1810 + value = xctrls[i].value; 1840 1811 /* 1841 1812 * If the master is being modified in the same transaction 1842 1813 * flags may change too. ··· 1851 1814 changes |= V4L2_EVENT_CTRL_CH_FLAGS; 1852 1815 1853 1816 uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping, 1854 - xctrls[i].value, changes); 1817 + value, changes); 1855 1818 } 1856 1819 } 1857 1820 ··· 1883 1846 u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; 1884 1847 s32 val = 0; 1885 1848 1886 - if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) 1849 + if (uvc_ctrl_mapping_is_compound(mapping) || 1850 + __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) 1887 1851 changes |= V4L2_EVENT_CTRL_CH_VALUE; 1888 1852 1889 1853 uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, ··· 2024 1986 2025 1987 for (i = 0; i < ctrls->count; i++) { 2026 1988 __uvc_find_control(entity, ctrls->controls[i].id, &mapping, 2027 - &ctrl_found, 0); 1989 + &ctrl_found, 0, 0); 2028 1990 if (uvc_control == ctrl_found) 2029 1991 return i; 2030 1992 } ··· 2060 2022 return ret; 2061 2023 } 2062 2024 2063 - int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which, 2064 - struct v4l2_ext_control *xctrl) 2025 + static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain, 2026 + struct uvc_control *ctrl, 2027 + struct uvc_control_mapping *mapping, 2028 + u32 which, 2029 + struct v4l2_ext_control *xctrl) 2065 2030 { 2066 - struct uvc_control *ctrl; 2067 - struct uvc_control_mapping *mapping; 2031 + u8 *data __free(kfree) = NULL; 2032 + size_t size; 2033 + u8 query; 2034 + int ret; 2035 + int id; 2068 2036 2069 - if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) 2070 - return -EACCES; 2071 - 2072 - ctrl = uvc_find_control(chain, xctrl->id, &mapping); 2073 - if (ctrl == NULL) 2037 + switch (which) { 2038 + case V4L2_CTRL_WHICH_CUR_VAL: 2039 + ret = __uvc_ctrl_load_cur(chain, ctrl); 2040 + if (ret < 0) 2041 + return ret; 2042 + id = UVC_CTRL_DATA_CURRENT; 2043 + query = UVC_GET_CUR; 2044 + break; 2045 + case V4L2_CTRL_WHICH_DEF_VAL: 2046 + ret = uvc_ctrl_populate_cache(chain, ctrl); 2047 + if (ret < 0) 2048 + return ret; 2049 + id = UVC_CTRL_DATA_DEF; 2050 + query = UVC_GET_DEF; 2051 + break; 2052 + default: 2074 2053 return -EINVAL; 2054 + } 2075 2055 2056 + size = DIV_ROUND_UP(mapping->size, 8); 2057 + if (xctrl->size < size) { 2058 + xctrl->size = size; 2059 + return -ENOSPC; 2060 + } 2061 + 2062 + data = kmalloc(size, GFP_KERNEL); 2063 + if (!data) 2064 + return -ENOMEM; 2065 + 2066 + ret = mapping->get(mapping, query, uvc_ctrl_data(ctrl, id), size, data); 2067 + if (ret < 0) 2068 + return ret; 2069 + 2070 + /* 2071 + * v4l2_ext_control does not have enough room to fit a compound control. 2072 + * Instead, the value is in the user memory at xctrl->ptr. The v4l2 2073 + * ioctl helper does not copy it for us. 2074 + */ 2075 + return copy_to_user(xctrl->ptr, data, size) ? -EFAULT : 0; 2076 + } 2077 + 2078 + static int uvc_mapping_get_xctrl_std(struct uvc_video_chain *chain, 2079 + struct uvc_control *ctrl, 2080 + struct uvc_control_mapping *mapping, 2081 + u32 which, struct v4l2_ext_control *xctrl) 2082 + { 2076 2083 switch (which) { 2077 2084 case V4L2_CTRL_WHICH_CUR_VAL: 2078 2085 return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); ··· 2134 2051 } 2135 2052 2136 2053 return -EINVAL; 2054 + } 2055 + 2056 + static int uvc_mapping_get_xctrl(struct uvc_video_chain *chain, 2057 + struct uvc_control *ctrl, 2058 + struct uvc_control_mapping *mapping, 2059 + u32 which, struct v4l2_ext_control *xctrl) 2060 + { 2061 + if (uvc_ctrl_mapping_is_compound(mapping)) 2062 + return uvc_mapping_get_xctrl_compound(chain, ctrl, mapping, 2063 + which, xctrl); 2064 + return uvc_mapping_get_xctrl_std(chain, ctrl, mapping, which, xctrl); 2065 + } 2066 + 2067 + int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which, 2068 + struct v4l2_ext_control *xctrl) 2069 + { 2070 + struct uvc_control *ctrl; 2071 + struct uvc_control_mapping *mapping; 2072 + 2073 + if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) 2074 + return -EACCES; 2075 + 2076 + ctrl = uvc_find_control(chain, xctrl->id, &mapping); 2077 + if (!ctrl) 2078 + return -EINVAL; 2079 + 2080 + return uvc_mapping_get_xctrl(chain, ctrl, mapping, which, xctrl); 2137 2081 } 2138 2082 2139 2083 static int uvc_ctrl_clamp(struct uvc_video_chain *chain, ··· 2246 2136 return 0; 2247 2137 } 2248 2138 2139 + static int uvc_mapping_set_xctrl_compound(struct uvc_control *ctrl, 2140 + struct uvc_control_mapping *mapping, 2141 + struct v4l2_ext_control *xctrl) 2142 + { 2143 + u8 *data __free(kfree) = NULL; 2144 + size_t size; 2145 + 2146 + size = DIV_ROUND_UP(mapping->size, 8); 2147 + if (xctrl->size != size) 2148 + return -EINVAL; 2149 + 2150 + /* 2151 + * v4l2_ext_control does not have enough room to fit a compound control. 2152 + * Instead, the value is in the user memory at xctrl->ptr. The v4l2 2153 + * ioctl helper does not copy it for us. 2154 + */ 2155 + data = memdup_user(xctrl->ptr, size); 2156 + if (IS_ERR(data)) 2157 + return PTR_ERR(data); 2158 + 2159 + return mapping->set(mapping, size, data, 2160 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 2161 + } 2162 + 2163 + static int uvc_mapping_set_xctrl(struct uvc_control *ctrl, 2164 + struct uvc_control_mapping *mapping, 2165 + struct v4l2_ext_control *xctrl) 2166 + { 2167 + if (uvc_ctrl_mapping_is_compound(mapping)) 2168 + return uvc_mapping_set_xctrl_compound(ctrl, mapping, xctrl); 2169 + 2170 + uvc_mapping_set_s32(mapping, xctrl->value, 2171 + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 2172 + return 0; 2173 + } 2174 + 2249 2175 int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl) 2250 2176 { 2251 2177 struct uvc_video_chain *chain = handle->chain; ··· 2321 2175 ctrl->info.size); 2322 2176 } 2323 2177 2324 - uvc_mapping_set_s32(mapping, xctrl->value, 2325 - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 2178 + ret = uvc_mapping_set_xctrl(ctrl, mapping, xctrl); 2179 + if (ret) 2180 + return ret; 2326 2181 2327 2182 ctrl->dirty = 1; 2328 2183 ctrl->modified = 1; ··· 2698 2551 struct uvc_control_mapping *map; 2699 2552 unsigned int size; 2700 2553 unsigned int i; 2554 + int ret; 2701 2555 2702 2556 /* 2703 2557 * Most mappings come from static kernel data, and need to be duplicated. ··· 2739 2591 goto err_nomem; 2740 2592 } 2741 2593 2594 + if (uvc_ctrl_mapping_is_compound(map)) 2595 + if (WARN_ON(!map->set || !map->get)) { 2596 + ret = -EIO; 2597 + goto free_mem; 2598 + } 2599 + 2742 2600 if (map->get == NULL) 2743 2601 map->get = uvc_get_le_value; 2744 2602 if (map->set == NULL) ··· 2766 2612 return 0; 2767 2613 2768 2614 err_nomem: 2615 + ret = -ENOMEM; 2616 + free_mem: 2769 2617 kfree(map->menu_names); 2770 2618 kfree(map->menu_mapping); 2771 2619 kfree(map->name); 2772 2620 kfree(map); 2773 - return -ENOMEM; 2621 + return ret; 2774 2622 } 2775 2623 2776 2624 int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+5
drivers/media/usb/uvc/uvcvideo.h
··· 116 116 u8 entity[16]; 117 117 u8 selector; 118 118 119 + /* 120 + * Size of the control data in the payload of the UVC control GET and 121 + * SET requests, expressed in bits. 122 + */ 119 123 u8 size; 124 + 120 125 u8 offset; 121 126 enum v4l2_ctrl_type v4l2_type; 122 127 u32 data_type;