All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency
@ 2022-06-17 23:56 Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 1/9] media: uvcvideo: Add missing value for power_line_frequency Ricardo Ribalda
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Hello,

This series is a new version of "[PATCH v3 0/7] uvcvideo: Fix handling
of power_line_frequency", with an attempt to generalize the
UVC_QUIRK_LIMITED_POWERLINE quirk that it introduced and turn it into a
control mappings override mechanism.

The goal is still to support the UVC 1.5 power line frequency control
extra option (patch 1/7), and work around an issue with devices that do
not implement support for disabling the power line frequency (patches
2/7 to 7/7).

Changelog v8:
- media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU
  New patch
- media: uvcvideo: Use standard names for menus
  New patch

Changelog v7:
- Support minimum for V4L2_CTRL_TYPE_MENU
  Fix uvc_query_v4l2_menu

Changelog v6:
- Add support for per-device control mapping overrides
  Fix invalid memory access
- Support minimum for V4L2_CTRL_TYPE_MENU
  New patch
- Limit power line control for Quanta UVC Webcam
  Fix id

Ricardo Ribalda (9):
  media: uvcvideo: Add missing value for power_line_frequency
  media: uvcvideo: Add support for per-device control mapping overrides
  media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU
  media: uvcvideo: Use standard names for menus
  media: uvcvideo: Limit power line control for Quanta UVC Webcam
  media: uvcvideo: Limit power line control for Chicony Easycamera
  media: uvcvideo: Limit power line control for Chicony Easycamera
  media: uvcvideo: Limit power line control for Quanta cameras
  media: uvcvideo: Limit power line control for Acer EasyCamera

 drivers/media/usb/uvc/uvc_ctrl.c   | 208 ++++++++++++++++++++++-------
 drivers/media/usb/uvc/uvc_driver.c |  81 +++++++++++
 drivers/media/usb/uvc/uvc_v4l2.c   |  77 ++++++++---
 drivers/media/usb/uvc/uvcvideo.h   |   6 +-
 include/uapi/linux/uvcvideo.h      |   3 +-
 5 files changed, 303 insertions(+), 72 deletions(-)

-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v8 1/9] media: uvcvideo: Add missing value for power_line_frequency
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 2/9] media: uvcvideo: Add support for per-device control mapping overrides Ricardo Ribalda
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

UVC 1.5 class defines 4 values for this control on:
4.2.2.3.6 Power Line Frequency Control

Add the missing value when the UVC version is 1.5.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 56 +++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 11 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 0e78233fc8a0..a709ebbb4d69 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -366,6 +366,7 @@ static const struct uvc_menu_info power_line_frequency_controls[] = {
 	{ 0, "Disabled" },
 	{ 1, "50 Hz" },
 	{ 2, "60 Hz" },
+	{ 3, "Auto" },
 };
 
 static const struct uvc_menu_info exposure_auto_controls[] = {
@@ -504,17 +505,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
 		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
 	},
-	{
-		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
-		.entity		= UVC_GUID_UVC_PROCESSING,
-		.selector	= UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
-		.size		= 2,
-		.offset		= 0,
-		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
-		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
-		.menu_info	= power_line_frequency_controls,
-		.menu_count	= ARRAY_SIZE(power_line_frequency_controls),
-	},
 	{
 		.id		= V4L2_CID_HUE_AUTO,
 		.entity		= UVC_GUID_UVC_PROCESSING,
@@ -730,6 +720,34 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 	},
 };
 
+static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
+	{
+		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+		.size		= 2,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
+		.menu_info	= power_line_frequency_controls,
+		.menu_count	= ARRAY_SIZE(power_line_frequency_controls) - 1,
+	},
+};
+
+static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
+	{
+		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+		.size		= 2,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
+		.menu_info	= power_line_frequency_controls,
+		.menu_count	= ARRAY_SIZE(power_line_frequency_controls),
+	},
+};
+
 /* ------------------------------------------------------------------------
  * Utility functions
  */
@@ -2415,6 +2433,22 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
 	if (!ctrl->initialized)
 		return;
 
+	/* Process common mappings first. */
+	for (; mapping < mend; ++mapping) {
+		if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+		    ctrl->info.selector == mapping->selector)
+			__uvc_ctrl_add_mapping(chain, ctrl, mapping);
+	}
+
+	/* And then version-specific mappings. */
+	if (chain->dev->uvc_version < 0x0150) {
+		mapping = uvc_ctrl_mappings_uvc11;
+		mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11);
+	} else {
+		mapping = uvc_ctrl_mappings_uvc15;
+		mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc15);
+	}
+
 	for (; mapping < mend; ++mapping) {
 		if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
 		    ctrl->info.selector == mapping->selector)
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 2/9] media: uvcvideo: Add support for per-device control mapping overrides
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 1/9] media: uvcvideo: Add missing value for power_line_frequency Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 3/9] media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU Ricardo Ribalda
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Some devices do not implement all their controls in a way that complies
with the UVC specification. This is for instance the case for several
devices that do not support the disabled mode for the power line
frequency control. Add a mechanism to allow per-device control mapping
overrides to avoid errors when accessing non-compliant controls.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 34 +++++++++++++++++++++++++++-----
 drivers/media/usb/uvc/uvcvideo.h |  1 +
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index a709ebbb4d69..38e35e369ddf 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2403,9 +2403,8 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
 {
 	const struct uvc_control_info *info = uvc_ctrls;
 	const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
-	const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
-	const struct uvc_control_mapping *mend =
-		mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+	const struct uvc_control_mapping *mapping;
+	const struct uvc_control_mapping *mend;
 
 	/* XU controls initialization requires querying the device for control
 	 * information. As some buggy UVC devices will crash when queried
@@ -2433,14 +2432,39 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
 	if (!ctrl->initialized)
 		return;
 
-	/* Process common mappings first. */
+	/*
+	 * First check if the device provides a custom mapping for this control,
+	 * used to override standard mappings for non-conformant devices. Don't
+	 * process standard mappings if a custom mapping is found. This
+	 * mechanism doesn't support combining standard and custom mappings for
+	 * a single control.
+	 */
+	if (chain->dev->info->mappings) {
+		bool custom = false;
+		unsigned int i;
+
+		for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) {
+			if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+			    ctrl->info.selector == mapping->selector) {
+				__uvc_ctrl_add_mapping(chain, ctrl, mapping);
+				custom = true;
+			}
+		}
+
+		if (custom)
+			return;
+	}
+
+	/* Process common mappings next. */
+	mapping = uvc_ctrl_mappings;
+	mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings);
 	for (; mapping < mend; ++mapping) {
 		if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
 		    ctrl->info.selector == mapping->selector)
 			__uvc_ctrl_add_mapping(chain, ctrl, mapping);
 	}
 
-	/* And then version-specific mappings. */
+	/* Finally process version-specific mappings. */
 	if (chain->dev->uvc_version < 0x0150) {
 		mapping = uvc_ctrl_mappings_uvc11;
 		mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index c5b4febd2d94..fff5c5c99a3d 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -667,6 +667,7 @@ struct uvc_device_info {
 	u32	quirks;
 	u32	meta_format;
 	u16	uvc_version;
+	const struct uvc_control_mapping **mappings;
 };
 
 struct uvc_device {
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 3/9] media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 1/9] media: uvcvideo: Add missing value for power_line_frequency Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 2/9] media: uvcvideo: Add support for per-device control mapping overrides Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 4/9] media: uvcvideo: Use standard names for menus Ricardo Ribalda
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Replace the count with a mask field that let us choose not only the max
value, but also the minimum value and what values are valid in between.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 32 ++++++++++++++++++++++----------
 drivers/media/usb/uvc/uvc_v4l2.c |  2 +-
 drivers/media/usb/uvc/uvcvideo.h |  2 +-
 3 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 38e35e369ddf..a03714c3a265 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -524,7 +524,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_BITMASK,
 		.menu_info	= exposure_auto_controls,
-		.menu_count	= ARRAY_SIZE(exposure_auto_controls),
+		.menu_mask	=
+			BIT_MASK(ARRAY_SIZE(exposure_auto_controls)),
 		.slave_ids	= { V4L2_CID_EXPOSURE_ABSOLUTE, },
 	},
 	{
@@ -730,7 +731,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
 		.menu_info	= power_line_frequency_controls,
-		.menu_count	= ARRAY_SIZE(power_line_frequency_controls) - 1,
+		.menu_mask	=
+			BIT_MASK(ARRAY_SIZE(power_line_frequency_controls) - 1),
 	},
 };
 
@@ -744,7 +746,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
 		.menu_info	= power_line_frequency_controls,
-		.menu_count	= ARRAY_SIZE(power_line_frequency_controls),
+		.menu_mask	=
+			BIT_MASK(ARRAY_SIZE(power_line_frequency_controls)),
 	},
 };
 
@@ -970,7 +973,9 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
 		const struct uvc_menu_info *menu = mapping->menu_info;
 		unsigned int i;
 
-		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+		for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
+			if (!test_bit(i, &mapping->menu_mask))
+				continue;
 			if (menu->value == value) {
 				value = i;
 				break;
@@ -1144,12 +1149,14 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 
 	switch (mapping->v4l2_type) {
 	case V4L2_CTRL_TYPE_MENU:
-		v4l2_ctrl->minimum = 0;
-		v4l2_ctrl->maximum = mapping->menu_count - 1;
+		v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1;
+		v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
 		v4l2_ctrl->step = 1;
 
 		menu = mapping->menu_info;
-		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+		for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
+			if (!test_bit(i, &mapping->menu_mask))
+				continue;
 			if (menu->value == v4l2_ctrl->default_value) {
 				v4l2_ctrl->default_value = i;
 				break;
@@ -1264,7 +1271,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 		goto done;
 	}
 
-	if (query_menu->index >= mapping->menu_count) {
+	if (!test_bit(query_menu->index, &mapping->menu_mask)) {
 		ret = -EINVAL;
 		goto done;
 	}
@@ -1769,8 +1776,13 @@ int uvc_ctrl_set(struct uvc_fh *handle,
 		break;
 
 	case V4L2_CTRL_TYPE_MENU:
-		if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
+		if (xctrl->value < (ffs(mapping->menu_mask) - 1) ||
+		    xctrl->value > (fls(mapping->menu_mask) - 1))
 			return -ERANGE;
+
+		if (!test_bit(xctrl->value, &mapping->menu_mask))
+			return -EINVAL;
+
 		value = mapping->menu_info[xctrl->value].value;
 
 		/* Valid menu indices are reported by the GET_RES request for
@@ -2217,7 +2229,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 
 	INIT_LIST_HEAD(&map->ev_subs);
 
-	size = sizeof(*mapping->menu_info) * mapping->menu_count;
+	size = sizeof(*mapping->menu_info) * fls(mapping->menu_mask);
 	map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
 	if (map->menu_info == NULL) {
 		kfree(map->name);
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 648dcd579e81..85aced173daa 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -79,7 +79,7 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
 			goto free_map;
 		}
 
-		map->menu_count = xmap->menu_count;
+		map->menu_mask = BIT_MASK(xmap->menu_count);
 		break;
 
 	default:
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index fff5c5c99a3d..0736b8815d79 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -254,7 +254,7 @@ struct uvc_control_mapping {
 	u32 data_type;
 
 	const struct uvc_menu_info *menu_info;
-	u32 menu_count;
+	unsigned long menu_mask;
 
 	u32 master_id;
 	s32 master_manual;
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 4/9] media: uvcvideo: Use standard names for menus
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (2 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 3/9] media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-18  7:50   ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 5/9] media: uvcvideo: Limit power line control for Quanta UVC Webcam Ricardo Ribalda
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Instead of duplicating the menu info, use the one from the core.
Also, do not use extra memory for 1:1 mappings.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 116 +++++++++++++++++++++----------
 drivers/media/usb/uvc/uvc_v4l2.c |  80 ++++++++++++++++-----
 drivers/media/usb/uvc/uvcvideo.h |   3 +-
 include/uapi/linux/uvcvideo.h    |   3 +-
 4 files changed, 144 insertions(+), 58 deletions(-)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index a03714c3a265..1a3021a16b76 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -362,19 +362,31 @@ static const u32 uvc_control_classes[] = {
 	V4L2_CID_USER_CLASS,
 };
 
-static const struct uvc_menu_info power_line_frequency_controls[] = {
-	{ 0, "Disabled" },
-	{ 1, "50 Hz" },
-	{ 2, "60 Hz" },
-	{ 3, "Auto" },
-};
+static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
 
-static const struct uvc_menu_info exposure_auto_controls[] = {
-	{ 2, "Auto Mode" },
-	{ 1, "Manual Mode" },
-	{ 4, "Shutter Priority Mode" },
-	{ 8, "Aperture Priority Mode" },
-};
+static u32 uvc_mapping_get_menu_value(struct uvc_control_mapping *mapping,
+				      u32 idx)
+{
+	if (!test_bit(idx, &mapping->menu_mask))
+		return 0;
+
+	if (mapping->menu_mapping)
+		return mapping->menu_mapping[idx];
+
+	return idx;
+}
+
+static const char
+*uvc_mapping_get_menu_name(struct uvc_control_mapping *mapping, u32 idx)
+{
+	if (!test_bit(idx, &mapping->menu_mask))
+		return NULL;
+
+	if (mapping->menu_names)
+		return mapping->menu_names[idx];
+
+	return v4l2_ctrl_get_menu(mapping->id)[idx];
+}
 
 static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
 	u8 query, const u8 *data)
@@ -523,9 +535,9 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_BITMASK,
-		.menu_info	= exposure_auto_controls,
+		.menu_mapping	= exposure_auto_mapping,
 		.menu_mask	=
-			BIT_MASK(ARRAY_SIZE(exposure_auto_controls)),
+			GENMASK(ARRAY_SIZE(exposure_auto_mapping) - 1, 0),
 		.slave_ids	= { V4L2_CID_EXPOSURE_ABSOLUTE, },
 	},
 	{
@@ -730,9 +742,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
-		.menu_info	= power_line_frequency_controls,
 		.menu_mask	=
-			BIT_MASK(ARRAY_SIZE(power_line_frequency_controls) - 1),
+			GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0),
 	},
 };
 
@@ -745,9 +756,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
 		.offset		= 0,
 		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
 		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
-		.menu_info	= power_line_frequency_controls,
 		.menu_mask	=
-			BIT_MASK(ARRAY_SIZE(power_line_frequency_controls)),
+			GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0),
 	},
 };
 
@@ -970,13 +980,17 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
 	s32 value = mapping->get(mapping, UVC_GET_CUR, data);
 
 	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
-		const struct uvc_menu_info *menu = mapping->menu_info;
 		unsigned int i;
 
-		for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
+		for (i = 1; BIT(i) <= mapping->menu_mask; ++i) {
+			u32 menu_value;
+
 			if (!test_bit(i, &mapping->menu_mask))
 				continue;
-			if (menu->value == value) {
+
+			menu_value = uvc_mapping_get_menu_value(mapping, i);
+
+			if (menu_value == value) {
 				value = i;
 				break;
 			}
@@ -1108,7 +1122,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 {
 	struct uvc_control_mapping *master_map = NULL;
 	struct uvc_control *master_ctrl = NULL;
-	const struct uvc_menu_info *menu;
 	unsigned int i;
 
 	memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
@@ -1153,11 +1166,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 		v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
 		v4l2_ctrl->step = 1;
 
-		menu = mapping->menu_info;
-		for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
+		for (i = 1; BIT(i) <= mapping->menu_mask; ++i) {
+			u32 menu_value;
+
 			if (!test_bit(i, &mapping->menu_mask))
 				continue;
-			if (menu->value == v4l2_ctrl->default_value) {
+
+			menu_value = uvc_mapping_get_menu_value(mapping, i);
+
+			if (menu_value == v4l2_ctrl->default_value) {
 				v4l2_ctrl->default_value = i;
 				break;
 			}
@@ -1250,11 +1267,11 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 	struct v4l2_querymenu *query_menu)
 {
-	const struct uvc_menu_info *menu_info;
 	struct uvc_control_mapping *mapping;
 	struct uvc_control *ctrl;
 	u32 index = query_menu->index;
 	u32 id = query_menu->id;
+	const char *name;
 	int ret;
 
 	memset(query_menu, 0, sizeof(*query_menu));
@@ -1276,11 +1293,10 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 		goto done;
 	}
 
-	menu_info = &mapping->menu_info[query_menu->index];
-
 	if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
 	    (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
 		s32 bitmap;
+		u32 menu_value;
 
 		if (!ctrl->cached) {
 			ret = uvc_ctrl_populate_cache(chain, ctrl);
@@ -1288,15 +1304,22 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
 				goto done;
 		}
 
+		menu_value = uvc_mapping_get_menu_value(mapping,
+							query_menu->index);
+
 		bitmap = mapping->get(mapping, UVC_GET_RES,
 				      uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
-		if (!(bitmap & menu_info->value)) {
+		if (!(bitmap & menu_value)) {
 			ret = -EINVAL;
 			goto done;
 		}
 	}
 
-	strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
+	name = uvc_mapping_get_menu_name(mapping, query_menu->index);
+	if (name)
+		strscpy(query_menu->name, name, sizeof(query_menu->name));
+	else
+		ret = -EINVAL;
 
 done:
 	mutex_unlock(&chain->ctrl_mutex);
@@ -1783,7 +1806,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
 		if (!test_bit(xctrl->value, &mapping->menu_mask))
 			return -EINVAL;
 
-		value = mapping->menu_info[xctrl->value].value;
+		value = uvc_mapping_get_menu_value(mapping, xctrl->value);
 
 		/* Valid menu indices are reported by the GET_RES request for
 		 * UVC controls that support it.
@@ -2229,12 +2252,28 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
 
 	INIT_LIST_HEAD(&map->ev_subs);
 
-	size = sizeof(*mapping->menu_info) * fls(mapping->menu_mask);
-	map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
-	if (map->menu_info == NULL) {
-		kfree(map->name);
-		kfree(map);
-		return -ENOMEM;
+	if (mapping->menu_mapping && mapping->menu_mask) {
+		size = sizeof(mapping->menu_mapping[0]) *
+			      fls(mapping->menu_mask);
+		map->menu_mapping = kmemdup(mapping->menu_mapping, size,
+					    GFP_KERNEL);
+		if (!map->menu_mapping) {
+			kfree(map->name);
+			kfree(map);
+			return -ENOMEM;
+		}
+	}
+	if (mapping->menu_names && mapping->menu_mask) {
+		size = sizeof(mapping->menu_names[0]) *
+			      fls(mapping->menu_mask);
+		map->menu_names = kmemdup(mapping->menu_names, size,
+					  GFP_KERNEL);
+		if (!map->menu_names) {
+			kfree(map->menu_mapping);
+			kfree(map->name);
+			kfree(map);
+			return -ENOMEM;
+		}
 	}
 
 	if (map->get == NULL)
@@ -2577,7 +2616,8 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
 
 	list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
 		list_del(&mapping->list);
-		kfree(mapping->menu_info);
+		kfree(mapping->menu_names);
+		kfree(mapping->menu_mapping);
 		kfree(mapping->name);
 		kfree(mapping);
 	}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 85aced173daa..0ba1eb92df8e 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -25,6 +25,64 @@
 
 #include "uvcvideo.h"
 
+static int uvc_control_xu_2_mapping(struct uvc_control_mapping *map,
+				    struct uvc_xu_control_mapping *xmap)
+{
+	char (*names)[UVC_MENU_NAME_LEN];
+	unsigned int i;
+	u32 *mapping;
+	size_t size;
+
+	/* Prevent excessive memory consumption, as well as integer
+	 * overflows.
+	 */
+	if (xmap->menu_count == 0 ||
+	    xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES)
+		return -EINVAL;
+
+	map->menu_mask = BIT_MASK(xmap->menu_count);
+
+	size = xmap->menu_count * sizeof(*map->menu_mapping);
+	mapping = kzalloc(size, GFP_KERNEL);
+	if (!mapping)
+		return -ENOMEM;
+
+	for (i = 0; i < xmap->menu_count ; i++)
+		if (copy_from_user(&mapping[i], &xmap->menu_info[i].value,
+				   sizeof(mapping[i]))) {
+			kfree(mapping);
+			return -ENOMEM;
+		}
+
+	map->menu_mapping = mapping;
+
+	/*
+	 * Always use the standard naming if available.
+	 */
+	if (v4l2_ctrl_get_menu(map->id))
+		return 0;
+
+	size = xmap->menu_count * sizeof(map->menu_names[0]);
+	names = kzalloc(size, GFP_KERNEL);
+	if (!names) {
+		kfree(mapping);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < xmap->menu_count ; i++) {
+		/* sizeof(names[i]) - 1: to take care of \0 */
+		if (copy_from_user(&names[i], &xmap->menu_info[i].name,
+				   sizeof(names[i]) - 1)) {
+			kfree(names);
+			kfree(mapping);
+			return -ENOMEM;
+		}
+	}
+	map->menu_names = names;
+
+	return 0;
+}
+
 /* ------------------------------------------------------------------------
  * UVC ioctls
  */
@@ -32,7 +90,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
 	struct uvc_xu_control_mapping *xmap)
 {
 	struct uvc_control_mapping *map;
-	unsigned int size;
 	int ret;
 
 	map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -63,23 +120,9 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
 		break;
 
 	case V4L2_CTRL_TYPE_MENU:
-		/* Prevent excessive memory consumption, as well as integer
-		 * overflows.
-		 */
-		if (xmap->menu_count == 0 ||
-		    xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
-			ret = -EINVAL;
-			goto free_map;
-		}
-
-		size = xmap->menu_count * sizeof(*map->menu_info);
-		map->menu_info = memdup_user(xmap->menu_info, size);
-		if (IS_ERR(map->menu_info)) {
-			ret = PTR_ERR(map->menu_info);
+		ret = uvc_control_xu_2_mapping(map, xmap);
+		if (ret)
 			goto free_map;
-		}
-
-		map->menu_mask = BIT_MASK(xmap->menu_count);
 		break;
 
 	default:
@@ -91,7 +134,8 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
 
 	ret = uvc_ctrl_add_mapping(chain, map);
 
-	kfree(map->menu_info);
+	kfree(map->menu_names);
+	kfree(map->menu_mapping);
 free_map:
 	kfree(map);
 
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 0736b8815d79..b702f1c8547b 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -253,7 +253,8 @@ struct uvc_control_mapping {
 	enum v4l2_ctrl_type v4l2_type;
 	u32 data_type;
 
-	const struct uvc_menu_info *menu_info;
+	const u32 *menu_mapping;
+	const char (*menu_names)[UVC_MENU_NAME_LEN];
 	unsigned long menu_mask;
 
 	u32 master_id;
diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
index 8288137387c0..1b64b6aa40b5 100644
--- a/include/uapi/linux/uvcvideo.h
+++ b/include/uapi/linux/uvcvideo.h
@@ -36,9 +36,10 @@
 	 UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \
 	 UVC_CTRL_FLAG_GET_DEF)
 
+#define UVC_MENU_NAME_LEN 32
 struct uvc_menu_info {
 	__u32 value;
-	__u8 name[32];
+	__u8 name[UVC_MENU_NAME_LEN];
 };
 
 struct uvc_xu_control_mapping {
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 5/9] media: uvcvideo: Limit power line control for Quanta UVC Webcam
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (3 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 4/9] media: uvcvideo: Use standard names for menus Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 6/9] media: uvcvideo: Limit power line control for Chicony Easycamera Ricardo Ribalda
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

The device does not implement the power line control correctly. Add a
corresponding control mapping override.

Bus 001 Device 003: ID 0408:3090 Quanta Computer, Inc. USB2.0 HD UVC WebCam
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0408 Quanta Computer, Inc.
  idProduct          0x3090
  bcdDevice            0.04
  iManufacturer           3 Quanta
  iProduct                1 USB2.0 HD UVC WebCam
  iSerial                 2 0x0001
  bNumConfigurations      1

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_driver.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 6c86faecbea2..ea8f0bb7a20c 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2643,6 +2643,24 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
  * Driver initialization and cleanup
  */
 
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
+	.id		= V4L2_CID_POWER_LINE_FREQUENCY,
+	.entity		= UVC_GUID_UVC_PROCESSING,
+	.selector	= UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+	.size		= 2,
+	.offset		= 0,
+	.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+	.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
+	.menu_mask	= 0x6,
+};
+
+static const struct uvc_device_info uvc_ctrl_power_line_limited = {
+	.mappings = (const struct uvc_control_mapping *[]) {
+		&uvc_ctrl_power_line_mapping_limited,
+		NULL, /* Sentinel */
+	},
+};
+
 static const struct uvc_device_info uvc_quirk_probe_minmax = {
 	.quirks = UVC_QUIRK_PROBE_MINMAX,
 };
@@ -2673,6 +2691,15 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
  * though they are compliant.
  */
 static const struct usb_device_id uvc_ids[] = {
+	/* Quanta USB2.0 HD UVC Webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0408,
+	  .idProduct		= 0x3090,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
 	/* LogiLink Wireless Webcam */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 6/9] media: uvcvideo: Limit power line control for Chicony Easycamera
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (4 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 5/9] media: uvcvideo: Limit power line control for Quanta UVC Webcam Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 7/9] " Ricardo Ribalda
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Two different Easycamera devices do not implement the power line control
correctly. Add a corresponding control mapping override.

Bus 001 Device 003: ID 04f2:b6ba Chicony Electronics Co., Ltd EasyCamera
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x04f2 Chicony Electronics Co., Ltd
  idProduct          0xb6ba
  bcdDevice           10.70
  iManufacturer           3 Chicony Electronics Co.,Ltd.
  iProduct                1 EasyCamera
  iSerial                 2 0001
  bNumConfigurations      1

Bus 001 Device 003: ID 04f2:b746 Chicony Electronics Co., Ltd EasyCamera
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x04f2 Chicony Electronics Co., Ltd
  idProduct          0xb746
  bcdDevice           97.57
  iManufacturer           3 Chicony Electronics Co.,Ltd.
  iProduct                1 EasyCamera
  iSerial                 2 0001
  bNumConfigurations      1

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_driver.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index ea8f0bb7a20c..b22d083833ee 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2811,6 +2811,24 @@ static const struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
+	/* Chicony EasyCamera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x04f2,
+	  .idProduct		= 0xb6ba,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+	/* Chicony EasyCamera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x04f2,
+	  .idProduct		= 0xb746,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
 	/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 7/9] media: uvcvideo: Limit power line control for Chicony Easycamera
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (5 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 6/9] media: uvcvideo: Limit power line control for Chicony Easycamera Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 8/9] media: uvcvideo: Limit power line control for Quanta cameras Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 9/9] media: uvcvideo: Limit power line control for Acer EasyCamera Ricardo Ribalda
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Another Chicony camera device does not implement the power line control
correctly. Add a corresponding control mapping override.

Bus 001 Device 003: ID 04f2:b5eb Chicony Electronics Co., Ltd EasyCamera
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x04f2 Chicony Electronics Co., Ltd
  idProduct          0xb5eb
  bcdDevice           90.45
  iManufacturer           3 Chicony Electronics Co.,Ltd.
  iProduct                1 EasyCamera
  iSerial                 2 0001
  bNumConfigurations      1

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index b22d083833ee..425520f06ce4 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2812,6 +2812,15 @@ static const struct usb_device_id uvc_ids[] = {
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
 	/* Chicony EasyCamera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x04f2,
+	  .idProduct		= 0xb5eb,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+	/* Chicony EasyCamera */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
 	  .idVendor		= 0x04f2,
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 8/9] media: uvcvideo: Limit power line control for Quanta cameras
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (6 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 7/9] " Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  2022-06-17 23:56 ` [PATCH v8 9/9] media: uvcvideo: Limit power line control for Acer EasyCamera Ricardo Ribalda
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

Two more cameras do not implement the power line control correctly. Add
a corresponding control mapping override.

Bus 001 Device 003: ID 0408:4034 Quanta Computer, Inc. ACER HD User Facing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.01
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0408 Quanta Computer, Inc.
  idProduct          0x4034
  bcdDevice            0.01
  iManufacturer           1 Quanta
  iProduct                2 ACER HD User Facing
  iSerial                 3 01.00.00
  bNumConfigurations      1

Bus 001 Device 003: ID 0408:4030 Quanta Computer, Inc. HD User Facing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.01
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x0408 Quanta Computer, Inc.
  idProduct          0x4030
  bcdDevice            0.02
  iManufacturer           1 Quanta
  iProduct                2 HD User Facing
  iSerial                 3 01.00.00
  bNumConfigurations      1

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_driver.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 425520f06ce4..387b85fa1998 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2700,6 +2700,24 @@ static const struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+	/* Quanta USB2.0 HD UVC Webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0408,
+	  .idProduct		= 0x4030,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 1,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+	/* Quanta USB2.0 HD UVC Webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0408,
+	  .idProduct		= 0x4034,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
 	/* LogiLink Wireless Webcam */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v8 9/9] media: uvcvideo: Limit power line control for Acer EasyCamera
  2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
                   ` (7 preceding siblings ...)
  2022-06-17 23:56 ` [PATCH v8 8/9] media: uvcvideo: Limit power line control for Quanta cameras Ricardo Ribalda
@ 2022-06-17 23:56 ` Ricardo Ribalda
  8 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-17 23:56 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec
  Cc: Ricardo Ribalda

The device does not implement the power line control correctly. Add a
corresponding control mapping override.

Bus 001 Device 003: ID 5986:1172 Acer, Inc EasyCamera
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x5986 Acer, Inc
  idProduct          0x1172
  bcdDevice           56.04
  iManufacturer           3 Bison
  iProduct                1 EasyCamera
  iSerial                 2
  bNumConfigurations      1

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 387b85fa1998..e037d46b958e 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -3240,6 +3240,15 @@ static const struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
+	/* Acer EasyCamera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x1172,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= (kernel_ulong_t)&uvc_ctrl_power_line_limited },
 	/* Intel RealSense D4M */
 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
 				| USB_DEVICE_ID_MATCH_INT_INFO,
-- 
2.37.0.rc0.104.g0611611a94-goog


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v8 4/9] media: uvcvideo: Use standard names for menus
  2022-06-17 23:56 ` [PATCH v8 4/9] media: uvcvideo: Use standard names for menus Ricardo Ribalda
@ 2022-06-18  7:50   ` Ricardo Ribalda
  0 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda @ 2022-06-18  7:50 UTC (permalink / raw)
  To: Laurent Pinchart, Mauro Carvalho Chehab, linux-media,
	linux-kernel, tfiga, senozhatsky, yunkec

Hi Laurent

On Sat, 18 Jun 2022 at 01:56, Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Instead of duplicating the menu info, use the one from the core.
> Also, do not use extra memory for 1:1 mappings.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 116 +++++++++++++++++++++----------
>  drivers/media/usb/uvc/uvc_v4l2.c |  80 ++++++++++++++++-----
>  drivers/media/usb/uvc/uvcvideo.h |   3 +-
>  include/uapi/linux/uvcvideo.h    |   3 +-
>  4 files changed, 144 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index a03714c3a265..1a3021a16b76 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -362,19 +362,31 @@ static const u32 uvc_control_classes[] = {
>         V4L2_CID_USER_CLASS,
>  };
>
> -static const struct uvc_menu_info power_line_frequency_controls[] = {
> -       { 0, "Disabled" },
> -       { 1, "50 Hz" },
> -       { 2, "60 Hz" },
> -       { 3, "Auto" },
> -};
> +static const int exposure_auto_mapping[] = { 2, 1, 4, 8 };
>
> -static const struct uvc_menu_info exposure_auto_controls[] = {
> -       { 2, "Auto Mode" },
> -       { 1, "Manual Mode" },
> -       { 4, "Shutter Priority Mode" },
> -       { 8, "Aperture Priority Mode" },
> -};
> +static u32 uvc_mapping_get_menu_value(struct uvc_control_mapping *mapping,
> +                                     u32 idx)
> +{
> +       if (!test_bit(idx, &mapping->menu_mask))
> +               return 0;
> +
> +       if (mapping->menu_mapping)
> +               return mapping->menu_mapping[idx];
> +
> +       return idx;
> +}
> +
> +static const char
> +*uvc_mapping_get_menu_name(struct uvc_control_mapping *mapping, u32 idx)
> +{
> +       if (!test_bit(idx, &mapping->menu_mask))
> +               return NULL;
> +
> +       if (mapping->menu_names)
> +               return mapping->menu_names[idx];
> +
> +       return v4l2_ctrl_get_menu(mapping->id)[idx];
> +}
>
>  static s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
>         u8 query, const u8 *data)
> @@ -523,9 +535,9 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
>                 .offset         = 0,
>                 .v4l2_type      = V4L2_CTRL_TYPE_MENU,
>                 .data_type      = UVC_CTRL_DATA_TYPE_BITMASK,
> -               .menu_info      = exposure_auto_controls,
> +               .menu_mapping   = exposure_auto_mapping,
>                 .menu_mask      =
> -                       BIT_MASK(ARRAY_SIZE(exposure_auto_controls)),
> +                       GENMASK(ARRAY_SIZE(exposure_auto_mapping) - 1, 0),
>                 .slave_ids      = { V4L2_CID_EXPOSURE_ABSOLUTE, },
>         },
>         {
> @@ -730,9 +742,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
>                 .offset         = 0,
>                 .v4l2_type      = V4L2_CTRL_TYPE_MENU,
>                 .data_type      = UVC_CTRL_DATA_TYPE_ENUM,
> -               .menu_info      = power_line_frequency_controls,
>                 .menu_mask      =
> -                       BIT_MASK(ARRAY_SIZE(power_line_frequency_controls) - 1),
> +                       GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0),
>         },
>  };
>
> @@ -745,9 +756,8 @@ static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
>                 .offset         = 0,
>                 .v4l2_type      = V4L2_CTRL_TYPE_MENU,
>                 .data_type      = UVC_CTRL_DATA_TYPE_ENUM,
> -               .menu_info      = power_line_frequency_controls,
>                 .menu_mask      =
> -                       BIT_MASK(ARRAY_SIZE(power_line_frequency_controls)),
> +                       GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0),
>         },
>  };
>
> @@ -970,13 +980,17 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping,
>         s32 value = mapping->get(mapping, UVC_GET_CUR, data);
>
>         if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
> -               const struct uvc_menu_info *menu = mapping->menu_info;
>                 unsigned int i;
>
> -               for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
> +               for (i = 1; BIT(i) <= mapping->menu_mask; ++i) {
> +                       u32 menu_value;
> +
>                         if (!test_bit(i, &mapping->menu_mask))
>                                 continue;
> -                       if (menu->value == value) {
> +
> +                       menu_value = uvc_mapping_get_menu_value(mapping, i);
> +
> +                       if (menu_value == value) {
>                                 value = i;
>                                 break;
>                         }
> @@ -1108,7 +1122,6 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>  {
>         struct uvc_control_mapping *master_map = NULL;
>         struct uvc_control *master_ctrl = NULL;
> -       const struct uvc_menu_info *menu;
>         unsigned int i;
>
>         memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> @@ -1153,11 +1166,15 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>                 v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1;
>                 v4l2_ctrl->step = 1;
>
> -               menu = mapping->menu_info;
> -               for (i = 1; BIT(i) <= mapping->menu_mask; ++i, ++menu) {
> +               for (i = 1; BIT(i) <= mapping->menu_mask; ++i) {
> +                       u32 menu_value;
> +
>                         if (!test_bit(i, &mapping->menu_mask))
>                                 continue;
> -                       if (menu->value == v4l2_ctrl->default_value) {
> +
> +                       menu_value = uvc_mapping_get_menu_value(mapping, i);
> +
> +                       if (menu_value == v4l2_ctrl->default_value) {
>                                 v4l2_ctrl->default_value = i;
>                                 break;
>                         }
> @@ -1250,11 +1267,11 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>  int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
>         struct v4l2_querymenu *query_menu)
>  {
> -       const struct uvc_menu_info *menu_info;
>         struct uvc_control_mapping *mapping;
>         struct uvc_control *ctrl;
>         u32 index = query_menu->index;
>         u32 id = query_menu->id;
> +       const char *name;
>         int ret;
>
>         memset(query_menu, 0, sizeof(*query_menu));
> @@ -1276,11 +1293,10 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
>                 goto done;
>         }
>
> -       menu_info = &mapping->menu_info[query_menu->index];
> -
>         if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
>             (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
>                 s32 bitmap;
> +               u32 menu_value;
>
>                 if (!ctrl->cached) {
>                         ret = uvc_ctrl_populate_cache(chain, ctrl);
> @@ -1288,15 +1304,22 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
>                                 goto done;
>                 }
>
> +               menu_value = uvc_mapping_get_menu_value(mapping,
> +                                                       query_menu->index);
> +
>                 bitmap = mapping->get(mapping, UVC_GET_RES,
>                                       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> -               if (!(bitmap & menu_info->value)) {
> +               if (!(bitmap & menu_value)) {
>                         ret = -EINVAL;
>                         goto done;
>                 }
>         }
>
> -       strscpy(query_menu->name, menu_info->name, sizeof(query_menu->name));
> +       name = uvc_mapping_get_menu_name(mapping, query_menu->index);
> +       if (name)
> +               strscpy(query_menu->name, name, sizeof(query_menu->name));
> +       else
> +               ret = -EINVAL;
>
>  done:
>         mutex_unlock(&chain->ctrl_mutex);
> @@ -1783,7 +1806,7 @@ int uvc_ctrl_set(struct uvc_fh *handle,
>                 if (!test_bit(xctrl->value, &mapping->menu_mask))
>                         return -EINVAL;
>
> -               value = mapping->menu_info[xctrl->value].value;
> +               value = uvc_mapping_get_menu_value(mapping, xctrl->value);
>
>                 /* Valid menu indices are reported by the GET_RES request for
>                  * UVC controls that support it.
> @@ -2229,12 +2252,28 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
>
>         INIT_LIST_HEAD(&map->ev_subs);
>
> -       size = sizeof(*mapping->menu_info) * fls(mapping->menu_mask);
> -       map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
> -       if (map->menu_info == NULL) {
> -               kfree(map->name);
> -               kfree(map);
> -               return -ENOMEM;
> +       if (mapping->menu_mapping && mapping->menu_mask) {
> +               size = sizeof(mapping->menu_mapping[0]) *
> +                             fls(mapping->menu_mask);
> +               map->menu_mapping = kmemdup(mapping->menu_mapping, size,
> +                                           GFP_KERNEL);
> +               if (!map->menu_mapping) {
> +                       kfree(map->name);
> +                       kfree(map);
> +                       return -ENOMEM;
> +               }
> +       }
> +       if (mapping->menu_names && mapping->menu_mask) {
> +               size = sizeof(mapping->menu_names[0]) *
> +                             fls(mapping->menu_mask);
> +               map->menu_names = kmemdup(mapping->menu_names, size,
> +                                         GFP_KERNEL);
> +               if (!map->menu_names) {
> +                       kfree(map->menu_mapping);
> +                       kfree(map->name);
> +                       kfree(map);
> +                       return -ENOMEM;
> +               }
>         }
>
>         if (map->get == NULL)
> @@ -2577,7 +2616,8 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
>
>         list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
>                 list_del(&mapping->list);
> -               kfree(mapping->menu_info);
> +               kfree(mapping->menu_names);
> +               kfree(mapping->menu_mapping);
>                 kfree(mapping->name);
>                 kfree(mapping);
>         }
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index 85aced173daa..0ba1eb92df8e 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -25,6 +25,64 @@
>
>  #include "uvcvideo.h"
>
> +static int uvc_control_xu_2_mapping(struct uvc_control_mapping *map,
> +                                   struct uvc_xu_control_mapping *xmap)
> +{
> +       char (*names)[UVC_MENU_NAME_LEN];
> +       unsigned int i;
> +       u32 *mapping;
> +       size_t size;
> +
> +       /* Prevent excessive memory consumption, as well as integer
> +        * overflows.
> +        */
> +       if (xmap->menu_count == 0 ||
> +           xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES)
> +               return -EINVAL;
> +
> +       map->menu_mask = BIT_MASK(xmap->menu_count);
> +
> +       size = xmap->menu_count * sizeof(*map->menu_mapping);
> +       mapping = kzalloc(size, GFP_KERNEL);
> +       if (!mapping)
> +               return -ENOMEM;
> +
> +       for (i = 0; i < xmap->menu_count ; i++)
> +               if (copy_from_user(&mapping[i], &xmap->menu_info[i].value,
> +                                  sizeof(mapping[i]))) {
> +                       kfree(mapping);
> +                       return -ENOMEM;
> +               }
> +
> +       map->menu_mapping = mapping;
> +
> +       /*
> +        * Always use the standard naming if available.
> +        */
> +       if (v4l2_ctrl_get_menu(map->id))
> +               return 0;

There is a potential invalid memory access here if we use the standard
naming for custom controls.
let's say that the user says that there are 32 values, but picks a
CTRL_ID that only has 3 values.

Simply removing the previous 2 lines should be enough to take care of that.

I will send a new version once there is more feedback on the series.

[did I said that I hate user defined controls :P, is anyone using it? ]

> +
> +       size = xmap->menu_count * sizeof(map->menu_names[0]);
> +       names = kzalloc(size, GFP_KERNEL);
> +       if (!names) {
> +               kfree(mapping);
> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < xmap->menu_count ; i++) {
> +               /* sizeof(names[i]) - 1: to take care of \0 */
> +               if (copy_from_user(&names[i], &xmap->menu_info[i].name,
> +                                  sizeof(names[i]) - 1)) {
> +                       kfree(names);
> +                       kfree(mapping);
> +                       return -ENOMEM;
> +               }
> +       }
> +       map->menu_names = names;
> +
> +       return 0;
> +}
> +
>  /* ------------------------------------------------------------------------
>   * UVC ioctls
>   */
> @@ -32,7 +90,6 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
>         struct uvc_xu_control_mapping *xmap)
>  {
>         struct uvc_control_mapping *map;
> -       unsigned int size;
>         int ret;
>
>         map = kzalloc(sizeof(*map), GFP_KERNEL);
> @@ -63,23 +120,9 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
>                 break;
>
>         case V4L2_CTRL_TYPE_MENU:
> -               /* Prevent excessive memory consumption, as well as integer
> -                * overflows.
> -                */
> -               if (xmap->menu_count == 0 ||
> -                   xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
> -                       ret = -EINVAL;
> -                       goto free_map;
> -               }
> -
> -               size = xmap->menu_count * sizeof(*map->menu_info);
> -               map->menu_info = memdup_user(xmap->menu_info, size);
> -               if (IS_ERR(map->menu_info)) {
> -                       ret = PTR_ERR(map->menu_info);
> +               ret = uvc_control_xu_2_mapping(map, xmap);
> +               if (ret)
>                         goto free_map;
> -               }
> -
> -               map->menu_mask = BIT_MASK(xmap->menu_count);
>                 break;
>
>         default:
> @@ -91,7 +134,8 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
>
>         ret = uvc_ctrl_add_mapping(chain, map);
>
> -       kfree(map->menu_info);
> +       kfree(map->menu_names);
> +       kfree(map->menu_mapping);
>  free_map:
>         kfree(map);
>
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 0736b8815d79..b702f1c8547b 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -253,7 +253,8 @@ struct uvc_control_mapping {
>         enum v4l2_ctrl_type v4l2_type;
>         u32 data_type;
>
> -       const struct uvc_menu_info *menu_info;
> +       const u32 *menu_mapping;
> +       const char (*menu_names)[UVC_MENU_NAME_LEN];
>         unsigned long menu_mask;
>
>         u32 master_id;
> diff --git a/include/uapi/linux/uvcvideo.h b/include/uapi/linux/uvcvideo.h
> index 8288137387c0..1b64b6aa40b5 100644
> --- a/include/uapi/linux/uvcvideo.h
> +++ b/include/uapi/linux/uvcvideo.h
> @@ -36,9 +36,10 @@
>          UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \
>          UVC_CTRL_FLAG_GET_DEF)
>
> +#define UVC_MENU_NAME_LEN 32
>  struct uvc_menu_info {
>         __u32 value;
> -       __u8 name[32];
> +       __u8 name[UVC_MENU_NAME_LEN];
>  };
>
>  struct uvc_xu_control_mapping {
> --
> 2.37.0.rc0.104.g0611611a94-goog
>


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2022-06-18  7:50 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-17 23:56 [PATCH v7 0/8] uvcvideo: Fix handling of power_line_frequency Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 1/9] media: uvcvideo: Add missing value for power_line_frequency Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 2/9] media: uvcvideo: Add support for per-device control mapping overrides Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 3/9] media: uvcvideo: Implement mask for V4L2_CTRL_TYPE_MENU Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 4/9] media: uvcvideo: Use standard names for menus Ricardo Ribalda
2022-06-18  7:50   ` Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 5/9] media: uvcvideo: Limit power line control for Quanta UVC Webcam Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 6/9] media: uvcvideo: Limit power line control for Chicony Easycamera Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 7/9] " Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 8/9] media: uvcvideo: Limit power line control for Quanta cameras Ricardo Ribalda
2022-06-17 23:56 ` [PATCH v8 9/9] media: uvcvideo: Limit power line control for Acer EasyCamera Ricardo Ribalda

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.