* [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation.
@ 2025-06-05 17:52 Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
` (11 more replies)
0 siblings, 12 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
The ACPI has ways to annotate the location of a USB device. Wire that
annotation to a v4l2 control.
To support all possible devices, add a way to annotate USB devices on DT
as well. The original binding discussion happened here:
https://lore.kernel.org/linux-devicetree/20241212-usb-orientation-v1-1-0b69adf05f37@chromium.org/
The following patches are needed regardless if we finally add support
for orientation and rotation or not:
- media: uvcvideo: Always set default_value
- media: uvcvideo: Do not create MC entities for virtual entities
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
Changes in v2:
- Add support for rotation
- Rename fwnode to swentity
- Remove the patch to move the gpio file
- Remove patches already in media-committers
- Change priority of data origins
- Patch mipi-disco
- Link to v1: https://lore.kernel.org/r/20250403-uvc-orientation-v1-0-1a0cc595a62d@chromium.org
---
Ricardo Ribalda (12):
media: uvcvideo: Always set default_value
media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes
media: ipu-bridge: Use v4l2_fwnode_device_parse helper
media: ipu-bridge: Use v4l2_fwnode for unknown rotations
dt-bindings: usb: usb-device: Add orientation and rotation
media: uvcvideo: Make uvc_alloc_entity non static
media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
media: uvcvideo: Add uvc_ctrl_query_entity helper
media: uvcvideo: Add get_* functions to uvc_entity
media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
media: uvcvideo: Do not create MC entities for virtual entities
.../devicetree/bindings/usb/usb-device.yaml | 10 ++
drivers/acpi/mipi-disco-img.c | 15 ---
drivers/media/pci/intel/ipu-bridge.c | 52 ++++----
drivers/media/usb/uvc/Makefile | 3 +-
drivers/media/usb/uvc/uvc_ctrl.c | 132 ++++++++++++++-------
drivers/media/usb/uvc/uvc_driver.c | 18 ++-
drivers/media/usb/uvc/uvc_entity.c | 11 ++
drivers/media/usb/uvc/uvc_swentity.c | 118 ++++++++++++++++++
drivers/media/usb/uvc/uvcvideo.h | 29 +++++
drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++-
include/linux/usb/uvc.h | 3 +
11 files changed, 377 insertions(+), 99 deletions(-)
---
base-commit: 5e1ff2314797bf53636468a97719a8222deca9ae
change-id: 20250403-uvc-orientation-5f7f19da5adb
Best regards,
--
Ricardo Ribalda <ribalda@chromium.org>
^ permalink raw reply [flat|nested] 62+ messages in thread
* [PATCH v2 01/12] media: uvcvideo: Always set default_value
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-06-29 17:39 ` Laurent Pinchart
2025-07-14 13:00 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse Ricardo Ribalda
` (10 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
If the control does not support GET_DEF, the field default_value will be
left uninitialized during queryctrl.
Fixes: c0efd232929c ("V4L/DVB (8145a): USB Video Class driver")
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 44b6513c526421943bb9841fb53dc5f8e9f93f02..47e8ccc39234d1769384b55539a21df07f3d57c7 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1497,6 +1497,8 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
+ } else {
+ v4l2_ctrl->default_value = 0;
}
switch (mapping->v4l2_type) {
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-06-29 9:21 ` Sakari Ailus
2025-07-14 13:03 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
` (9 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Currently v4l2_fwnode_device_parse() obtains the orientation and
rotation via fwnode properties.
Extend the function to support as well ACPI devices with _PLD info.
We give a higher priority to fwnode, because it might contain quirks
injected via swnodes.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 6 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -15,6 +15,7 @@
* Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*/
#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
@@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
}
EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
-int v4l2_fwnode_device_parse(struct device *dev,
- struct v4l2_fwnode_device_properties *props)
+static int v4l2_fwnode_device_parse_acpi(struct device *dev,
+ struct v4l2_fwnode_device_properties *props)
+{
+ struct acpi_pld_info *pld;
+ int ret = 0;
+
+ if (!is_acpi_device_node(dev_fwnode(dev)))
+ return 0;
+
+ if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
+ dev_dbg(dev, "acpi _PLD call failed\n");
+ return 0;
+ }
+
+ if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
+ switch (pld->panel) {
+ case ACPI_PLD_PANEL_FRONT:
+ props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
+ break;
+ case ACPI_PLD_PANEL_BACK:
+ props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
+ break;
+ case ACPI_PLD_PANEL_TOP:
+ case ACPI_PLD_PANEL_LEFT:
+ case ACPI_PLD_PANEL_RIGHT:
+ case ACPI_PLD_PANEL_UNKNOWN:
+ props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
+ break;
+ default:
+ dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
+ switch (pld->rotation) {
+ case 0 ... 7:
+ props->rotation = pld->rotation * 45;
+ break;
+ default:
+ dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ ACPI_FREE(pld);
+ return ret;
+}
+
+static int v4l2_fwnode_device_parse_dt(struct device *dev,
+ struct v4l2_fwnode_device_properties *props)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
u32 val;
int ret;
- memset(props, 0, sizeof(*props));
-
- props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
ret = fwnode_property_read_u32(fwnode, "orientation", &val);
if (!ret) {
switch (val) {
@@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
dev_dbg(dev, "device orientation: %u\n", val);
}
- props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
ret = fwnode_property_read_u32(fwnode, "rotation", &val);
if (!ret) {
if (val >= 360) {
@@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
return 0;
}
+
+int v4l2_fwnode_device_parse(struct device *dev,
+ struct v4l2_fwnode_device_properties *props)
+{
+ int ret;
+
+ memset(props, 0, sizeof(*props));
+
+ props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
+ props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
+
+ /* Start by looking into swnodes and dt. */
+ ret = v4l2_fwnode_device_parse_dt(dev, props);
+ if (ret)
+ return ret;
+
+ /* Orientation and rotation found!, we are ready. */
+ if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
+ props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
+ return 0;
+
+ /* Let's check the acpi table. */
+ return v4l2_fwnode_device_parse_acpi(dev, props);
+}
EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
/*
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-06-29 9:24 ` Sakari Ailus
` (2 more replies)
2025-06-05 17:52 ` [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper Ricardo Ribalda
` (8 subsequent siblings)
11 siblings, 3 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
The function v4l2_fwnode_device_parse() is not capable of parsint the
_PLD method, there is no need to duplicate the rotation information in a
swnode.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/acpi/mipi-disco-img.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c
index 5b85989f96beeb726f59ac9e12e965a215fb38f6..b58b5ba22a47a4afc5212998074d322f0b7586dc 100644
--- a/drivers/acpi/mipi-disco-img.c
+++ b/drivers/acpi/mipi-disco-img.c
@@ -617,21 +617,6 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2)
adev_fwnode = acpi_fwnode_handle(adev);
- /*
- * If the "rotation" property is not present, but _PLD is there,
- * evaluate it to get the "rotation" value.
- */
- if (!fwnode_property_present(adev_fwnode, "rotation")) {
- struct acpi_pld_info *pld;
-
- if (acpi_get_physical_device_location(handle, &pld)) {
- swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] =
- PROPERTY_ENTRY_U32("rotation",
- pld->rotation * 45U);
- kfree(pld);
- }
- }
-
if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val))
swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] =
PROPERTY_ENTRY_U32("clock-frequency", val);
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (2 preceding siblings ...)
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-06-06 4:27 ` kernel test robot
2025-07-14 13:11 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations Ricardo Ribalda
` (7 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
v4l2_fwnode_device_parse now supports acpi devices as well. Use the
helper instead of re-implement the logic.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/pci/intel/ipu-bridge.c | 32 ++++++--------------------------
1 file changed, 6 insertions(+), 26 deletions(-)
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 83e682e1a4b77d9d97b2988750732d0b7c9087b3..020aa52f590d66b6d333adc56ebfb9ab0561db51 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -253,36 +253,16 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
{
- enum v4l2_fwnode_orientation orientation;
- struct acpi_pld_info *pld = NULL;
+ struct v4l2_fwnode_device_properties props;
+ int ret;
- if (!acpi_get_physical_device_location(ACPI_PTR(adev->handle), &pld)) {
- dev_warn(ADEV_DEV(adev), "_PLD call failed, using default orientation\n");
+ ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
+ if (!ret || props.rotation == V4L2_FWNODE_PROPERTY_UNSET) {
+ dev_warn(ADEV_DEV(adev), "Using default orientation\n");
return V4L2_FWNODE_ORIENTATION_EXTERNAL;
}
- switch (pld->panel) {
- case ACPI_PLD_PANEL_FRONT:
- orientation = V4L2_FWNODE_ORIENTATION_FRONT;
- break;
- case ACPI_PLD_PANEL_BACK:
- orientation = V4L2_FWNODE_ORIENTATION_BACK;
- break;
- case ACPI_PLD_PANEL_TOP:
- case ACPI_PLD_PANEL_LEFT:
- case ACPI_PLD_PANEL_RIGHT:
- case ACPI_PLD_PANEL_UNKNOWN:
- orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
- break;
- default:
- dev_warn(ADEV_DEV(adev), "Unknown _PLD panel val %d\n",
- pld->panel);
- orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
- break;
- }
-
- ACPI_FREE(pld);
- return orientation;
+ return props.orientation;
}
int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (3 preceding siblings ...)
2025-06-05 17:52 ` [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-07-07 21:44 ` Sakari Ailus
2025-06-05 17:52 ` [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation Ricardo Ribalda
` (6 subsequent siblings)
11 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
The v4l2_fwnode_device_properties contains information about the
rotation. Use it if the ssdb data is inconclusive.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/pci/intel/ipu-bridge.c | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 020aa52f590d66b6d333adc56ebfb9ab0561db51..6f436a8b4d23373af8a6668530333a827eca467a 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -236,37 +236,41 @@ static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
}
static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
- struct ipu_sensor_ssdb *ssdb)
+ struct ipu_sensor_ssdb *ssdb,
+ struct v4l2_fwnode_device_properties *props)
{
switch (ssdb->degree) {
case IPU_SENSOR_ROTATION_NORMAL:
return 0;
case IPU_SENSOR_ROTATION_INVERTED:
return 180;
- default:
+ }
+
+ if (props->rotation == V4L2_FWNODE_PROPERTY_UNSET) {
dev_warn(ADEV_DEV(adev),
"Unknown rotation %d. Assume 0 degree rotation\n",
ssdb->degree);
return 0;
}
+
+ return props->rotation;
}
-static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
+static enum v4l2_fwnode_orientation
+ipu_bridge_parse_orientation(struct acpi_device *adev,
+ struct v4l2_fwnode_device_properties *props)
{
- struct v4l2_fwnode_device_properties props;
- int ret;
-
- ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
- if (!ret || props.rotation == V4L2_FWNODE_PROPERTY_UNSET) {
+ if (props->orientation == V4L2_FWNODE_PROPERTY_UNSET) {
dev_warn(ADEV_DEV(adev), "Using default orientation\n");
return V4L2_FWNODE_ORIENTATION_EXTERNAL;
}
- return props.orientation;
+ return props->orientation;
}
int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
{
+ struct v4l2_fwnode_device_properties props;
struct ipu_sensor_ssdb ssdb = {};
int ret;
@@ -274,6 +278,10 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
if (ret)
return ret;
+ ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
+ if (ret)
+ return ret;
+
if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {
dev_warn(ADEV_DEV(adev), "Unknown VCM type %d\n", ssdb.vcmtype);
ssdb.vcmtype = 0;
@@ -287,8 +295,8 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
sensor->link = ssdb.link;
sensor->lanes = ssdb.lanes;
sensor->mclkspeed = ssdb.mclkspeed;
- sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb);
- sensor->orientation = ipu_bridge_parse_orientation(adev);
+ sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb, &props);
+ sensor->orientation = ipu_bridge_parse_orientation(adev, &props);
if (ssdb.vcmtype)
sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1];
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (4 preceding siblings ...)
2025-06-05 17:52 ` [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations Ricardo Ribalda
@ 2025-06-05 17:52 ` Ricardo Ribalda
2025-06-25 18:56 ` Rob Herring
2025-06-05 17:53 ` [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static Ricardo Ribalda
` (5 subsequent siblings)
11 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:52 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
For some devices, such as cameras, the OS needs to know where they are
mounted.
ACPI has a property for this purpose, which is parsed by
acpi_get_physical_device_location():
https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/06_Device_Configuration/Device_Configuration.html#pld-physical-location-of-device
In DT we have similar properties for video-interface-devices called
orientation and rotation:
Documentation/devicetree/bindings/media/video-interface-devices.yaml
Add rotation and orientation for usb-devices that matches the already
existing properties of video-interface-devices.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
Documentation/devicetree/bindings/usb/usb-device.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml
index c676956810331b81f11f3624340fc3e612c98315..a44eb24c657993f88145377a4706ec419b6cd998 100644
--- a/Documentation/devicetree/bindings/usb/usb-device.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-device.yaml
@@ -44,6 +44,14 @@ properties:
- minimum: 1
maximum: 255
+ orientation:
+ description: If present, specifies the orientation of the usb device.
+ $ref: /schemas/media/video-interface-devices.yaml#/properties/orientation
+
+ rotation:
+ description: If present, specifies the rotation of the usb device.
+ $ref: /schemas/media/video-interface-devices.yaml#/properties/rotation
+
"#address-cells":
description: should be 1 for hub nodes with device nodes,
should be 2 for device nodes with interface nodes.
@@ -103,6 +111,8 @@ examples:
device@2 {
compatible = "usb123,4567";
reg = <2>;
+ orientation = <0>;
+ rotation = <90>;
};
device@3 {
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (5 preceding siblings ...)
2025-06-05 17:52 ` [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 17:43 ` Laurent Pinchart
2025-07-14 13:31 ` Hans de Goede
2025-06-05 17:53 ` [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION Ricardo Ribalda
` (4 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
The function is useful for other compilation units.
This is just a refactor patch, no new functionality is added.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_driver.c | 4 ++--
drivers/media/usb/uvc/uvcvideo.h | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index da24a655ab68cc0957762f2b67387677c22224d1..bcc97f71fa1703aea1119469fb32659c17d9409a 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -792,8 +792,8 @@ static const u8 uvc_media_transport_input_guid[16] =
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
- unsigned int num_pads, unsigned int extra_size)
+struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
+ unsigned int extra_size)
{
struct uvc_entity *entity;
unsigned int num_inputs;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index b9f8eb62ba1d82ea7788cf6c10cc838a429dbc9e..dc23d8a97340dc4615d4182232d395106e6d9ed5 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -684,6 +684,8 @@ do { \
*/
struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
+struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
+ unsigned int extra_size);
/* Video buffers queue management. */
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (6 preceding siblings ...)
2025-06-05 17:53 ` [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 17:50 ` Laurent Pinchart
2025-07-14 14:36 ` Hans de Goede
2025-06-05 17:53 ` [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper Ricardo Ribalda
` (3 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Fetch the orientation from the fwnode and map it into a control.
The uvc driver does not use the media controller, so we need to create a
virtual entity, like we previously did with the external gpio.
We do not re-purpose the external gpio entity because its is planned to
remove it.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/Makefile | 3 +-
drivers/media/usb/uvc/uvc_ctrl.c | 21 +++++++++++
drivers/media/usb/uvc/uvc_driver.c | 14 +++++--
drivers/media/usb/uvc/uvc_entity.c | 1 +
drivers/media/usb/uvc/uvc_swentity.c | 73 ++++++++++++++++++++++++++++++++++++
drivers/media/usb/uvc/uvcvideo.h | 14 +++++++
include/linux/usb/uvc.h | 3 ++
7 files changed, 125 insertions(+), 4 deletions(-)
diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile
index 4f9eee4f81ab6436a8b90324a688a149b2c3bcd1..b4398177c4bb0a9bd49dfd4ca7f2e933b4a1d7df 100644
--- a/drivers/media/usb/uvc/Makefile
+++ b/drivers/media/usb/uvc/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
- uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o
+ uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o \
+ uvc_swentity.o
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
uvcvideo-objs += uvc_entity.o
endif
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 47e8ccc39234d1769384b55539a21df07f3d57c7..b2768080c08aafa85acb9b7f318672c043d84e55 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -376,6 +376,13 @@ static const struct uvc_control_info uvc_ctrls[] = {
| UVC_CTRL_FLAG_GET_DEF
| UVC_CTRL_FLAG_AUTO_UPDATE,
},
+ {
+ .entity = UVC_GUID_SWENTITY,
+ .selector = 0,
+ .index = 0,
+ .size = 1,
+ .flags = UVC_CTRL_FLAG_GET_CUR,
+ },
};
static const u32 uvc_control_classes[] = {
@@ -975,6 +982,17 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.data_type = UVC_CTRL_DATA_TYPE_BITMASK,
.name = "Region of Interest Auto Ctrls",
},
+ {
+ .id = V4L2_CID_CAMERA_ORIENTATION,
+ .entity = UVC_GUID_SWENTITY,
+ .selector = 0,
+ .size = 8,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
+ V4L2_CAMERA_ORIENTATION_FRONT),
+ },
};
/* ------------------------------------------------------------------------
@@ -3210,6 +3228,9 @@ static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
} else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
bmControls = entity->gpio.bmControls;
bControlSize = entity->gpio.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == UVC_SWENTITY_UNIT) {
+ bmControls = entity->swentity.bmControls;
+ bControlSize = entity->swentity.bControlSize;
}
/* Remove bogus/blacklisted controls */
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index bcc97f71fa1703aea1119469fb32659c17d9409a..96eeb3aee546487d15f3c30dfe1775189ddf7e47 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
return -1;
}
- /* Add GPIO entity to the first chain. */
- if (dev->gpio_unit) {
+ /* Add virtual entities to the first chain. */
+ if (dev->gpio_unit || dev->swentity_unit) {
chain = list_first_entry(&dev->chains,
struct uvc_video_chain, list);
- list_add_tail(&dev->gpio_unit->chain, &chain->entities);
+ if (dev->gpio_unit)
+ list_add_tail(&dev->gpio_unit->chain, &chain->entities);
+ if (dev->swentity_unit)
+ list_add_tail(&dev->swentity_unit->chain,
+ &chain->entities);
}
return 0;
@@ -2249,6 +2253,10 @@ static int uvc_probe(struct usb_interface *intf,
if (ret < 0)
goto error;
+ ret = uvc_swentity_init(dev);
+ if (ret < 0)
+ goto error;
+
dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
dev->uvc_version >> 8, dev->uvc_version & 0xff,
udev->product ? udev->product : "<unnamed>",
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index cc68dd24eb42dce5b2846ca52a8dfa499c8aed96..d1a652ef35ec34801bd39a5124b834edf838a79e 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
case UVC_EXTERNAL_VENDOR_SPECIFIC:
case UVC_EXT_GPIO_UNIT:
+ case UVC_SWENTITY_UNIT:
default:
function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
break;
diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
new file mode 100644
index 0000000000000000000000000000000000000000..702a2c26e029a0655dade177ed2a9b88d7a4136d
--- /dev/null
+++ b/drivers/media/usb/uvc/uvc_swentity.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * uvc_swentity.c -- USB Video Class driver
+ *
+ * Copyright 2025 Google LLC
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb/uvc.h>
+#include <media/v4l2-fwnode.h>
+#include "uvcvideo.h"
+
+static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size)
+{
+ if (size < 1)
+ return -EINVAL;
+
+ switch (entity->swentity.props.orientation) {
+ case V4L2_FWNODE_ORIENTATION_FRONT:
+ *(u8 *)data = V4L2_CAMERA_ORIENTATION_FRONT;
+ break;
+ case V4L2_FWNODE_ORIENTATION_BACK:
+ *(u8 *)data = V4L2_CAMERA_ORIENTATION_BACK;
+ break;
+ default:
+ *(u8 *)data = V4L2_CAMERA_ORIENTATION_EXTERNAL;
+ }
+
+ return 0;
+}
+
+static int uvc_swentity_get_info(struct uvc_device *dev,
+ struct uvc_entity *entity, u8 cs, u8 *caps)
+{
+ *caps = UVC_CONTROL_CAP_GET;
+ return 0;
+}
+
+int uvc_swentity_init(struct uvc_device *dev)
+{
+ static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
+ struct v4l2_fwnode_device_properties props;
+ struct uvc_entity *unit;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
+ if (ret)
+ return dev_err_probe(&dev->intf->dev, ret,
+ "Can't parse fwnode\n");
+
+ if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
+ return 0;
+
+ unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
+ if (!unit)
+ return -ENOMEM;
+
+ memcpy(unit->guid, uvc_swentity_guid, sizeof(unit->guid));
+ unit->swentity.props = props;
+ unit->swentity.bControlSize = 1;
+ unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
+ unit->swentity.bmControls[0] = 1;
+ unit->get_cur = uvc_swentity_get_cur;
+ unit->get_info = uvc_swentity_get_info;
+ strscpy(unit->name, "SWENTITY", sizeof(unit->name));
+
+ list_add_tail(&unit->list, &dev->entities);
+
+ dev->swentity_unit = unit;
+
+ return 0;
+}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index dc23d8a97340dc4615d4182232d395106e6d9ed5..a931750bdea25b9062dcc7644bf5f2ed89c1cb4c 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -19,6 +19,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-fwnode.h>
/* --------------------------------------------------------------------------
* UVC constants
@@ -41,6 +42,9 @@
#define UVC_EXT_GPIO_UNIT 0x7ffe
#define UVC_EXT_GPIO_UNIT_ID 0x100
+#define UVC_SWENTITY_UNIT 0x7ffd
+#define UVC_SWENTITY_UNIT_ID 0x101
+
/* ------------------------------------------------------------------------
* Driver specific constants.
*/
@@ -242,6 +246,12 @@ struct uvc_entity {
int irq;
bool initialized;
} gpio;
+
+ struct {
+ u8 bControlSize;
+ u8 *bmControls;
+ struct v4l2_fwnode_device_properties props;
+ } swentity;
};
u8 bNrInPins;
@@ -617,6 +627,7 @@ struct uvc_device {
} async_ctrl;
struct uvc_entity *gpio_unit;
+ struct uvc_entity *swentity_unit;
};
enum uvc_handle_state {
@@ -836,4 +847,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
size_t size);
+/* swentity */
+int uvc_swentity_init(struct uvc_device *dev);
+
#endif
diff --git a/include/linux/usb/uvc.h b/include/linux/usb/uvc.h
index bce95153e5a65613a710d7316fc17cf5462b5bce..88a23e8919d1294da4308e0e3ca0eccdc66a318f 100644
--- a/include/linux/usb/uvc.h
+++ b/include/linux/usb/uvc.h
@@ -29,6 +29,9 @@
#define UVC_GUID_EXT_GPIO_CONTROLLER \
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
+#define UVC_GUID_SWENTITY \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
#define UVC_GUID_FORMAT_MJPEG \
{ 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (7 preceding siblings ...)
2025-06-05 17:53 ` [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 18:01 ` Laurent Pinchart
2025-07-14 14:24 ` Hans de Goede
2025-06-05 17:53 ` [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity Ricardo Ribalda
` (2 subsequent siblings)
11 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Create a helper function to query a control. The new function reduces
the number of arguments, calculates the length of the operation and
redirects the operation to the hardware or to the entity private
functions.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++--------------------
1 file changed, 41 insertions(+), 40 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b2768080c08aafa85acb9b7f318672c043d84e55..21ec7b978bc7aca21db7cb8fd5d135d876f3330c 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -576,6 +576,34 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
};
+static int uvc_ctrl_query_entity(struct uvc_device *dev,
+ const struct uvc_control *ctrl, u8 query,
+ void *data)
+{
+ u16 len;
+
+ switch (query) {
+ case UVC_GET_INFO:
+ len = 1;
+ break;
+ case UVC_GET_LEN:
+ len = 2;
+ break;
+ default:
+ len = ctrl->info.size;
+ }
+
+ if (query == UVC_GET_CUR && ctrl->entity->get_cur)
+ return ctrl->entity->get_cur(dev, ctrl->entity,
+ ctrl->info.selector, data, len);
+ if (query == UVC_GET_INFO && ctrl->entity->get_info)
+ return ctrl->entity->get_info(dev, ctrl->entity,
+ ctrl->info.selector, data);
+
+ return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
+ ctrl->info.selector, data, len);
+}
+
static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
struct uvc_video_chain *chain, struct uvc_control *ctrl)
{
@@ -1222,35 +1250,27 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
int ret;
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
- ctrl->info.size);
+ ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_DEF,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
if (ret < 0)
return ret;
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
- ctrl->info.size);
+ ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
if (ret < 0)
return ret;
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
- ctrl->info.size);
+ ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
if (ret < 0)
return ret;
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
- ctrl->info.size);
+ ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (ret < 0) {
if (UVC_ENTITY_TYPE(ctrl->entity) !=
UVC_VC_EXTENSION_UNIT)
@@ -1291,16 +1311,7 @@ static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
return 0;
}
- if (ctrl->entity->get_cur)
- ret = ctrl->entity->get_cur(chain->dev, ctrl->entity,
- ctrl->info.selector, data,
- ctrl->info.size);
- else
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
- ctrl->entity->id, chain->dev->intfnum,
- ctrl->info.selector, data,
- ctrl->info.size);
-
+ ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_CUR, data);
if (ret < 0)
return ret;
@@ -2164,11 +2175,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
continue;
if (!rollback)
- ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
- dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
-
+ ret = uvc_ctrl_query_entity(dev, ctrl, UVC_SET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (!ret)
processed_ctrls++;
@@ -2570,13 +2578,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
if (data == NULL)
return -ENOMEM;
- if (ctrl->entity->get_info)
- ret = ctrl->entity->get_info(dev, ctrl->entity,
- ctrl->info.selector, data);
- else
- ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
- dev->intfnum, info->selector, data, 1);
-
+ ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_INFO, data);
if (!ret) {
info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
UVC_CTRL_FLAG_SET_CUR |
@@ -2654,8 +2656,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
info->selector = ctrl->index + 1;
/* Query and verify the control length (GET_LEN) */
- ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
- info->selector, data, 2);
+ ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_LEN, data);
if (ret < 0) {
uvc_dbg(dev, CONTROL,
"GET_LEN failed on control %pUl/%u (%d)\n",
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (8 preceding siblings ...)
2025-06-05 17:53 ` [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 18:12 ` Laurent Pinchart
2025-06-05 17:53 ` [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION Ricardo Ribalda
2025-06-05 17:53 ` [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities Ricardo Ribalda
11 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Virtual entities need to provide more values than get_cur and get_cur
for their controls. Add support for get_def, get_min, get_max and
get_res.
This is a preparation patch.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
2 files changed, 20 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
if (query == UVC_GET_CUR && ctrl->entity->get_cur)
return ctrl->entity->get_cur(dev, ctrl->entity,
ctrl->info.selector, data, len);
+ if (query == UVC_GET_DEF && ctrl->entity->get_def)
+ return ctrl->entity->get_def(dev, ctrl->entity,
+ ctrl->info.selector, data, len);
+ if (query == UVC_GET_MIN && ctrl->entity->get_min)
+ return ctrl->entity->get_min(dev, ctrl->entity,
+ ctrl->info.selector, data, len);
+ if (query == UVC_GET_MAX && ctrl->entity->get_max)
+ return ctrl->entity->get_max(dev, ctrl->entity,
+ ctrl->info.selector, data, len);
+ if (query == UVC_GET_RES && ctrl->entity->get_res)
+ return ctrl->entity->get_res(dev, ctrl->entity,
+ ctrl->info.selector, data, len);
if (query == UVC_GET_INFO && ctrl->entity->get_info)
return ctrl->entity->get_info(dev, ctrl->entity,
ctrl->info.selector, data);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -261,6 +261,14 @@ struct uvc_entity {
u8 cs, u8 *caps);
int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
u8 cs, void *data, u16 size);
+ int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size);
+ int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size);
+ int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size);
+ int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size);
unsigned int ncontrols;
struct uvc_control *controls;
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (9 preceding siblings ...)
2025-06-05 17:53 ` [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 18:14 ` Laurent Pinchart
2025-06-05 17:53 ` [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities Ricardo Ribalda
11 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Fetch the rotation from the fwnode and map it into a control.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_ctrl.c | 22 +++++++++++++--
drivers/media/usb/uvc/uvc_swentity.c | 55 ++++++++++++++++++++++++++++++++----
drivers/media/usb/uvc/uvcvideo.h | 5 ++++
3 files changed, 74 insertions(+), 8 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 59be62ae24a4219fa9d7aacf2ae7382c95362178..5788f0c0f6604da06a7bca1b9999d0957817e75e 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -378,11 +378,18 @@ static const struct uvc_control_info uvc_ctrls[] = {
},
{
.entity = UVC_GUID_SWENTITY,
- .selector = 0,
- .index = 0,
+ .selector = UVC_SWENTITY_ORIENTATION,
+ .index = UVC_SWENTITY_ORIENTATION,
.size = 1,
.flags = UVC_CTRL_FLAG_GET_CUR,
},
+ {
+ .entity = UVC_GUID_SWENTITY,
+ .selector = UVC_SWENTITY_ROTATION,
+ .index = UVC_SWENTITY_ROTATION,
+ .size = 2,
+ .flags = UVC_CTRL_FLAG_GET_RANGE,
+ },
};
static const u32 uvc_control_classes[] = {
@@ -1025,7 +1032,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_CAMERA_ORIENTATION,
.entity = UVC_GUID_SWENTITY,
- .selector = 0,
+ .selector = UVC_SWENTITY_ORIENTATION,
.size = 8,
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_MENU,
@@ -1033,6 +1040,15 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
V4L2_CAMERA_ORIENTATION_FRONT),
},
+ {
+ .id = V4L2_CID_CAMERA_SENSOR_ROTATION,
+ .entity = UVC_GUID_SWENTITY,
+ .selector = UVC_SWENTITY_ROTATION,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
};
/* ------------------------------------------------------------------------
diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
index 702a2c26e029a0655dade177ed2a9b88d7a4136d..60f3166addbeb7d2e431d107b23034d2d11a1812 100644
--- a/drivers/media/usb/uvc/uvc_swentity.c
+++ b/drivers/media/usb/uvc/uvc_swentity.c
@@ -10,10 +10,11 @@
#include <media/v4l2-fwnode.h>
#include "uvcvideo.h"
-static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
- u8 cs, void *data, u16 size)
+static int uvc_swentity_get_orientation(struct uvc_device *dev,
+ struct uvc_entity *entity, u8 cs,
+ void *data, u16 size)
{
- if (size < 1)
+ if (cs != UVC_SWENTITY_ORIENTATION || size != 1)
return -EINVAL;
switch (entity->swentity.props.orientation) {
@@ -30,6 +31,31 @@ static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entit
return 0;
}
+static int uvc_swentity_get_rotation(struct uvc_device *dev,
+ struct uvc_entity *entity, u8 cs, void *data,
+ u16 size)
+{
+ if (cs != UVC_SWENTITY_ROTATION || size != 2)
+ return -EINVAL;
+
+ ((u8 *)data)[0] = entity->swentity.props.rotation;
+ ((u8 *)data)[1] = entity->swentity.props.rotation >> 8;
+
+ return 0;
+}
+
+static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *data, u16 size)
+{
+ switch (cs) {
+ case UVC_SWENTITY_ORIENTATION:
+ return uvc_swentity_get_orientation(dev, entity, cs, data, size);
+ case UVC_SWENTITY_ROTATION:
+ return uvc_swentity_get_rotation(dev, entity, cs, data, size);
+ }
+ return -EINVAL;
+}
+
static int uvc_swentity_get_info(struct uvc_device *dev,
struct uvc_entity *entity, u8 cs, u8 *caps)
{
@@ -37,11 +63,22 @@ static int uvc_swentity_get_info(struct uvc_device *dev,
return 0;
}
+static int uvc_swentity_get_res(struct uvc_device *dev, struct uvc_entity *entity,
+ u8 cs, void *res, u16 size)
+{
+ if (size == 0)
+ return -EINVAL;
+ ((u8 *)res)[0] = 1;
+ memset(res + 1, 0, size - 1);
+ return 0;
+}
+
int uvc_swentity_init(struct uvc_device *dev)
{
static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
struct v4l2_fwnode_device_properties props;
struct uvc_entity *unit;
+ u8 controls = 0;
int ret;
ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
@@ -49,7 +86,11 @@ int uvc_swentity_init(struct uvc_device *dev)
return dev_err_probe(&dev->intf->dev, ret,
"Can't parse fwnode\n");
- if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
+ if (props.orientation != V4L2_FWNODE_PROPERTY_UNSET)
+ controls |= BIT(UVC_SWENTITY_ORIENTATION);
+ if (props.rotation != V4L2_FWNODE_PROPERTY_UNSET)
+ controls |= BIT(UVC_SWENTITY_ROTATION);
+ if (!controls)
return 0;
unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
@@ -60,9 +101,13 @@ int uvc_swentity_init(struct uvc_device *dev)
unit->swentity.props = props;
unit->swentity.bControlSize = 1;
unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
- unit->swentity.bmControls[0] = 1;
+ unit->swentity.bmControls[0] = controls;
unit->get_cur = uvc_swentity_get_cur;
unit->get_info = uvc_swentity_get_info;
+ unit->get_res = uvc_swentity_get_res;
+ unit->get_def = uvc_swentity_get_rotation;
+ unit->get_min = uvc_swentity_get_rotation;
+ unit->get_max = uvc_swentity_get_rotation;
strscpy(unit->name, "SWENTITY", sizeof(unit->name));
list_add_tail(&unit->list, &dev->entities);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index d6da8ed3ad4cf3377df49923e051fe04d83d2e38..7cca0dc75d11f6a13bc4f09676a5a00e80cb38f7 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -45,6 +45,11 @@
#define UVC_SWENTITY_UNIT 0x7ffd
#define UVC_SWENTITY_UNIT_ID 0x101
+enum {
+ UVC_SWENTITY_ORIENTATION,
+ UVC_SWENTITY_ROTATION
+};
+
/* ------------------------------------------------------------------------
* Driver specific constants.
*/
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
` (10 preceding siblings ...)
2025-06-05 17:53 ` [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION Ricardo Ribalda
@ 2025-06-05 17:53 ` Ricardo Ribalda
2025-06-29 18:05 ` Laurent Pinchart
11 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-06-05 17:53 UTC (permalink / raw)
To: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi, Ricardo Ribalda
Neither the GPIO nor the SWENTITY entities form part of the device
pipeline. We just create them to hold emulated uvc controls.
When the device initializes, a warning is thrown by the v4l2 core:
uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
There are no entity function that matches what we are doing here, and
it does not make to much sense to create a function for entities that
do not really exist.
Do not create MC entities for them and pretend nothing happened here.
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
{
int ret;
+ /*
+ * Do not initialize virtual entities, they do not really exist
+ * and are not connected to any other entities.
+ */
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case UVC_EXT_GPIO_UNIT:
+ case UVC_SWENTITY_UNIT:
+ return 0;
+ }
+
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
u32 function;
--
2.50.0.rc0.642.g800a2b2222-goog
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper
2025-06-05 17:52 ` [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper Ricardo Ribalda
@ 2025-06-06 4:27 ` kernel test robot
2025-07-14 13:11 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: kernel test robot @ 2025-06-06 4:27 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Hans de Goede,
Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown
Cc: oe-kbuild-all, linux-media, linux-kernel, linux-usb, devicetree,
linux-gpio, linux-acpi, Ricardo Ribalda
Hi Ricardo,
kernel test robot noticed the following build errors:
[auto build test ERROR on 5e1ff2314797bf53636468a97719a8222deca9ae]
url: https://github.com/intel-lab-lkp/linux/commits/Ricardo-Ribalda/media-uvcvideo-Always-set-default_value/20250606-015643
base: 5e1ff2314797bf53636468a97719a8222deca9ae
patch link: https://lore.kernel.org/r/20250605-uvc-orientation-v2-4-5710f9d030aa%40chromium.org
patch subject: [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper
config: riscv-randconfig-002-20250606 (https://download.01.org/0day-ci/archive/20250606/202506061223.m9fBRBFN-lkp@intel.com/config)
compiler: riscv64-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250606/202506061223.m9fBRBFN-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506061223.m9fBRBFN-lkp@intel.com/
All errors (new ones prefixed by >>, old ones prefixed by <<):
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/fpga/tests/fpga-mgr-test.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/fpga/tests/fpga-bridge-test.o
WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/fpga/tests/fpga-region-test.o
>> ERROR: modpost: "v4l2_fwnode_device_parse" [drivers/media/pci/intel/ipu-bridge.ko] undefined!
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation
2025-06-05 17:52 ` [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation Ricardo Ribalda
@ 2025-06-25 18:56 ` Rob Herring
0 siblings, 0 replies; 62+ messages in thread
From: Rob Herring @ 2025-06-25 18:56 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Thu, Jun 05, 2025 at 05:52:59PM +0000, Ricardo Ribalda wrote:
> For some devices, such as cameras, the OS needs to know where they are
> mounted.
>
> ACPI has a property for this purpose, which is parsed by
> acpi_get_physical_device_location():
> https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/06_Device_Configuration/Device_Configuration.html#pld-physical-location-of-device
>
> In DT we have similar properties for video-interface-devices called
> orientation and rotation:
> Documentation/devicetree/bindings/media/video-interface-devices.yaml
>
> Add rotation and orientation for usb-devices that matches the already
> existing properties of video-interface-devices.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> Documentation/devicetree/bindings/usb/usb-device.yaml | 10 ++++++++++
> 1 file changed, 10 insertions(+)
Comments from v1 still apply. Add a schema for *your* device (i.e. one
that only matches the compatible string of your device). Look for
anything that includes usb-device.yaml for an example. Your schema
should have something like this if you want to use
video-interface-devices.yaml properties:
allOf:
- $ref: /schemas/usb/usb-device.yaml#
- $ref: /schemas/media/video-interface-devices.yaml#
>
> diff --git a/Documentation/devicetree/bindings/usb/usb-device.yaml b/Documentation/devicetree/bindings/usb/usb-device.yaml
> index c676956810331b81f11f3624340fc3e612c98315..a44eb24c657993f88145377a4706ec419b6cd998 100644
> --- a/Documentation/devicetree/bindings/usb/usb-device.yaml
> +++ b/Documentation/devicetree/bindings/usb/usb-device.yaml
> @@ -44,6 +44,14 @@ properties:
> - minimum: 1
> maximum: 255
>
> + orientation:
> + description: If present, specifies the orientation of the usb device.
> + $ref: /schemas/media/video-interface-devices.yaml#/properties/orientation
Again, this is generally the wrong way to add properties from another
schema for your device. Above is the right way.
Rob
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-06-05 17:52 ` [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse Ricardo Ribalda
@ 2025-06-29 9:21 ` Sakari Ailus
2025-07-01 9:04 ` Ricardo Ribalda
2025-07-14 13:03 ` Hans de Goede
1 sibling, 1 reply; 62+ messages in thread
From: Sakari Ailus @ 2025-06-29 9:21 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Hans de Goede,
Mauro Carvalho Chehab, Hans Verkuil, Greg Kroah-Hartman,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi Ricardo,
Thanks for the update.
On 6/5/25 20:52, Ricardo Ribalda wrote:
> Currently v4l2_fwnode_device_parse() obtains the orientation and
> rotation via fwnode properties.
>
> Extend the function to support as well ACPI devices with _PLD info.
>
> We give a higher priority to fwnode, because it might contain quirks
> injected via swnodes.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
> 1 file changed, 79 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -15,6 +15,7 @@
> * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> */
> #include <linux/acpi.h>
> +#include <acpi/acpi_bus.h>
> #include <linux/kernel.h>
> #include <linux/mm.h>
> #include <linux/module.h>
> @@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
> }
> EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
>
> -int v4l2_fwnode_device_parse(struct device *dev,
> - struct v4l2_fwnode_device_properties *props)
> +static int v4l2_fwnode_device_parse_acpi(struct device *dev,
> + struct v4l2_fwnode_device_properties *props)
> +{
> + struct acpi_pld_info *pld;
> + int ret = 0;
> +
> + if (!is_acpi_device_node(dev_fwnode(dev)))
> + return 0;
> +
> + if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
> + dev_dbg(dev, "acpi _PLD call failed\n");
I'd do:
acpi_handle_debug(ACPI_HANDLE(dev), "cannot obtain _PLD\n");
> + return 0;
> + }
> +
> + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
> + switch (pld->panel) {
> + case ACPI_PLD_PANEL_FRONT:
> + props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> + break;
> + case ACPI_PLD_PANEL_BACK:
> + props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
> + break;
> + case ACPI_PLD_PANEL_TOP:
> + case ACPI_PLD_PANEL_LEFT:
> + case ACPI_PLD_PANEL_RIGHT:
> + case ACPI_PLD_PANEL_UNKNOWN:
> + props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> + break;
> + default:
> + dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
Similarly:
acpi_handle_debug(ACPI_HANDLE(dev), "invalid panel %u in _PLD\n",
pld->panel);
> + ret = -EINVAL;
Should this be an error or should we simply ignore it here (and maybe
use acpi_handle_warn())?
> + goto done;
> + }
> + }
> +
> + if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
> + switch (pld->rotation) {
> + case 0 ... 7:
> + props->rotation = pld->rotation * 45;
> + break;
> + default:
> + dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
acpi_handle_debug(ACPI_HANDLE(dev), "invalid rotation %u in _PLD\n",
pld->rotation);
> + ret = -EINVAL;
> + goto done;
> + }
> + }
> +
> +done:
> + ACPI_FREE(pld);
> + return ret;
> +}
> +
> +static int v4l2_fwnode_device_parse_dt(struct device *dev,
I'd call this v4l2_fwnode_device_parse_of() as we're parsing OF nodes
and properties here.
> + struct v4l2_fwnode_device_properties *props)
> {
> struct fwnode_handle *fwnode = dev_fwnode(dev);
> u32 val;
> int ret;
>
> - memset(props, 0, sizeof(*props));
> -
> - props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> ret = fwnode_property_read_u32(fwnode, "orientation", &val);
> if (!ret) {
> switch (val) {
> @@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
> dev_dbg(dev, "device orientation: %u\n", val);
> }
>
> - props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> ret = fwnode_property_read_u32(fwnode, "rotation", &val);
> if (!ret) {
> if (val >= 360) {
> @@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
>
> return 0;
> }
> +
> +int v4l2_fwnode_device_parse(struct device *dev,
> + struct v4l2_fwnode_device_properties *props)
> +{
> + int ret;
> +
> + memset(props, 0, sizeof(*props));
> +
> + props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> + props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> +
> + /* Start by looking into swnodes and dt. */
> + ret = v4l2_fwnode_device_parse_dt(dev, props);
> + if (ret)
> + return ret;
> +
> + /* Orientation and rotation found!, we are ready. */
> + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
> + props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> + return 0;
I think you can remove this check without affecting the functionality.
> +
> + /* Let's check the acpi table. */
> + return v4l2_fwnode_device_parse_acpi(dev, props);
> +}
> EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
>
> /*
>
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
@ 2025-06-29 9:24 ` Sakari Ailus
2025-07-07 21:05 ` Sakari Ailus
2025-07-14 13:08 ` Hans de Goede
2 siblings, 0 replies; 62+ messages in thread
From: Sakari Ailus @ 2025-06-29 9:24 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Hans de Goede,
Mauro Carvalho Chehab, Hans Verkuil, Greg Kroah-Hartman,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi Ricardo,
On 6/5/25 20:52, Ricardo Ribalda wrote:
> The function v4l2_fwnode_device_parse() is not capable of parsint the
> _PLD method, there is no need to duplicate the rotation information in a
> swnode.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/acpi/mipi-disco-img.c | 15 ---------------
> 1 file changed, 15 deletions(-)
>
> diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c
> index 5b85989f96beeb726f59ac9e12e965a215fb38f6..b58b5ba22a47a4afc5212998074d322f0b7586dc 100644
> --- a/drivers/acpi/mipi-disco-img.c
> +++ b/drivers/acpi/mipi-disco-img.c
> @@ -617,21 +617,6 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2)
>
> adev_fwnode = acpi_fwnode_handle(adev);
>
> - /*
> - * If the "rotation" property is not present, but _PLD is there,
> - * evaluate it to get the "rotation" value.
> - */
> - if (!fwnode_property_present(adev_fwnode, "rotation")) {
> - struct acpi_pld_info *pld;
> -
> - if (acpi_get_physical_device_location(handle, &pld)) {
> - swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] =
> - PROPERTY_ENTRY_U32("rotation",
> - pld->rotation * 45U);
As "rotation" property won't come via software nodes anymore in DisCo
for Imaging, please remove ACPI_DEVICE_SWNODE_DEV_ROTATION from struct
acpi_device_swnode_dev_props as well.
> - kfree(pld);
> - }
> - }
> -
> if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val))
> swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] =
> PROPERTY_ENTRY_U32("clock-frequency", val);
>
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 01/12] media: uvcvideo: Always set default_value
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
@ 2025-06-29 17:39 ` Laurent Pinchart
2025-07-14 13:00 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 17:39 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
Thank you for the patch.
On Thu, Jun 05, 2025 at 05:52:54PM +0000, Ricardo Ribalda wrote:
> If the control does not support GET_DEF, the field default_value will be
> left uninitialized during queryctrl.
>
> Fixes: c0efd232929c ("V4L/DVB (8145a): USB Video Class driver")
Media CI rules require a Cc: stable.
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 44b6513c526421943bb9841fb53dc5f8e9f93f02..47e8ccc39234d1769384b55539a21df07f3d57c7 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1497,6 +1497,8 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
> UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> + } else {
> + v4l2_ctrl->default_value = 0;
> }
While at it we can drop the curly braces.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> switch (mapping->v4l2_type) {
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static
2025-06-05 17:53 ` [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static Ricardo Ribalda
@ 2025-06-29 17:43 ` Laurent Pinchart
2025-07-14 13:31 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 17:43 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Thu, Jun 05, 2025 at 05:53:00PM +0000, Ricardo Ribalda wrote:
> The function is useful for other compilation units.
>
> This is just a refactor patch, no new functionality is added.
I think you can squash it with patch 08/12 where the function is used.
The change is small enough.
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> drivers/media/usb/uvc/uvc_driver.c | 4 ++--
> drivers/media/usb/uvc/uvcvideo.h | 2 ++
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index da24a655ab68cc0957762f2b67387677c22224d1..bcc97f71fa1703aea1119469fb32659c17d9409a 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -792,8 +792,8 @@ static const u8 uvc_media_transport_input_guid[16] =
> UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
> static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
>
> -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
> - unsigned int num_pads, unsigned int extra_size)
> +struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
> + unsigned int extra_size)
> {
> struct uvc_entity *entity;
> unsigned int num_inputs;
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index b9f8eb62ba1d82ea7788cf6c10cc838a429dbc9e..dc23d8a97340dc4615d4182232d395106e6d9ed5 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -684,6 +684,8 @@ do { \
> */
>
> struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
> +struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
> + unsigned int extra_size);
>
> /* Video buffers queue management. */
> int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-06-05 17:53 ` [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION Ricardo Ribalda
@ 2025-06-29 17:50 ` Laurent Pinchart
2025-07-01 9:22 ` Ricardo Ribalda
2025-07-14 14:36 ` Hans de Goede
1 sibling, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 17:50 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Thu, Jun 05, 2025 at 05:53:01PM +0000, Ricardo Ribalda wrote:
> Fetch the orientation from the fwnode and map it into a control.
>
> The uvc driver does not use the media controller, so we need to create a
> virtual entity, like we previously did with the external gpio.
>
> We do not re-purpose the external gpio entity because its is planned to
> remove it.
Comparing the GUIDs for the EXT_GPIO_CONTROLLER and SWENTITY, we have
#define UVC_GUID_EXT_GPIO_CONTROLLER \
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
#define UVC_GUID_SWENTITY \
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
The GUIDs don't carry any special meaning in their values. I agree with
the plan to drop the existing features of the GPIO entity, but wouldn't
it be easier to rename UVC_GUID_EXT_GPIO_CONTROLLER to UVC_GUID_SWENTITY
and UVC_EXT_GPIO_UNIT* to UVC_SWENTITY_UNIT* (the macros are not exposed
to userspace), and later drop the existing GPIO controls from the entity
?
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/Makefile | 3 +-
> drivers/media/usb/uvc/uvc_ctrl.c | 21 +++++++++++
> drivers/media/usb/uvc/uvc_driver.c | 14 +++++--
> drivers/media/usb/uvc/uvc_entity.c | 1 +
> drivers/media/usb/uvc/uvc_swentity.c | 73 ++++++++++++++++++++++++++++++++++++
> drivers/media/usb/uvc/uvcvideo.h | 14 +++++++
> include/linux/usb/uvc.h | 3 ++
> 7 files changed, 125 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile
> index 4f9eee4f81ab6436a8b90324a688a149b2c3bcd1..b4398177c4bb0a9bd49dfd4ca7f2e933b4a1d7df 100644
> --- a/drivers/media/usb/uvc/Makefile
> +++ b/drivers/media/usb/uvc/Makefile
> @@ -1,6 +1,7 @@
> # SPDX-License-Identifier: GPL-2.0
> uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
> - uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o
> + uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o \
> + uvc_swentity.o
> ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
> uvcvideo-objs += uvc_entity.o
> endif
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 47e8ccc39234d1769384b55539a21df07f3d57c7..b2768080c08aafa85acb9b7f318672c043d84e55 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -376,6 +376,13 @@ static const struct uvc_control_info uvc_ctrls[] = {
> | UVC_CTRL_FLAG_GET_DEF
> | UVC_CTRL_FLAG_AUTO_UPDATE,
> },
> + {
> + .entity = UVC_GUID_SWENTITY,
> + .selector = 0,
> + .index = 0,
> + .size = 1,
> + .flags = UVC_CTRL_FLAG_GET_CUR,
> + },
> };
>
> static const u32 uvc_control_classes[] = {
> @@ -975,6 +982,17 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> .name = "Region of Interest Auto Ctrls",
> },
> + {
> + .id = V4L2_CID_CAMERA_ORIENTATION,
> + .entity = UVC_GUID_SWENTITY,
> + .selector = 0,
> + .size = 8,
> + .offset = 0,
> + .v4l2_type = V4L2_CTRL_TYPE_MENU,
> + .data_type = UVC_CTRL_DATA_TYPE_ENUM,
> + .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> + V4L2_CAMERA_ORIENTATION_FRONT),
> + },
> };
>
> /* ------------------------------------------------------------------------
> @@ -3210,6 +3228,9 @@ static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
> } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
> bmControls = entity->gpio.bmControls;
> bControlSize = entity->gpio.bControlSize;
> + } else if (UVC_ENTITY_TYPE(entity) == UVC_SWENTITY_UNIT) {
> + bmControls = entity->swentity.bmControls;
> + bControlSize = entity->swentity.bControlSize;
> }
>
> /* Remove bogus/blacklisted controls */
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index bcc97f71fa1703aea1119469fb32659c17d9409a..96eeb3aee546487d15f3c30dfe1775189ddf7e47 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
> return -1;
> }
>
> - /* Add GPIO entity to the first chain. */
> - if (dev->gpio_unit) {
> + /* Add virtual entities to the first chain. */
> + if (dev->gpio_unit || dev->swentity_unit) {
> chain = list_first_entry(&dev->chains,
> struct uvc_video_chain, list);
> - list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> + if (dev->gpio_unit)
> + list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> + if (dev->swentity_unit)
> + list_add_tail(&dev->swentity_unit->chain,
> + &chain->entities);
> }
>
> return 0;
> @@ -2249,6 +2253,10 @@ static int uvc_probe(struct usb_interface *intf,
> if (ret < 0)
> goto error;
>
> + ret = uvc_swentity_init(dev);
> + if (ret < 0)
> + goto error;
> +
> dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
> dev->uvc_version >> 8, dev->uvc_version & 0xff,
> udev->product ? udev->product : "<unnamed>",
> diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> index cc68dd24eb42dce5b2846ca52a8dfa499c8aed96..d1a652ef35ec34801bd39a5124b834edf838a79e 100644
> --- a/drivers/media/usb/uvc/uvc_entity.c
> +++ b/drivers/media/usb/uvc/uvc_entity.c
> @@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
> case UVC_EXTERNAL_VENDOR_SPECIFIC:
> case UVC_EXT_GPIO_UNIT:
> + case UVC_SWENTITY_UNIT:
> default:
> function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
> break;
> diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..702a2c26e029a0655dade177ed2a9b88d7a4136d
> --- /dev/null
> +++ b/drivers/media/usb/uvc/uvc_swentity.c
> @@ -0,0 +1,73 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * uvc_swentity.c -- USB Video Class driver
> + *
> + * Copyright 2025 Google LLC
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/usb/uvc.h>
> +#include <media/v4l2-fwnode.h>
> +#include "uvcvideo.h"
Blank lines between header groups would be nice.
> +
> +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size)
> +{
> + if (size < 1)
> + return -EINVAL;
> +
> + switch (entity->swentity.props.orientation) {
> + case V4L2_FWNODE_ORIENTATION_FRONT:
> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_FRONT;
> + break;
> + case V4L2_FWNODE_ORIENTATION_BACK:
> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_BACK;
> + break;
> + default:
> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_EXTERNAL;
> + }
> +
> + return 0;
> +}
> +
> +static int uvc_swentity_get_info(struct uvc_device *dev,
> + struct uvc_entity *entity, u8 cs, u8 *caps)
> +{
> + *caps = UVC_CONTROL_CAP_GET;
> + return 0;
> +}
> +
> +int uvc_swentity_init(struct uvc_device *dev)
> +{
> + static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> + struct v4l2_fwnode_device_properties props;
> + struct uvc_entity *unit;
> + int ret;
> +
> + ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> + if (ret)
> + return dev_err_probe(&dev->intf->dev, ret,
> + "Can't parse fwnode\n");
> +
> + if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> + return 0;
> +
> + unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> + if (!unit)
> + return -ENOMEM;
> +
> + memcpy(unit->guid, uvc_swentity_guid, sizeof(unit->guid));
> + unit->swentity.props = props;
> + unit->swentity.bControlSize = 1;
> + unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> + unit->swentity.bmControls[0] = 1;
> + unit->get_cur = uvc_swentity_get_cur;
> + unit->get_info = uvc_swentity_get_info;
> + strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> +
> + list_add_tail(&unit->list, &dev->entities);
> +
> + dev->swentity_unit = unit;
> +
> + return 0;
> +}
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index dc23d8a97340dc4615d4182232d395106e6d9ed5..a931750bdea25b9062dcc7644bf5f2ed89c1cb4c 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -19,6 +19,7 @@
> #include <media/v4l2-event.h>
> #include <media/v4l2-fh.h>
> #include <media/videobuf2-v4l2.h>
> +#include <media/v4l2-fwnode.h>
Alphabetical order.
>
> /* --------------------------------------------------------------------------
> * UVC constants
> @@ -41,6 +42,9 @@
> #define UVC_EXT_GPIO_UNIT 0x7ffe
> #define UVC_EXT_GPIO_UNIT_ID 0x100
>
> +#define UVC_SWENTITY_UNIT 0x7ffd
> +#define UVC_SWENTITY_UNIT_ID 0x101
> +
> /* ------------------------------------------------------------------------
> * Driver specific constants.
> */
> @@ -242,6 +246,12 @@ struct uvc_entity {
> int irq;
> bool initialized;
> } gpio;
> +
> + struct {
> + u8 bControlSize;
> + u8 *bmControls;
> + struct v4l2_fwnode_device_properties props;
> + } swentity;
> };
>
> u8 bNrInPins;
> @@ -617,6 +627,7 @@ struct uvc_device {
> } async_ctrl;
>
> struct uvc_entity *gpio_unit;
> + struct uvc_entity *swentity_unit;
> };
>
> enum uvc_handle_state {
> @@ -836,4 +847,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
> size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
> size_t size);
>
> +/* swentity */
> +int uvc_swentity_init(struct uvc_device *dev);
> +
> #endif
> diff --git a/include/linux/usb/uvc.h b/include/linux/usb/uvc.h
> index bce95153e5a65613a710d7316fc17cf5462b5bce..88a23e8919d1294da4308e0e3ca0eccdc66a318f 100644
> --- a/include/linux/usb/uvc.h
> +++ b/include/linux/usb/uvc.h
> @@ -29,6 +29,9 @@
> #define UVC_GUID_EXT_GPIO_CONTROLLER \
> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
> +#define UVC_GUID_SWENTITY \
> + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
>
> #define UVC_GUID_FORMAT_MJPEG \
> { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper
2025-06-05 17:53 ` [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper Ricardo Ribalda
@ 2025-06-29 18:01 ` Laurent Pinchart
2025-07-14 14:24 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 18:01 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Thu, Jun 05, 2025 at 05:53:02PM +0000, Ricardo Ribalda wrote:
> Create a helper function to query a control. The new function reduces
> the number of arguments, calculates the length of the operation and
> redirects the operation to the hardware or to the entity private
> functions.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++--------------------
> 1 file changed, 41 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index b2768080c08aafa85acb9b7f318672c043d84e55..21ec7b978bc7aca21db7cb8fd5d135d876f3330c 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -576,6 +576,34 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
> V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
> };
>
> +static int uvc_ctrl_query_entity(struct uvc_device *dev,
> + const struct uvc_control *ctrl, u8 query,
> + void *data)
> +{
> + u16 len;
> +
> + switch (query) {
> + case UVC_GET_INFO:
> + len = 1;
> + break;
> + case UVC_GET_LEN:
> + len = 2;
> + break;
> + default:
> + len = ctrl->info.size;
break;
> + }
> +
> + if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> + return ctrl->entity->get_cur(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> + if (query == UVC_GET_INFO && ctrl->entity->get_info)
> + return ctrl->entity->get_info(dev, ctrl->entity,
> + ctrl->info.selector, data);
> +
> + return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
> + ctrl->info.selector, data, len);
> +}
> +
> static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> struct uvc_video_chain *chain, struct uvc_control *ctrl)
> {
> @@ -1222,35 +1250,27 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
> int ret;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_DEF,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> if (ret < 0)
> return ret;
> }
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> if (ret < 0)
> return ret;
> }
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> if (ret < 0)
> return ret;
> }
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> if (ret < 0) {
> if (UVC_ENTITY_TYPE(ctrl->entity) !=
> UVC_VC_EXTENSION_UNIT)
> @@ -1291,16 +1311,7 @@ static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
> return 0;
> }
>
> - if (ctrl->entity->get_cur)
> - ret = ctrl->entity->get_cur(chain->dev, ctrl->entity,
> - ctrl->info.selector, data,
> - ctrl->info.size);
> - else
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
> - ctrl->entity->id, chain->dev->intfnum,
> - ctrl->info.selector, data,
> - ctrl->info.size);
> -
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_CUR, data);
> if (ret < 0)
> return ret;
>
> @@ -2164,11 +2175,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> continue;
>
> if (!rollback)
> - ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
> - dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> - ctrl->info.size);
> -
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_SET_CUR,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> if (!ret)
> processed_ctrls++;
>
> @@ -2570,13 +2578,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
> if (data == NULL)
> return -ENOMEM;
>
> - if (ctrl->entity->get_info)
> - ret = ctrl->entity->get_info(dev, ctrl->entity,
> - ctrl->info.selector, data);
> - else
> - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
> - dev->intfnum, info->selector, data, 1);
Here ctrl->info isn't filled yet, so replacing info->selector with
ctrl->info.selector won't work. Usage of ctrl->info.selector in the
->get_info() branch looks like a bug.
> -
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_INFO, data);
> if (!ret) {
> info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
> UVC_CTRL_FLAG_SET_CUR |
> @@ -2654,8 +2656,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
> info->selector = ctrl->index + 1;
>
> /* Query and verify the control length (GET_LEN) */
> - ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
> - info->selector, data, 2);
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_LEN, data);
Same here.
> if (ret < 0) {
> uvc_dbg(dev, CONTROL,
> "GET_LEN failed on control %pUl/%u (%d)\n",
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-06-05 17:53 ` [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities Ricardo Ribalda
@ 2025-06-29 18:05 ` Laurent Pinchart
2025-07-01 11:20 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 18:05 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
Thank you for the patch.
I would use "software entities" and not "virtual entities" in the
subject line and everywhere else, as those entities are not virtual.
On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> Neither the GPIO nor the SWENTITY entities form part of the device
> pipeline. We just create them to hold emulated uvc controls.
>
> When the device initializes, a warning is thrown by the v4l2 core:
> uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
>
> There are no entity function that matches what we are doing here, and
> it does not make to much sense to create a function for entities that
> do not really exist.
I don't agree with this. The purpose of reporting entities to userspace
through the MC API is to let application enumerate what entities a
device contains. Being able to enumerate software entities seems as
useful as being able to enumerate hardware entities.
> Do not create MC entities for them and pretend nothing happened here.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> --- a/drivers/media/usb/uvc/uvc_entity.c
> +++ b/drivers/media/usb/uvc/uvc_entity.c
> @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> {
> int ret;
>
> + /*
> + * Do not initialize virtual entities, they do not really exist
> + * and are not connected to any other entities.
> + */
> + switch (UVC_ENTITY_TYPE(entity)) {
> + case UVC_EXT_GPIO_UNIT:
> + case UVC_SWENTITY_UNIT:
> + return 0;
> + }
> +
> if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> u32 function;
>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-06-05 17:53 ` [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity Ricardo Ribalda
@ 2025-06-29 18:12 ` Laurent Pinchart
2025-07-01 11:13 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 18:12 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
Thank you for the patch.
On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> Virtual entities need to provide more values than get_cur and get_cur
I think you meant "get_info and get_cur".
> for their controls. Add support for get_def, get_min, get_max and
> get_res.
Do they ? The UVC specification defines controls that don't list
GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
the same for the software controls ? This patch is meant to support the
UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
enough ?
>
> This is a preparation patch.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> 2 files changed, 20 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> return ctrl->entity->get_cur(dev, ctrl->entity,
> ctrl->info.selector, data, len);
> + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> + return ctrl->entity->get_def(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> + return ctrl->entity->get_min(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> + return ctrl->entity->get_max(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> + if (query == UVC_GET_RES && ctrl->entity->get_res)
> + return ctrl->entity->get_res(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> if (query == UVC_GET_INFO && ctrl->entity->get_info)
> return ctrl->entity->get_info(dev, ctrl->entity,
> ctrl->info.selector, data);
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -261,6 +261,14 @@ struct uvc_entity {
> u8 cs, u8 *caps);
> int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> u8 cs, void *data, u16 size);
> + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size);
> + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size);
> + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size);
> + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size);
>
> unsigned int ncontrols;
> struct uvc_control *controls;
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
2025-06-05 17:53 ` [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION Ricardo Ribalda
@ 2025-06-29 18:14 ` Laurent Pinchart
2025-07-01 11:26 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-06-29 18:14 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Thu, Jun 05, 2025 at 05:53:04PM +0000, Ricardo Ribalda wrote:
> Fetch the rotation from the fwnode and map it into a control.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 22 +++++++++++++--
> drivers/media/usb/uvc/uvc_swentity.c | 55 ++++++++++++++++++++++++++++++++----
> drivers/media/usb/uvc/uvcvideo.h | 5 ++++
> 3 files changed, 74 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 59be62ae24a4219fa9d7aacf2ae7382c95362178..5788f0c0f6604da06a7bca1b9999d0957817e75e 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -378,11 +378,18 @@ static const struct uvc_control_info uvc_ctrls[] = {
> },
> {
> .entity = UVC_GUID_SWENTITY,
> - .selector = 0,
> - .index = 0,
> + .selector = UVC_SWENTITY_ORIENTATION,
> + .index = UVC_SWENTITY_ORIENTATION,
> .size = 1,
> .flags = UVC_CTRL_FLAG_GET_CUR,
> },
> + {
> + .entity = UVC_GUID_SWENTITY,
> + .selector = UVC_SWENTITY_ROTATION,
> + .index = UVC_SWENTITY_ROTATION,
> + .size = 2,
> + .flags = UVC_CTRL_FLAG_GET_RANGE,
> + },
> };
>
> static const u32 uvc_control_classes[] = {
> @@ -1025,7 +1032,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> {
> .id = V4L2_CID_CAMERA_ORIENTATION,
> .entity = UVC_GUID_SWENTITY,
> - .selector = 0,
> + .selector = UVC_SWENTITY_ORIENTATION,
> .size = 8,
> .offset = 0,
> .v4l2_type = V4L2_CTRL_TYPE_MENU,
> @@ -1033,6 +1040,15 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> V4L2_CAMERA_ORIENTATION_FRONT),
> },
> + {
> + .id = V4L2_CID_CAMERA_SENSOR_ROTATION,
> + .entity = UVC_GUID_SWENTITY,
> + .selector = UVC_SWENTITY_ROTATION,
> + .size = 16,
> + .offset = 0,
> + .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
> + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
> + },
> };
>
> /* ------------------------------------------------------------------------
> diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> index 702a2c26e029a0655dade177ed2a9b88d7a4136d..60f3166addbeb7d2e431d107b23034d2d11a1812 100644
> --- a/drivers/media/usb/uvc/uvc_swentity.c
> +++ b/drivers/media/usb/uvc/uvc_swentity.c
> @@ -10,10 +10,11 @@
> #include <media/v4l2-fwnode.h>
> #include "uvcvideo.h"
>
> -static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> - u8 cs, void *data, u16 size)
> +static int uvc_swentity_get_orientation(struct uvc_device *dev,
> + struct uvc_entity *entity, u8 cs,
> + void *data, u16 size)
> {
> - if (size < 1)
> + if (cs != UVC_SWENTITY_ORIENTATION || size != 1)
> return -EINVAL;
>
> switch (entity->swentity.props.orientation) {
> @@ -30,6 +31,31 @@ static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entit
> return 0;
> }
>
> +static int uvc_swentity_get_rotation(struct uvc_device *dev,
> + struct uvc_entity *entity, u8 cs, void *data,
> + u16 size)
> +{
> + if (cs != UVC_SWENTITY_ROTATION || size != 2)
> + return -EINVAL;
> +
> + ((u8 *)data)[0] = entity->swentity.props.rotation;
> + ((u8 *)data)[1] = entity->swentity.props.rotation >> 8;
> +
> + return 0;
> +}
> +
> +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *data, u16 size)
> +{
> + switch (cs) {
> + case UVC_SWENTITY_ORIENTATION:
> + return uvc_swentity_get_orientation(dev, entity, cs, data, size);
> + case UVC_SWENTITY_ROTATION:
> + return uvc_swentity_get_rotation(dev, entity, cs, data, size);
> + }
> + return -EINVAL;
> +}
> +
> static int uvc_swentity_get_info(struct uvc_device *dev,
> struct uvc_entity *entity, u8 cs, u8 *caps)
> {
> @@ -37,11 +63,22 @@ static int uvc_swentity_get_info(struct uvc_device *dev,
> return 0;
> }
>
> +static int uvc_swentity_get_res(struct uvc_device *dev, struct uvc_entity *entity,
> + u8 cs, void *res, u16 size)
> +{
> + if (size == 0)
> + return -EINVAL;
The get_cur functions return an error if the size doesn't match the
expected size. I think you can return -EINVAL if size != 1.
> + ((u8 *)res)[0] = 1;
> + memset(res + 1, 0, size - 1);
And drop the memset.
> + return 0;
> +}
> +
> int uvc_swentity_init(struct uvc_device *dev)
> {
> static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> struct v4l2_fwnode_device_properties props;
> struct uvc_entity *unit;
> + u8 controls = 0;
> int ret;
>
> ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> @@ -49,7 +86,11 @@ int uvc_swentity_init(struct uvc_device *dev)
> return dev_err_probe(&dev->intf->dev, ret,
> "Can't parse fwnode\n");
>
> - if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> + if (props.orientation != V4L2_FWNODE_PROPERTY_UNSET)
> + controls |= BIT(UVC_SWENTITY_ORIENTATION);
> + if (props.rotation != V4L2_FWNODE_PROPERTY_UNSET)
> + controls |= BIT(UVC_SWENTITY_ROTATION);
> + if (!controls)
> return 0;
>
> unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> @@ -60,9 +101,13 @@ int uvc_swentity_init(struct uvc_device *dev)
> unit->swentity.props = props;
> unit->swentity.bControlSize = 1;
> unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> - unit->swentity.bmControls[0] = 1;
> + unit->swentity.bmControls[0] = controls;
> unit->get_cur = uvc_swentity_get_cur;
> unit->get_info = uvc_swentity_get_info;
> + unit->get_res = uvc_swentity_get_res;
> + unit->get_def = uvc_swentity_get_rotation;
> + unit->get_min = uvc_swentity_get_rotation;
> + unit->get_max = uvc_swentity_get_rotation;
Why do you support GET_DEF, GET_MIN and GET_MAX for rotation only ?
> strscpy(unit->name, "SWENTITY", sizeof(unit->name));
>
> list_add_tail(&unit->list, &dev->entities);
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index d6da8ed3ad4cf3377df49923e051fe04d83d2e38..7cca0dc75d11f6a13bc4f09676a5a00e80cb38f7 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -45,6 +45,11 @@
> #define UVC_SWENTITY_UNIT 0x7ffd
> #define UVC_SWENTITY_UNIT_ID 0x101
>
> +enum {
> + UVC_SWENTITY_ORIENTATION,
> + UVC_SWENTITY_ROTATION
> +};
> +
> /* ------------------------------------------------------------------------
> * Driver specific constants.
> */
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-06-29 9:21 ` Sakari Ailus
@ 2025-07-01 9:04 ` Ricardo Ribalda
2025-07-07 21:01 ` Sakari Ailus
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-01 9:04 UTC (permalink / raw)
To: Sakari Ailus
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Sakari
Thanks for your review!
On Mon, 30 Jun 2025 at 09:06, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>
> Hi Ricardo,
>
> Thanks for the update.
>
> On 6/5/25 20:52, Ricardo Ribalda wrote:
> > Currently v4l2_fwnode_device_parse() obtains the orientation and
> > rotation via fwnode properties.
> >
> > Extend the function to support as well ACPI devices with _PLD info.
> >
> > We give a higher priority to fwnode, because it might contain quirks
> > injected via swnodes.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
> > 1 file changed, 79 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -15,6 +15,7 @@
> > * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > */
> > #include <linux/acpi.h>
> > +#include <acpi/acpi_bus.h>
> > #include <linux/kernel.h>
> > #include <linux/mm.h>
> > #include <linux/module.h>
> > @@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
> > }
> > EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
> >
> > -int v4l2_fwnode_device_parse(struct device *dev,
> > - struct v4l2_fwnode_device_properties *props)
> > +static int v4l2_fwnode_device_parse_acpi(struct device *dev,
> > + struct v4l2_fwnode_device_properties *props)
> > +{
> > + struct acpi_pld_info *pld;
> > + int ret = 0;
> > +
> > + if (!is_acpi_device_node(dev_fwnode(dev)))
> > + return 0;
> > +
> > + if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
> > + dev_dbg(dev, "acpi _PLD call failed\n");
>
> I'd do:
>
> acpi_handle_debug(ACPI_HANDLE(dev), "cannot obtain _PLD\n");
ack
>
> > + return 0;
> > + }
> > +
> > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
> > + switch (pld->panel) {
> > + case ACPI_PLD_PANEL_FRONT:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> > + break;
> > + case ACPI_PLD_PANEL_BACK:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
> > + break;
> > + case ACPI_PLD_PANEL_TOP:
> > + case ACPI_PLD_PANEL_LEFT:
> > + case ACPI_PLD_PANEL_RIGHT:
> > + case ACPI_PLD_PANEL_UNKNOWN:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> > + break;
> > + default:
> > + dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
>
> Similarly:
>
> acpi_handle_debug(ACPI_HANDLE(dev), "invalid panel %u in _PLD\n",
> pld->panel);
>
> > + ret = -EINVAL;
>
> Should this be an error or should we simply ignore it here (and maybe
> use acpi_handle_warn())?
v4l2_fwnode_device_parse_of() returns -EINVAL for a similar situation,
so I think it is better to be consistent and return -EINVAL here.
But I agree that acpi_handle_warn() better suits here than _dbg.
>
> > + goto done;
> > + }
> > + }
> > +
> > + if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
> > + switch (pld->rotation) {
> > + case 0 ... 7:
> > + props->rotation = pld->rotation * 45;
> > + break;
> > + default:
> > + dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
>
> acpi_handle_debug(ACPI_HANDLE(dev), "invalid rotation %u in _PLD\n",
> pld->rotation);
>
> > + ret = -EINVAL;
> > + goto done;
> > + }
> > + }
> > +
> > +done:
> > + ACPI_FREE(pld);
> > + return ret;
> > +}
> > +
> > +static int v4l2_fwnode_device_parse_dt(struct device *dev,
>
> I'd call this v4l2_fwnode_device_parse_of() as we're parsing OF nodes
> and properties here.
ack
>
> > + struct v4l2_fwnode_device_properties *props)
> > {
> > struct fwnode_handle *fwnode = dev_fwnode(dev);
> > u32 val;
> > int ret;
> >
> > - memset(props, 0, sizeof(*props));
> > -
> > - props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > ret = fwnode_property_read_u32(fwnode, "orientation", &val);
> > if (!ret) {
> > switch (val) {
> > @@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > dev_dbg(dev, "device orientation: %u\n", val);
> > }
> >
> > - props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > ret = fwnode_property_read_u32(fwnode, "rotation", &val);
> > if (!ret) {
> > if (val >= 360) {
> > @@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
> >
> > return 0;
> > }
> > +
> > +int v4l2_fwnode_device_parse(struct device *dev,
> > + struct v4l2_fwnode_device_properties *props)
> > +{
> > + int ret;
> > +
> > + memset(props, 0, sizeof(*props));
> > +
> > + props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > + props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > +
> > + /* Start by looking into swnodes and dt. */
> > + ret = v4l2_fwnode_device_parse_dt(dev, props);
> > + if (ret)
> > + return ret;
> > +
> > + /* Orientation and rotation found!, we are ready. */
> > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
> > + props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > + return 0;
>
> I think you can remove this check without affecting the functionality.
I want to avoid calling an acpi method unless it is strictly
necessary. The check is not that ugly... if it is ok with you i'd
rather keep it.
>
> > +
> > + /* Let's check the acpi table. */
> > + return v4l2_fwnode_device_parse_acpi(dev, props);
> > +}
> > EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
> >
> > /*
> >
>
> --
> Regards,
>
> Sakari Ailus
Thanks!
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-06-29 17:50 ` Laurent Pinchart
@ 2025-07-01 9:22 ` Ricardo Ribalda
2025-07-14 14:15 ` Hans de Goede
2025-07-14 14:23 ` Laurent Pinchart
0 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-01 9:22 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Sun, 29 Jun 2025 at 19:51, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Ricardo,
>
> On Thu, Jun 05, 2025 at 05:53:01PM +0000, Ricardo Ribalda wrote:
> > Fetch the orientation from the fwnode and map it into a control.
> >
> > The uvc driver does not use the media controller, so we need to create a
> > virtual entity, like we previously did with the external gpio.
> >
> > We do not re-purpose the external gpio entity because its is planned to
> > remove it.
>
> Comparing the GUIDs for the EXT_GPIO_CONTROLLER and SWENTITY, we have
>
> #define UVC_GUID_EXT_GPIO_CONTROLLER \
> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
> #define UVC_GUID_SWENTITY \
> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
>
> The GUIDs don't carry any special meaning in their values. I agree with
> the plan to drop the existing features of the GPIO entity, but wouldn't
> it be easier to rename UVC_GUID_EXT_GPIO_CONTROLLER to UVC_GUID_SWENTITY
> and UVC_EXT_GPIO_UNIT* to UVC_SWENTITY_UNIT* (the macros are not exposed
> to userspace), and later drop the existing GPIO controls from the entity
It would make my life easier if we keep the naming as is, the final
result will be identical.
Maybe you want to take a look into
https://patchwork.linuxtv.org/project/linux-media/list/?series=14066 ?
Will it help if I rebase it to the current media-committers/next. It
has been hanging around since november.
> ?
>
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/Makefile | 3 +-
> > drivers/media/usb/uvc/uvc_ctrl.c | 21 +++++++++++
> > drivers/media/usb/uvc/uvc_driver.c | 14 +++++--
> > drivers/media/usb/uvc/uvc_entity.c | 1 +
> > drivers/media/usb/uvc/uvc_swentity.c | 73 ++++++++++++++++++++++++++++++++++++
> > drivers/media/usb/uvc/uvcvideo.h | 14 +++++++
> > include/linux/usb/uvc.h | 3 ++
> > 7 files changed, 125 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile
> > index 4f9eee4f81ab6436a8b90324a688a149b2c3bcd1..b4398177c4bb0a9bd49dfd4ca7f2e933b4a1d7df 100644
> > --- a/drivers/media/usb/uvc/Makefile
> > +++ b/drivers/media/usb/uvc/Makefile
> > @@ -1,6 +1,7 @@
> > # SPDX-License-Identifier: GPL-2.0
> > uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
> > - uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o
> > + uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o \
> > + uvc_swentity.o
> > ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
> > uvcvideo-objs += uvc_entity.o
> > endif
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 47e8ccc39234d1769384b55539a21df07f3d57c7..b2768080c08aafa85acb9b7f318672c043d84e55 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -376,6 +376,13 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > | UVC_CTRL_FLAG_GET_DEF
> > | UVC_CTRL_FLAG_AUTO_UPDATE,
> > },
> > + {
> > + .entity = UVC_GUID_SWENTITY,
> > + .selector = 0,
> > + .index = 0,
> > + .size = 1,
> > + .flags = UVC_CTRL_FLAG_GET_CUR,
> > + },
> > };
> >
> > static const u32 uvc_control_classes[] = {
> > @@ -975,6 +982,17 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > .name = "Region of Interest Auto Ctrls",
> > },
> > + {
> > + .id = V4L2_CID_CAMERA_ORIENTATION,
> > + .entity = UVC_GUID_SWENTITY,
> > + .selector = 0,
> > + .size = 8,
> > + .offset = 0,
> > + .v4l2_type = V4L2_CTRL_TYPE_MENU,
> > + .data_type = UVC_CTRL_DATA_TYPE_ENUM,
> > + .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> > + V4L2_CAMERA_ORIENTATION_FRONT),
> > + },
> > };
> >
> > /* ------------------------------------------------------------------------
> > @@ -3210,6 +3228,9 @@ static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
> > } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
> > bmControls = entity->gpio.bmControls;
> > bControlSize = entity->gpio.bControlSize;
> > + } else if (UVC_ENTITY_TYPE(entity) == UVC_SWENTITY_UNIT) {
> > + bmControls = entity->swentity.bmControls;
> > + bControlSize = entity->swentity.bControlSize;
> > }
> >
> > /* Remove bogus/blacklisted controls */
> > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> > index bcc97f71fa1703aea1119469fb32659c17d9409a..96eeb3aee546487d15f3c30dfe1775189ddf7e47 100644
> > --- a/drivers/media/usb/uvc/uvc_driver.c
> > +++ b/drivers/media/usb/uvc/uvc_driver.c
> > @@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
> > return -1;
> > }
> >
> > - /* Add GPIO entity to the first chain. */
> > - if (dev->gpio_unit) {
> > + /* Add virtual entities to the first chain. */
> > + if (dev->gpio_unit || dev->swentity_unit) {
> > chain = list_first_entry(&dev->chains,
> > struct uvc_video_chain, list);
> > - list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> > + if (dev->gpio_unit)
> > + list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> > + if (dev->swentity_unit)
> > + list_add_tail(&dev->swentity_unit->chain,
> > + &chain->entities);
> > }
> >
> > return 0;
> > @@ -2249,6 +2253,10 @@ static int uvc_probe(struct usb_interface *intf,
> > if (ret < 0)
> > goto error;
> >
> > + ret = uvc_swentity_init(dev);
> > + if (ret < 0)
> > + goto error;
> > +
> > dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
> > dev->uvc_version >> 8, dev->uvc_version & 0xff,
> > udev->product ? udev->product : "<unnamed>",
> > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > index cc68dd24eb42dce5b2846ca52a8dfa499c8aed96..d1a652ef35ec34801bd39a5124b834edf838a79e 100644
> > --- a/drivers/media/usb/uvc/uvc_entity.c
> > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > @@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
> > case UVC_EXTERNAL_VENDOR_SPECIFIC:
> > case UVC_EXT_GPIO_UNIT:
> > + case UVC_SWENTITY_UNIT:
> > default:
> > function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
> > break;
> > diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..702a2c26e029a0655dade177ed2a9b88d7a4136d
> > --- /dev/null
> > +++ b/drivers/media/usb/uvc/uvc_swentity.c
> > @@ -0,0 +1,73 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * uvc_swentity.c -- USB Video Class driver
> > + *
> > + * Copyright 2025 Google LLC
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/usb/uvc.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include "uvcvideo.h"
>
> Blank lines between header groups would be nice.
ack
>
> > +
> > +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size)
> > +{
> > + if (size < 1)
> > + return -EINVAL;
> > +
> > + switch (entity->swentity.props.orientation) {
> > + case V4L2_FWNODE_ORIENTATION_FRONT:
> > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_FRONT;
> > + break;
> > + case V4L2_FWNODE_ORIENTATION_BACK:
> > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_BACK;
> > + break;
> > + default:
> > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_EXTERNAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int uvc_swentity_get_info(struct uvc_device *dev,
> > + struct uvc_entity *entity, u8 cs, u8 *caps)
> > +{
> > + *caps = UVC_CONTROL_CAP_GET;
> > + return 0;
> > +}
> > +
> > +int uvc_swentity_init(struct uvc_device *dev)
> > +{
> > + static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> > + struct v4l2_fwnode_device_properties props;
> > + struct uvc_entity *unit;
> > + int ret;
> > +
> > + ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> > + if (ret)
> > + return dev_err_probe(&dev->intf->dev, ret,
> > + "Can't parse fwnode\n");
> > +
> > + if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> > + return 0;
> > +
> > + unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> > + if (!unit)
> > + return -ENOMEM;
> > +
> > + memcpy(unit->guid, uvc_swentity_guid, sizeof(unit->guid));
> > + unit->swentity.props = props;
> > + unit->swentity.bControlSize = 1;
> > + unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> > + unit->swentity.bmControls[0] = 1;
> > + unit->get_cur = uvc_swentity_get_cur;
> > + unit->get_info = uvc_swentity_get_info;
> > + strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> > +
> > + list_add_tail(&unit->list, &dev->entities);
> > +
> > + dev->swentity_unit = unit;
> > +
> > + return 0;
> > +}
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index dc23d8a97340dc4615d4182232d395106e6d9ed5..a931750bdea25b9062dcc7644bf5f2ed89c1cb4c 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -19,6 +19,7 @@
> > #include <media/v4l2-event.h>
> > #include <media/v4l2-fh.h>
> > #include <media/videobuf2-v4l2.h>
> > +#include <media/v4l2-fwnode.h>
>
> Alphabetical order.
>
> >
> > /* --------------------------------------------------------------------------
> > * UVC constants
> > @@ -41,6 +42,9 @@
> > #define UVC_EXT_GPIO_UNIT 0x7ffe
> > #define UVC_EXT_GPIO_UNIT_ID 0x100
> >
> > +#define UVC_SWENTITY_UNIT 0x7ffd
> > +#define UVC_SWENTITY_UNIT_ID 0x101
> > +
> > /* ------------------------------------------------------------------------
> > * Driver specific constants.
> > */
> > @@ -242,6 +246,12 @@ struct uvc_entity {
> > int irq;
> > bool initialized;
> > } gpio;
> > +
> > + struct {
> > + u8 bControlSize;
> > + u8 *bmControls;
> > + struct v4l2_fwnode_device_properties props;
> > + } swentity;
> > };
> >
> > u8 bNrInPins;
> > @@ -617,6 +627,7 @@ struct uvc_device {
> > } async_ctrl;
> >
> > struct uvc_entity *gpio_unit;
> > + struct uvc_entity *swentity_unit;
> > };
> >
> > enum uvc_handle_state {
> > @@ -836,4 +847,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
> > size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
> > size_t size);
> >
> > +/* swentity */
> > +int uvc_swentity_init(struct uvc_device *dev);
> > +
> > #endif
> > diff --git a/include/linux/usb/uvc.h b/include/linux/usb/uvc.h
> > index bce95153e5a65613a710d7316fc17cf5462b5bce..88a23e8919d1294da4308e0e3ca0eccdc66a318f 100644
> > --- a/include/linux/usb/uvc.h
> > +++ b/include/linux/usb/uvc.h
> > @@ -29,6 +29,9 @@
> > #define UVC_GUID_EXT_GPIO_CONTROLLER \
> > {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
> > +#define UVC_GUID_SWENTITY \
> > + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
> >
> > #define UVC_GUID_FORMAT_MJPEG \
> > { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-06-29 18:12 ` Laurent Pinchart
@ 2025-07-01 11:13 ` Ricardo Ribalda
2025-07-14 14:28 ` Hans de Goede
2025-07-14 14:29 ` Laurent Pinchart
0 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-01 11:13 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Laurent
On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Ricardo,
>
> Thank you for the patch.
>
> On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > Virtual entities need to provide more values than get_cur and get_cur
>
> I think you meant "get_info and get_cur".
>
> > for their controls. Add support for get_def, get_min, get_max and
> > get_res.
>
> Do they ? The UVC specification defines controls that don't list
> GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> the same for the software controls ? This patch is meant to support the
> UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> enough ?
V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
that time requires get_min and get_max.
We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
fakes min, max and res, but I think that it is cleaner this approach.
>
> >
> > This is a preparation patch.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > 2 files changed, 20 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > return ctrl->entity->get_cur(dev, ctrl->entity,
> > ctrl->info.selector, data, len);
> > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > + return ctrl->entity->get_def(dev, ctrl->entity,
> > + ctrl->info.selector, data, len);
> > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > + return ctrl->entity->get_min(dev, ctrl->entity,
> > + ctrl->info.selector, data, len);
> > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > + return ctrl->entity->get_max(dev, ctrl->entity,
> > + ctrl->info.selector, data, len);
> > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > + return ctrl->entity->get_res(dev, ctrl->entity,
> > + ctrl->info.selector, data, len);
> > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > return ctrl->entity->get_info(dev, ctrl->entity,
> > ctrl->info.selector, data);
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -261,6 +261,14 @@ struct uvc_entity {
> > u8 cs, u8 *caps);
> > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > u8 cs, void *data, u16 size);
> > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size);
> > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size);
> > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size);
> > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size);
> >
> > unsigned int ncontrols;
> > struct uvc_control *controls;
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-06-29 18:05 ` Laurent Pinchart
@ 2025-07-01 11:20 ` Ricardo Ribalda
2025-07-08 6:28 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-01 11:20 UTC (permalink / raw)
To: Laurent Pinchart, Hans Verkuil
Cc: Hans de Goede, Mauro Carvalho Chehab, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Laurent and Hans
On Sun, 29 Jun 2025 at 20:06, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Ricardo,
>
> Thank you for the patch.
>
> I would use "software entities" and not "virtual entities" in the
> subject line and everywhere else, as those entities are not virtual.
>
> On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> > Neither the GPIO nor the SWENTITY entities form part of the device
> > pipeline. We just create them to hold emulated uvc controls.
> >
> > When the device initializes, a warning is thrown by the v4l2 core:
> > uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
> >
> > There are no entity function that matches what we are doing here, and
> > it does not make to much sense to create a function for entities that
> > do not really exist.
>
> I don't agree with this. The purpose of reporting entities to userspace
> through the MC API is to let application enumerate what entities a
> device contains. Being able to enumerate software entities seems as
> useful as being able to enumerate hardware entities.
What function shall we use in this case? Nothing here seems to match a
software entity
https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-types.html
Any suggestion for name?
Shall we just live with the warning in dmesg?
>
> > Do not create MC entities for them and pretend nothing happened here.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> > 1 file changed, 10 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> > --- a/drivers/media/usb/uvc/uvc_entity.c
> > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > {
> > int ret;
> >
> > + /*
> > + * Do not initialize virtual entities, they do not really exist
> > + * and are not connected to any other entities.
> > + */
> > + switch (UVC_ENTITY_TYPE(entity)) {
> > + case UVC_EXT_GPIO_UNIT:
> > + case UVC_SWENTITY_UNIT:
> > + return 0;
> > + }
> > +
> > if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> > u32 function;
> >
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
2025-06-29 18:14 ` Laurent Pinchart
@ 2025-07-01 11:26 ` Ricardo Ribalda
2025-07-14 14:31 ` Laurent Pinchart
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-01 11:26 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Sun, 29 Jun 2025 at 20:15, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Thu, Jun 05, 2025 at 05:53:04PM +0000, Ricardo Ribalda wrote:
> > Fetch the rotation from the fwnode and map it into a control.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 22 +++++++++++++--
> > drivers/media/usb/uvc/uvc_swentity.c | 55 ++++++++++++++++++++++++++++++++----
> > drivers/media/usb/uvc/uvcvideo.h | 5 ++++
> > 3 files changed, 74 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 59be62ae24a4219fa9d7aacf2ae7382c95362178..5788f0c0f6604da06a7bca1b9999d0957817e75e 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -378,11 +378,18 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > },
> > {
> > .entity = UVC_GUID_SWENTITY,
> > - .selector = 0,
> > - .index = 0,
> > + .selector = UVC_SWENTITY_ORIENTATION,
> > + .index = UVC_SWENTITY_ORIENTATION,
> > .size = 1,
> > .flags = UVC_CTRL_FLAG_GET_CUR,
> > },
> > + {
> > + .entity = UVC_GUID_SWENTITY,
> > + .selector = UVC_SWENTITY_ROTATION,
> > + .index = UVC_SWENTITY_ROTATION,
> > + .size = 2,
> > + .flags = UVC_CTRL_FLAG_GET_RANGE,
> > + },
> > };
> >
> > static const u32 uvc_control_classes[] = {
> > @@ -1025,7 +1032,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > {
> > .id = V4L2_CID_CAMERA_ORIENTATION,
> > .entity = UVC_GUID_SWENTITY,
> > - .selector = 0,
> > + .selector = UVC_SWENTITY_ORIENTATION,
> > .size = 8,
> > .offset = 0,
> > .v4l2_type = V4L2_CTRL_TYPE_MENU,
> > @@ -1033,6 +1040,15 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> > V4L2_CAMERA_ORIENTATION_FRONT),
> > },
> > + {
> > + .id = V4L2_CID_CAMERA_SENSOR_ROTATION,
> > + .entity = UVC_GUID_SWENTITY,
> > + .selector = UVC_SWENTITY_ROTATION,
> > + .size = 16,
> > + .offset = 0,
> > + .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
> > + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
> > + },
> > };
> >
> > /* ------------------------------------------------------------------------
> > diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> > index 702a2c26e029a0655dade177ed2a9b88d7a4136d..60f3166addbeb7d2e431d107b23034d2d11a1812 100644
> > --- a/drivers/media/usb/uvc/uvc_swentity.c
> > +++ b/drivers/media/usb/uvc/uvc_swentity.c
> > @@ -10,10 +10,11 @@
> > #include <media/v4l2-fwnode.h>
> > #include "uvcvideo.h"
> >
> > -static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > - u8 cs, void *data, u16 size)
> > +static int uvc_swentity_get_orientation(struct uvc_device *dev,
> > + struct uvc_entity *entity, u8 cs,
> > + void *data, u16 size)
> > {
> > - if (size < 1)
> > + if (cs != UVC_SWENTITY_ORIENTATION || size != 1)
> > return -EINVAL;
> >
> > switch (entity->swentity.props.orientation) {
> > @@ -30,6 +31,31 @@ static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entit
> > return 0;
> > }
> >
> > +static int uvc_swentity_get_rotation(struct uvc_device *dev,
> > + struct uvc_entity *entity, u8 cs, void *data,
> > + u16 size)
> > +{
> > + if (cs != UVC_SWENTITY_ROTATION || size != 2)
> > + return -EINVAL;
> > +
> > + ((u8 *)data)[0] = entity->swentity.props.rotation;
> > + ((u8 *)data)[1] = entity->swentity.props.rotation >> 8;
> > +
> > + return 0;
> > +}
> > +
> > +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *data, u16 size)
> > +{
> > + switch (cs) {
> > + case UVC_SWENTITY_ORIENTATION:
> > + return uvc_swentity_get_orientation(dev, entity, cs, data, size);
> > + case UVC_SWENTITY_ROTATION:
> > + return uvc_swentity_get_rotation(dev, entity, cs, data, size);
> > + }
> > + return -EINVAL;
> > +}
> > +
> > static int uvc_swentity_get_info(struct uvc_device *dev,
> > struct uvc_entity *entity, u8 cs, u8 *caps)
> > {
> > @@ -37,11 +63,22 @@ static int uvc_swentity_get_info(struct uvc_device *dev,
> > return 0;
> > }
> >
> > +static int uvc_swentity_get_res(struct uvc_device *dev, struct uvc_entity *entity,
> > + u8 cs, void *res, u16 size)
> > +{
> > + if (size == 0)
> > + return -EINVAL;
>
> The get_cur functions return an error if the size doesn't match the
> expected size. I think you can return -EINVAL if size != 1.
>
> > + ((u8 *)res)[0] = 1;
> > + memset(res + 1, 0, size - 1);
>
> And drop the memset.
>
> > + return 0;
> > +}
> > +
> > int uvc_swentity_init(struct uvc_device *dev)
> > {
> > static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> > struct v4l2_fwnode_device_properties props;
> > struct uvc_entity *unit;
> > + u8 controls = 0;
> > int ret;
> >
> > ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> > @@ -49,7 +86,11 @@ int uvc_swentity_init(struct uvc_device *dev)
> > return dev_err_probe(&dev->intf->dev, ret,
> > "Can't parse fwnode\n");
> >
> > - if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> > + if (props.orientation != V4L2_FWNODE_PROPERTY_UNSET)
> > + controls |= BIT(UVC_SWENTITY_ORIENTATION);
> > + if (props.rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > + controls |= BIT(UVC_SWENTITY_ROTATION);
> > + if (!controls)
> > return 0;
> >
> > unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> > @@ -60,9 +101,13 @@ int uvc_swentity_init(struct uvc_device *dev)
> > unit->swentity.props = props;
> > unit->swentity.bControlSize = 1;
> > unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> > - unit->swentity.bmControls[0] = 1;
> > + unit->swentity.bmControls[0] = controls;
> > unit->get_cur = uvc_swentity_get_cur;
> > unit->get_info = uvc_swentity_get_info;
> > + unit->get_res = uvc_swentity_get_res;
> > + unit->get_def = uvc_swentity_get_rotation;
> > + unit->get_min = uvc_swentity_get_rotation;
> > + unit->get_max = uvc_swentity_get_rotation;
>
> Why do you support GET_DEF, GET_MIN and GET_MAX for rotation only ?
Orientation has enum type. It does not require min or max.
For get_def I could use get_cur, but 0 is as good as any other value
within range.
>
> > strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> >
> > list_add_tail(&unit->list, &dev->entities);
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index d6da8ed3ad4cf3377df49923e051fe04d83d2e38..7cca0dc75d11f6a13bc4f09676a5a00e80cb38f7 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -45,6 +45,11 @@
> > #define UVC_SWENTITY_UNIT 0x7ffd
> > #define UVC_SWENTITY_UNIT_ID 0x101
> >
> > +enum {
> > + UVC_SWENTITY_ORIENTATION,
> > + UVC_SWENTITY_ROTATION
> > +};
> > +
> > /* ------------------------------------------------------------------------
> > * Driver specific constants.
> > */
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-07-01 9:04 ` Ricardo Ribalda
@ 2025-07-07 21:01 ` Sakari Ailus
0 siblings, 0 replies; 62+ messages in thread
From: Sakari Ailus @ 2025-07-07 21:01 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Tue, Jul 01, 2025 at 11:04:25AM +0200, Ricardo Ribalda wrote:
> Hi Sakari
>
> Thanks for your review!
>
> On Mon, 30 Jun 2025 at 09:06, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> >
> > Hi Ricardo,
> >
> > Thanks for the update.
> >
> > On 6/5/25 20:52, Ricardo Ribalda wrote:
> > > Currently v4l2_fwnode_device_parse() obtains the orientation and
> > > rotation via fwnode properties.
> > >
> > > Extend the function to support as well ACPI devices with _PLD info.
> > >
> > > We give a higher priority to fwnode, because it might contain quirks
> > > injected via swnodes.
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > > drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
> > > 1 file changed, 79 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
> > > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > > @@ -15,6 +15,7 @@
> > > * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > */
> > > #include <linux/acpi.h>
> > > +#include <acpi/acpi_bus.h>
> > > #include <linux/kernel.h>
> > > #include <linux/mm.h>
> > > #include <linux/module.h>
> > > @@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
> > > }
> > > EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
> > >
> > > -int v4l2_fwnode_device_parse(struct device *dev,
> > > - struct v4l2_fwnode_device_properties *props)
> > > +static int v4l2_fwnode_device_parse_acpi(struct device *dev,
> > > + struct v4l2_fwnode_device_properties *props)
> > > +{
> > > + struct acpi_pld_info *pld;
> > > + int ret = 0;
> > > +
> > > + if (!is_acpi_device_node(dev_fwnode(dev)))
> > > + return 0;
> > > +
> > > + if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
> > > + dev_dbg(dev, "acpi _PLD call failed\n");
> >
> > I'd do:
> >
> > acpi_handle_debug(ACPI_HANDLE(dev), "cannot obtain _PLD\n");
> ack
> >
> > > + return 0;
> > > + }
> > > +
> > > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
> > > + switch (pld->panel) {
> > > + case ACPI_PLD_PANEL_FRONT:
> > > + props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> > > + break;
> > > + case ACPI_PLD_PANEL_BACK:
> > > + props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
> > > + break;
> > > + case ACPI_PLD_PANEL_TOP:
> > > + case ACPI_PLD_PANEL_LEFT:
> > > + case ACPI_PLD_PANEL_RIGHT:
> > > + case ACPI_PLD_PANEL_UNKNOWN:
> > > + props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> > > + break;
> > > + default:
> > > + dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
> >
> > Similarly:
> >
> > acpi_handle_debug(ACPI_HANDLE(dev), "invalid panel %u in _PLD\n",
> > pld->panel);
> >
> > > + ret = -EINVAL;
> >
> > Should this be an error or should we simply ignore it here (and maybe
> > use acpi_handle_warn())?
>
> v4l2_fwnode_device_parse_of() returns -EINVAL for a similar situation,
> so I think it is better to be consistent and return -EINVAL here.
> But I agree that acpi_handle_warn() better suits here than _dbg.
Ack.
>
> >
> > > + goto done;
> > > + }
> > > + }
> > > +
> > > + if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
> > > + switch (pld->rotation) {
> > > + case 0 ... 7:
> > > + props->rotation = pld->rotation * 45;
> > > + break;
> > > + default:
> > > + dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
> >
> > acpi_handle_debug(ACPI_HANDLE(dev), "invalid rotation %u in _PLD\n",
> > pld->rotation);
> >
> > > + ret = -EINVAL;
> > > + goto done;
> > > + }
> > > + }
> > > +
> > > +done:
> > > + ACPI_FREE(pld);
> > > + return ret;
> > > +}
> > > +
> > > +static int v4l2_fwnode_device_parse_dt(struct device *dev,
> >
> > I'd call this v4l2_fwnode_device_parse_of() as we're parsing OF nodes
> > and properties here.
> ack
> >
> > > + struct v4l2_fwnode_device_properties *props)
> > > {
> > > struct fwnode_handle *fwnode = dev_fwnode(dev);
> > > u32 val;
> > > int ret;
> > >
> > > - memset(props, 0, sizeof(*props));
> > > -
> > > - props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > > ret = fwnode_property_read_u32(fwnode, "orientation", &val);
> > > if (!ret) {
> > > switch (val) {
> > > @@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > > dev_dbg(dev, "device orientation: %u\n", val);
> > > }
> > >
> > > - props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > > ret = fwnode_property_read_u32(fwnode, "rotation", &val);
> > > if (!ret) {
> > > if (val >= 360) {
> > > @@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > >
> > > return 0;
> > > }
> > > +
> > > +int v4l2_fwnode_device_parse(struct device *dev,
> > > + struct v4l2_fwnode_device_properties *props)
> > > +{
> > > + int ret;
> > > +
> > > + memset(props, 0, sizeof(*props));
> > > +
> > > + props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > > + props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > > +
> > > + /* Start by looking into swnodes and dt. */
s/dt/DT/
> > > + ret = v4l2_fwnode_device_parse_dt(dev, props);
^
Extra space.
> > > + if (ret)
> > > + return ret;
> > > +
> > > + /* Orientation and rotation found!, we are ready. */
> > > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
> > > + props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > > + return 0;
> >
> > I think you can remove this check without affecting the functionality.
> I want to avoid calling an acpi method unless it is strictly
> necessary. The check is not that ugly... if it is ok with you i'd
> rather keep it.
The function is already checking the node is an ACPI node and returns 0
otherwise. The above is simply redundant.
>
> >
> > > +
> > > + /* Let's check the acpi table. */
s/acpi/ACPI/
> > > + return v4l2_fwnode_device_parse_acpi(dev, props);
> > > +}
> > > EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
> > >
> > > /*
> > >
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
2025-06-29 9:24 ` Sakari Ailus
@ 2025-07-07 21:05 ` Sakari Ailus
2025-07-14 13:08 ` Hans de Goede
2 siblings, 0 replies; 62+ messages in thread
From: Sakari Ailus @ 2025-07-07 21:05 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
A few more comments.
On Thu, Jun 05, 2025 at 05:52:56PM +0000, Ricardo Ribalda wrote:
> The function v4l2_fwnode_device_parse() is not capable of parsint the
s/not/now/
s/parsin\Kt/g/
?
> _PLD method, there is no need to duplicate the rotation information in a
> swnode.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/acpi/mipi-disco-img.c | 15 ---------------
> 1 file changed, 15 deletions(-)
>
> diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c
> index 5b85989f96beeb726f59ac9e12e965a215fb38f6..b58b5ba22a47a4afc5212998074d322f0b7586dc 100644
> --- a/drivers/acpi/mipi-disco-img.c
> +++ b/drivers/acpi/mipi-disco-img.c
> @@ -617,21 +617,6 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2)
>
> adev_fwnode = acpi_fwnode_handle(adev);
>
> - /*
> - * If the "rotation" property is not present, but _PLD is there,
> - * evaluate it to get the "rotation" value.
> - */
> - if (!fwnode_property_present(adev_fwnode, "rotation")) {
> - struct acpi_pld_info *pld;
> -
> - if (acpi_get_physical_device_location(handle, &pld)) {
> - swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] =
> - PROPERTY_ENTRY_U32("rotation",
> - pld->rotation * 45U);
> - kfree(pld);
> - }
> - }
> -
> if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val))
> swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] =
> PROPERTY_ENTRY_U32("clock-frequency", val);
>
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-06-05 17:52 ` [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations Ricardo Ribalda
@ 2025-07-07 21:44 ` Sakari Ailus
2025-07-08 9:16 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Sakari Ailus @ 2025-07-07 21:44 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> The v4l2_fwnode_device_properties contains information about the
> rotation. Use it if the ssdb data is inconclusive.
As SSDB and _PLD provide the same information, are they always aligned? Do
you have any experience on how is this actually in firmware?
_PLD is standardised so it would seem reasonable to stick to that -- if it
exists. Another approach could be to pick the one that doesn't translate to
a sane default (0°).
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/pci/intel/ipu-bridge.c | 30 +++++++++++++++++++-----------
> 1 file changed, 19 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
> index 020aa52f590d66b6d333adc56ebfb9ab0561db51..6f436a8b4d23373af8a6668530333a827eca467a 100644
> --- a/drivers/media/pci/intel/ipu-bridge.c
> +++ b/drivers/media/pci/intel/ipu-bridge.c
> @@ -236,37 +236,41 @@ static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
> }
>
> static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
> - struct ipu_sensor_ssdb *ssdb)
> + struct ipu_sensor_ssdb *ssdb,
> + struct v4l2_fwnode_device_properties *props)
> {
> switch (ssdb->degree) {
> case IPU_SENSOR_ROTATION_NORMAL:
> return 0;
> case IPU_SENSOR_ROTATION_INVERTED:
> return 180;
> - default:
> + }
> +
> + if (props->rotation == V4L2_FWNODE_PROPERTY_UNSET) {
> dev_warn(ADEV_DEV(adev),
> "Unknown rotation %d. Assume 0 degree rotation\n",
> ssdb->degree);
> return 0;
> }
> +
> + return props->rotation;
> }
>
> -static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
> +static enum v4l2_fwnode_orientation
> +ipu_bridge_parse_orientation(struct acpi_device *adev,
> + struct v4l2_fwnode_device_properties *props)
> {
> - struct v4l2_fwnode_device_properties props;
> - int ret;
> -
> - ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
> - if (!ret || props.rotation == V4L2_FWNODE_PROPERTY_UNSET) {
> + if (props->orientation == V4L2_FWNODE_PROPERTY_UNSET) {
> dev_warn(ADEV_DEV(adev), "Using default orientation\n");
> return V4L2_FWNODE_ORIENTATION_EXTERNAL;
> }
>
> - return props.orientation;
> + return props->orientation;
> }
>
> int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> {
> + struct v4l2_fwnode_device_properties props;
> struct ipu_sensor_ssdb ssdb = {};
> int ret;
>
> @@ -274,6 +278,10 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> if (ret)
> return ret;
>
> + ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
> + if (ret)
> + return ret;
> +
> if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {
> dev_warn(ADEV_DEV(adev), "Unknown VCM type %d\n", ssdb.vcmtype);
> ssdb.vcmtype = 0;
> @@ -287,8 +295,8 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> sensor->link = ssdb.link;
> sensor->lanes = ssdb.lanes;
> sensor->mclkspeed = ssdb.mclkspeed;
> - sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb);
> - sensor->orientation = ipu_bridge_parse_orientation(adev);
> + sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb, &props);
> + sensor->orientation = ipu_bridge_parse_orientation(adev, &props);
>
> if (ssdb.vcmtype)
> sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1];
>
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-07-01 11:20 ` Ricardo Ribalda
@ 2025-07-08 6:28 ` Ricardo Ribalda
2025-07-14 14:36 ` Laurent Pinchart
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-08 6:28 UTC (permalink / raw)
To: Laurent Pinchart, Hans Verkuil
Cc: Hans de Goede, Mauro Carvalho Chehab, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Laurent
On Tue, 1 Jul 2025 at 13:20, Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> Hi Laurent and Hans
>
>
> On Sun, 29 Jun 2025 at 20:06, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Hi Ricardo,
> >
> > Thank you for the patch.
> >
> > I would use "software entities" and not "virtual entities" in the
> > subject line and everywhere else, as those entities are not virtual.
> >
> > On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> > > Neither the GPIO nor the SWENTITY entities form part of the device
> > > pipeline. We just create them to hold emulated uvc controls.
> > >
> > > When the device initializes, a warning is thrown by the v4l2 core:
> > > uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
> > >
> > > There are no entity function that matches what we are doing here, and
> > > it does not make to much sense to create a function for entities that
> > > do not really exist.
> >
> > I don't agree with this. The purpose of reporting entities to userspace
> > through the MC API is to let application enumerate what entities a
> > device contains. Being able to enumerate software entities seems as
> > useful as being able to enumerate hardware entities.
>
> What function shall we use in this case? Nothing here seems to match a
> software entity
> https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-types.html
>
> Any suggestion for name?
> Shall we just live with the warning in dmesg?
I just realised that if/when we move to the control framework, the
software entity will be gone.... So to avoid introducing a uAPI change
that will be reverted later I think that we should keep this patch.
Regards
>
> >
> > > Do not create MC entities for them and pretend nothing happened here.
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > > drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> > > 1 file changed, 10 insertions(+)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > > index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> > > --- a/drivers/media/usb/uvc/uvc_entity.c
> > > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > > @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > > {
> > > int ret;
> > >
> > > + /*
> > > + * Do not initialize virtual entities, they do not really exist
> > > + * and are not connected to any other entities.
> > > + */
> > > + switch (UVC_ENTITY_TYPE(entity)) {
> > > + case UVC_EXT_GPIO_UNIT:
> > > + case UVC_SWENTITY_UNIT:
> > > + return 0;
> > > + }
> > > +
> > > if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> > > u32 function;
> > >
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
>
>
>
> --
> Ricardo Ribalda
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-07 21:44 ` Sakari Ailus
@ 2025-07-08 9:16 ` Ricardo Ribalda
2025-07-08 9:22 ` Sakari Ailus
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-08 9:16 UTC (permalink / raw)
To: Sakari Ailus, Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Sakari
Thanks for your review
On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>
> Hi Ricardo,
>
> On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > The v4l2_fwnode_device_properties contains information about the
> > rotation. Use it if the ssdb data is inconclusive.
>
> As SSDB and _PLD provide the same information, are they always aligned? Do
> you have any experience on how is this actually in firmware?
Not really, in ChromeOS we are pretty lucky to control the firmware.
@HdG Do you have some experience/opinion here?
>
> _PLD is standardised so it would seem reasonable to stick to that -- if it
> exists. Another approach could be to pick the one that doesn't translate to
> a sane default (0°).
I'd rather stick to the current prioritization unless there is a
strong argument against it. Otherwise there is a chance that we will
have regressions (outside CrOS)
>
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/pci/intel/ipu-bridge.c | 30 +++++++++++++++++++-----------
> > 1 file changed, 19 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
> > index 020aa52f590d66b6d333adc56ebfb9ab0561db51..6f436a8b4d23373af8a6668530333a827eca467a 100644
> > --- a/drivers/media/pci/intel/ipu-bridge.c
> > +++ b/drivers/media/pci/intel/ipu-bridge.c
> > @@ -236,37 +236,41 @@ static int ipu_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
> > }
> >
> > static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
> > - struct ipu_sensor_ssdb *ssdb)
> > + struct ipu_sensor_ssdb *ssdb,
> > + struct v4l2_fwnode_device_properties *props)
> > {
> > switch (ssdb->degree) {
> > case IPU_SENSOR_ROTATION_NORMAL:
> > return 0;
> > case IPU_SENSOR_ROTATION_INVERTED:
> > return 180;
> > - default:
> > + }
> > +
> > + if (props->rotation == V4L2_FWNODE_PROPERTY_UNSET) {
> > dev_warn(ADEV_DEV(adev),
> > "Unknown rotation %d. Assume 0 degree rotation\n",
> > ssdb->degree);
> > return 0;
> > }
> > +
> > + return props->rotation;
> > }
> >
> > -static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
> > +static enum v4l2_fwnode_orientation
> > +ipu_bridge_parse_orientation(struct acpi_device *adev,
> > + struct v4l2_fwnode_device_properties *props)
> > {
> > - struct v4l2_fwnode_device_properties props;
> > - int ret;
> > -
> > - ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
> > - if (!ret || props.rotation == V4L2_FWNODE_PROPERTY_UNSET) {
> > + if (props->orientation == V4L2_FWNODE_PROPERTY_UNSET) {
> > dev_warn(ADEV_DEV(adev), "Using default orientation\n");
> > return V4L2_FWNODE_ORIENTATION_EXTERNAL;
> > }
> >
> > - return props.orientation;
> > + return props->orientation;
> > }
> >
> > int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> > {
> > + struct v4l2_fwnode_device_properties props;
> > struct ipu_sensor_ssdb ssdb = {};
> > int ret;
> >
> > @@ -274,6 +278,10 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> > if (ret)
> > return ret;
> >
> > + ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
> > + if (ret)
> > + return ret;
> > +
> > if (ssdb.vcmtype > ARRAY_SIZE(ipu_vcm_types)) {
> > dev_warn(ADEV_DEV(adev), "Unknown VCM type %d\n", ssdb.vcmtype);
> > ssdb.vcmtype = 0;
> > @@ -287,8 +295,8 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
> > sensor->link = ssdb.link;
> > sensor->lanes = ssdb.lanes;
> > sensor->mclkspeed = ssdb.mclkspeed;
> > - sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb);
> > - sensor->orientation = ipu_bridge_parse_orientation(adev);
> > + sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb, &props);
> > + sensor->orientation = ipu_bridge_parse_orientation(adev, &props);
> >
> > if (ssdb.vcmtype)
> > sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1];
> >
>
> --
> Regards,
>
> Sakari Ailus
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 9:16 ` Ricardo Ribalda
@ 2025-07-08 9:22 ` Sakari Ailus
2025-07-08 12:09 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Sakari Ailus @ 2025-07-08 9:22 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
> Hi Sakari
>
> Thanks for your review
>
> On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> >
> > Hi Ricardo,
> >
> > On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > > The v4l2_fwnode_device_properties contains information about the
> > > rotation. Use it if the ssdb data is inconclusive.
> >
> > As SSDB and _PLD provide the same information, are they always aligned? Do
> > you have any experience on how is this actually in firmware?
>
> Not really, in ChromeOS we are pretty lucky to control the firmware.
>
> @HdG Do you have some experience/opinion here?
>
> >
> > _PLD is standardised so it would seem reasonable to stick to that -- if it
> > exists. Another approach could be to pick the one that doesn't translate to
> > a sane default (0°).
>
> I'd rather stick to the current prioritization unless there is a
> strong argument against it. Otherwise there is a chance that we will
> have regressions (outside CrOS)
My point was rather there are no such rules currently for rotation: only
SSDB was being used by the IPU bridge to obtain the rotation value,
similarly only _PLD is consulted when it comes to orientation.
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 9:22 ` Sakari Ailus
@ 2025-07-08 12:09 ` Ricardo Ribalda
2025-07-08 12:20 ` Sakari Ailus
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-08 12:09 UTC (permalink / raw)
To: Sakari Ailus
Cc: Hans de Goede, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, 8 Jul 2025 at 11:22, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>
> Hi Ricardo,
>
> On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
> > Hi Sakari
> >
> > Thanks for your review
> >
> > On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > >
> > > Hi Ricardo,
> > >
> > > On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > > > The v4l2_fwnode_device_properties contains information about the
> > > > rotation. Use it if the ssdb data is inconclusive.
> > >
> > > As SSDB and _PLD provide the same information, are they always aligned? Do
> > > you have any experience on how is this actually in firmware?
> >
> > Not really, in ChromeOS we are pretty lucky to control the firmware.
> >
> > @HdG Do you have some experience/opinion here?
> >
> > >
> > > _PLD is standardised so it would seem reasonable to stick to that -- if it
> > > exists. Another approach could be to pick the one that doesn't translate to
> > > a sane default (0°).
> >
> > I'd rather stick to the current prioritization unless there is a
> > strong argument against it. Otherwise there is a chance that we will
> > have regressions (outside CrOS)
>
> My point was rather there are no such rules currently for rotation: only
> SSDB was being used by the IPU bridge to obtain the rotation value,
> similarly only _PLD is consulted when it comes to orientation.
So something like this:?
static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
struct ipu_sensor_ssdb *ssdb,
struct
v4l2_fwnode_device_properties *props)
{
if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
return props->rotation;
switch (ssdb->degree) {
case IPU_SENSOR_ROTATION_NORMAL:
return 0;
case IPU_SENSOR_ROTATION_INVERTED:
return 180;
}
dev_warn(ADEV_DEV(adev),
"Unknown rotation %d. Assume 0 degree rotation\n",
ssdb->degree);
return 0;
}
>
> --
> Regards,
>
> Sakari Ailus
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 12:09 ` Ricardo Ribalda
@ 2025-07-08 12:20 ` Sakari Ailus
2025-07-08 14:58 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Sakari Ailus @ 2025-07-08 12:20 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Tue, Jul 08, 2025 at 02:09:28PM +0200, Ricardo Ribalda wrote:
> On Tue, 8 Jul 2025 at 11:22, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> >
> > Hi Ricardo,
> >
> > On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
> > > Hi Sakari
> > >
> > > Thanks for your review
> > >
> > > On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > > >
> > > > Hi Ricardo,
> > > >
> > > > On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > > > > The v4l2_fwnode_device_properties contains information about the
> > > > > rotation. Use it if the ssdb data is inconclusive.
> > > >
> > > > As SSDB and _PLD provide the same information, are they always aligned? Do
> > > > you have any experience on how is this actually in firmware?
> > >
> > > Not really, in ChromeOS we are pretty lucky to control the firmware.
> > >
> > > @HdG Do you have some experience/opinion here?
> > >
> > > >
> > > > _PLD is standardised so it would seem reasonable to stick to that -- if it
> > > > exists. Another approach could be to pick the one that doesn't translate to
> > > > a sane default (0°).
> > >
> > > I'd rather stick to the current prioritization unless there is a
> > > strong argument against it. Otherwise there is a chance that we will
> > > have regressions (outside CrOS)
> >
> > My point was rather there are no such rules currently for rotation: only
> > SSDB was being used by the IPU bridge to obtain the rotation value,
> > similarly only _PLD is consulted when it comes to orientation.
>
> So something like this:?
>
> static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
> struct ipu_sensor_ssdb *ssdb,
> struct
> v4l2_fwnode_device_properties *props)
> {
> if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> return props->rotation;
>
> switch (ssdb->degree) {
> case IPU_SENSOR_ROTATION_NORMAL:
> return 0;
> case IPU_SENSOR_ROTATION_INVERTED:
> return 180;
> }
>
> dev_warn(ADEV_DEV(adev),
> "Unknown rotation %d. Assume 0 degree rotation\n",
> ssdb->degree);
Maybe:
acpi_handle_warn(acpi_device_handle(adev), ...);
?
> return 0;
> }
Looks good to me. Maybe something similar for orientation?
--
Regards,
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 12:20 ` Sakari Ailus
@ 2025-07-08 14:58 ` Ricardo Ribalda
2025-07-08 23:46 ` Sakari Ailus
2025-07-14 13:11 ` Hans de Goede
0 siblings, 2 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-08 14:58 UTC (permalink / raw)
To: Sakari Ailus
Cc: Hans de Goede, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, 8 Jul 2025 at 14:21, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>
> Hi Ricardo,
>
> On Tue, Jul 08, 2025 at 02:09:28PM +0200, Ricardo Ribalda wrote:
> > On Tue, 8 Jul 2025 at 11:22, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > >
> > > Hi Ricardo,
> > >
> > > On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
> > > > Hi Sakari
> > > >
> > > > Thanks for your review
> > > >
> > > > On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > > > >
> > > > > Hi Ricardo,
> > > > >
> > > > > On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > > > > > The v4l2_fwnode_device_properties contains information about the
> > > > > > rotation. Use it if the ssdb data is inconclusive.
> > > > >
> > > > > As SSDB and _PLD provide the same information, are they always aligned? Do
> > > > > you have any experience on how is this actually in firmware?
> > > >
> > > > Not really, in ChromeOS we are pretty lucky to control the firmware.
> > > >
> > > > @HdG Do you have some experience/opinion here?
> > > >
> > > > >
> > > > > _PLD is standardised so it would seem reasonable to stick to that -- if it
> > > > > exists. Another approach could be to pick the one that doesn't translate to
> > > > > a sane default (0°).
> > > >
> > > > I'd rather stick to the current prioritization unless there is a
> > > > strong argument against it. Otherwise there is a chance that we will
> > > > have regressions (outside CrOS)
> > >
> > > My point was rather there are no such rules currently for rotation: only
> > > SSDB was being used by the IPU bridge to obtain the rotation value,
> > > similarly only _PLD is consulted when it comes to orientation.
> >
> > So something like this:?
> >
> > static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
> > struct ipu_sensor_ssdb *ssdb,
> > struct
> > v4l2_fwnode_device_properties *props)
> > {
> > if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > return props->rotation;
> >
> > switch (ssdb->degree) {
> > case IPU_SENSOR_ROTATION_NORMAL:
> > return 0;
> > case IPU_SENSOR_ROTATION_INVERTED:
> > return 180;
> > }
> >
> > dev_warn(ADEV_DEV(adev),
> > "Unknown rotation %d. Assume 0 degree rotation\n",
> > ssdb->degree);
>
> Maybe:
>
> acpi_handle_warn(acpi_device_handle(adev), ...);
>
> ?
>
> > return 0;
> > }
>
> Looks good to me. Maybe something similar for orientation?
Do you mean using ssdb also for orientation or using acpi_handle_warn?
I cannot find anything related to orientation for SSDB
https://github.com/coreboot/coreboot/blob/main/src/drivers/intel/mipi_camera/chip.h#L150
Am I looking in the right place?
Regards!
>
> --
> Regards,
>
> Sakari Ailus
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 14:58 ` Ricardo Ribalda
@ 2025-07-08 23:46 ` Sakari Ailus
2025-07-14 13:11 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Sakari Ailus @ 2025-07-08 23:46 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, Jul 08, 2025 at 04:58:25PM +0200, Ricardo Ribalda wrote:
> On Tue, 8 Jul 2025 at 14:21, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> >
> > Hi Ricardo,
> >
> > On Tue, Jul 08, 2025 at 02:09:28PM +0200, Ricardo Ribalda wrote:
> > > On Tue, 8 Jul 2025 at 11:22, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > > >
> > > > Hi Ricardo,
> > > >
> > > > On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
> > > > > Hi Sakari
> > > > >
> > > > > Thanks for your review
> > > > >
> > > > > On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
> > > > > >
> > > > > > Hi Ricardo,
> > > > > >
> > > > > > On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
> > > > > > > The v4l2_fwnode_device_properties contains information about the
> > > > > > > rotation. Use it if the ssdb data is inconclusive.
> > > > > >
> > > > > > As SSDB and _PLD provide the same information, are they always aligned? Do
> > > > > > you have any experience on how is this actually in firmware?
> > > > >
> > > > > Not really, in ChromeOS we are pretty lucky to control the firmware.
> > > > >
> > > > > @HdG Do you have some experience/opinion here?
> > > > >
> > > > > >
> > > > > > _PLD is standardised so it would seem reasonable to stick to that -- if it
> > > > > > exists. Another approach could be to pick the one that doesn't translate to
> > > > > > a sane default (0°).
> > > > >
> > > > > I'd rather stick to the current prioritization unless there is a
> > > > > strong argument against it. Otherwise there is a chance that we will
> > > > > have regressions (outside CrOS)
> > > >
> > > > My point was rather there are no such rules currently for rotation: only
> > > > SSDB was being used by the IPU bridge to obtain the rotation value,
> > > > similarly only _PLD is consulted when it comes to orientation.
> > >
> > > So something like this:?
> > >
> > > static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
> > > struct ipu_sensor_ssdb *ssdb,
> > > struct
> > > v4l2_fwnode_device_properties *props)
> > > {
> > > if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > > return props->rotation;
> > >
> > > switch (ssdb->degree) {
> > > case IPU_SENSOR_ROTATION_NORMAL:
> > > return 0;
> > > case IPU_SENSOR_ROTATION_INVERTED:
> > > return 180;
> > > }
> > >
> > > dev_warn(ADEV_DEV(adev),
> > > "Unknown rotation %d. Assume 0 degree rotation\n",
> > > ssdb->degree);
> >
> > Maybe:
> >
> > acpi_handle_warn(acpi_device_handle(adev), ...);
> >
> > ?
> >
> > > return 0;
> > > }
> >
> > Looks good to me. Maybe something similar for orientation?
>
> Do you mean using ssdb also for orientation or using acpi_handle_warn?
>
>
> I cannot find anything related to orientation for SSDB
> https://github.com/coreboot/coreboot/blob/main/src/drivers/intel/mipi_camera/chip.h#L150
>
> Am I looking in the right place?
Ah, maybe SSDB has only rotation? At least it's less duplicated information
in different format, so that's a good thing. So this just applies to
rotation, it seems.
--
Sakari Ailus
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 01/12] media: uvcvideo: Always set default_value
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
2025-06-29 17:39 ` Laurent Pinchart
@ 2025-07-14 13:00 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:00 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:52, Ricardo Ribalda wrote:
> If the control does not support GET_DEF, the field default_value will be
> left uninitialized during queryctrl.
>
> Fixes: c0efd232929c ("V4L/DVB (8145a): USB Video Class driver")
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me,
Reviewed-by: Hans de Goede <hansg@kernel.org>
with Laurent's remarks addressed.
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 44b6513c526421943bb9841fb53dc5f8e9f93f02..47e8ccc39234d1769384b55539a21df07f3d57c7 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1497,6 +1497,8 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
> UVC_GET_DEF, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> + } else {
> + v4l2_ctrl->default_value = 0;
> }
>
> switch (mapping->v4l2_type) {
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-06-05 17:52 ` [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse Ricardo Ribalda
2025-06-29 9:21 ` Sakari Ailus
@ 2025-07-14 13:03 ` Hans de Goede
2025-07-14 14:14 ` Ricardo Ribalda
1 sibling, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:03 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:52, Ricardo Ribalda wrote:
> Currently v4l2_fwnode_device_parse() obtains the orientation and
> rotation via fwnode properties.
>
> Extend the function to support as well ACPI devices with _PLD info.
>
> We give a higher priority to fwnode, because it might contain quirks
> injected via swnodes.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
> 1 file changed, 79 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -15,6 +15,7 @@
> * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> */
> #include <linux/acpi.h>
> +#include <acpi/acpi_bus.h>
> #include <linux/kernel.h>
> #include <linux/mm.h>
> #include <linux/module.h>
> @@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
> }
> EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
>
> -int v4l2_fwnode_device_parse(struct device *dev,
> - struct v4l2_fwnode_device_properties *props)
> +static int v4l2_fwnode_device_parse_acpi(struct device *dev,
> + struct v4l2_fwnode_device_properties *props)
> +{
> + struct acpi_pld_info *pld;
> + int ret = 0;
> +
> + if (!is_acpi_device_node(dev_fwnode(dev)))
> + return 0;
> +
> + if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
> + dev_dbg(dev, "acpi _PLD call failed\n");
> + return 0;
> + }
> +
> + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
"!=" should be "==" here. So that we set it when not set already,
rather then leaving it unset when not set already.
> + switch (pld->panel) {
> + case ACPI_PLD_PANEL_FRONT:
> + props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> + break;
> + case ACPI_PLD_PANEL_BACK:
> + props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
> + break;
> + case ACPI_PLD_PANEL_TOP:
> + case ACPI_PLD_PANEL_LEFT:
> + case ACPI_PLD_PANEL_RIGHT:
> + case ACPI_PLD_PANEL_UNKNOWN:
> + props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> + break;
> + default:
> + dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
> + ret = -EINVAL;
> + goto done;
> + }
> + }
> +
> + if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
Same here.
> + switch (pld->rotation) {
> + case 0 ... 7:
> + props->rotation = pld->rotation * 45;
> + break;
> + default:
> + dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
> + ret = -EINVAL;
> + goto done;
> + }
> + }
> +
> +done:
> + ACPI_FREE(pld);
> + return ret;
> +}
> +
> +static int v4l2_fwnode_device_parse_dt(struct device *dev,
> + struct v4l2_fwnode_device_properties *props)
> {
> struct fwnode_handle *fwnode = dev_fwnode(dev);
> u32 val;
> int ret;
>
> - memset(props, 0, sizeof(*props));
> -
> - props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> ret = fwnode_property_read_u32(fwnode, "orientation", &val);
> if (!ret) {
> switch (val) {
> @@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
> dev_dbg(dev, "device orientation: %u\n", val);
> }
>
> - props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> ret = fwnode_property_read_u32(fwnode, "rotation", &val);
> if (!ret) {
> if (val >= 360) {
> @@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
>
> return 0;
> }
> +
> +int v4l2_fwnode_device_parse(struct device *dev,
> + struct v4l2_fwnode_device_properties *props)
> +{
> + int ret;
> +
> + memset(props, 0, sizeof(*props));
> +
> + props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> + props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> +
> + /* Start by looking into swnodes and dt. */
> + ret = v4l2_fwnode_device_parse_dt(dev, props);
> + if (ret)
> + return ret;
> +
> + /* Orientation and rotation found!, we are ready. */
> + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
> + props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> + return 0;
As Sakari set, this can be dropped, with the 2 checks above
fixed to be == v4l2_fwnode_device_parse_acpi() will become
a no-op in this case.
With these things fixed:
Reviewed-by: Hans de Goede <hansg@kernel.org>
Regards,
Hans
> +
> + /* Let's check the acpi table. */
> + return v4l2_fwnode_device_parse_acpi(dev, props);
> +}
> EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
>
> /*
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
2025-06-29 9:24 ` Sakari Ailus
2025-07-07 21:05 ` Sakari Ailus
@ 2025-07-14 13:08 ` Hans de Goede
2 siblings, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:08 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:52, Ricardo Ribalda wrote:
> The function v4l2_fwnode_device_parse() is not capable of parsint the
> _PLD method, there is no need to duplicate the rotation information in a
> swnode.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hansg@kernel.org>
with Sakari's review remarks addressed.
Regards,
Hans
> ---
> drivers/acpi/mipi-disco-img.c | 15 ---------------
> 1 file changed, 15 deletions(-)
>
> diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c
> index 5b85989f96beeb726f59ac9e12e965a215fb38f6..b58b5ba22a47a4afc5212998074d322f0b7586dc 100644
> --- a/drivers/acpi/mipi-disco-img.c
> +++ b/drivers/acpi/mipi-disco-img.c
> @@ -617,21 +617,6 @@ static void init_crs_csi2_swnodes(struct crs_csi2 *csi2)
>
> adev_fwnode = acpi_fwnode_handle(adev);
>
> - /*
> - * If the "rotation" property is not present, but _PLD is there,
> - * evaluate it to get the "rotation" value.
> - */
> - if (!fwnode_property_present(adev_fwnode, "rotation")) {
> - struct acpi_pld_info *pld;
> -
> - if (acpi_get_physical_device_location(handle, &pld)) {
> - swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] =
> - PROPERTY_ENTRY_U32("rotation",
> - pld->rotation * 45U);
> - kfree(pld);
> - }
> - }
> -
> if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val))
> swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] =
> PROPERTY_ENTRY_U32("clock-frequency", val);
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper
2025-06-05 17:52 ` [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper Ricardo Ribalda
2025-06-06 4:27 ` kernel test robot
@ 2025-07-14 13:11 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:11 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:52, Ricardo Ribalda wrote:
> v4l2_fwnode_device_parse now supports acpi devices as well. Use the
> helper instead of re-implement the logic.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/pci/intel/ipu-bridge.c | 32 ++++++--------------------------
> 1 file changed, 6 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
> index 83e682e1a4b77d9d97b2988750732d0b7c9087b3..020aa52f590d66b6d333adc56ebfb9ab0561db51 100644
> --- a/drivers/media/pci/intel/ipu-bridge.c
> +++ b/drivers/media/pci/intel/ipu-bridge.c
> @@ -253,36 +253,16 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
>
> static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_device *adev)
> {
In patch 5/12 you add a "struct v4l2_fwnode_device_properties *props" parameter
to this function and move the calling of v4l2_fwnode_device_parse() to
ipu_bridge_parse_ssdb().
You might just as well do this here so that there is a bit less churn in
the series.
Regards,
Hans
> - enum v4l2_fwnode_orientation orientation;
> - struct acpi_pld_info *pld = NULL;
> + struct v4l2_fwnode_device_properties props;
> + int ret;
>
> - if (!acpi_get_physical_device_location(ACPI_PTR(adev->handle), &pld)) {
> - dev_warn(ADEV_DEV(adev), "_PLD call failed, using default orientation\n");
> + ret = v4l2_fwnode_device_parse(ADEV_DEV(adev), &props);
> + if (!ret || props.rotation == V4L2_FWNODE_PROPERTY_UNSET) {
> + dev_warn(ADEV_DEV(adev), "Using default orientation\n");
> return V4L2_FWNODE_ORIENTATION_EXTERNAL;
> }
>
> - switch (pld->panel) {
> - case ACPI_PLD_PANEL_FRONT:
> - orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> - break;
> - case ACPI_PLD_PANEL_BACK:
> - orientation = V4L2_FWNODE_ORIENTATION_BACK;
> - break;
> - case ACPI_PLD_PANEL_TOP:
> - case ACPI_PLD_PANEL_LEFT:
> - case ACPI_PLD_PANEL_RIGHT:
> - case ACPI_PLD_PANEL_UNKNOWN:
> - orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> - break;
> - default:
> - dev_warn(ADEV_DEV(adev), "Unknown _PLD panel val %d\n",
> - pld->panel);
> - orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> - break;
> - }
> -
> - ACPI_FREE(pld);
> - return orientation;
> + return props.orientation;
> }
>
> int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations
2025-07-08 14:58 ` Ricardo Ribalda
2025-07-08 23:46 ` Sakari Ailus
@ 2025-07-14 13:11 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:11 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi,
On 8-Jul-25 16:58, Ricardo Ribalda wrote:
> On Tue, 8 Jul 2025 at 14:21, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>>
>> Hi Ricardo,
>>
>> On Tue, Jul 08, 2025 at 02:09:28PM +0200, Ricardo Ribalda wrote:
>>> On Tue, 8 Jul 2025 at 11:22, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>>>>
>>>> Hi Ricardo,
>>>>
>>>> On Tue, Jul 08, 2025 at 11:16:25AM +0200, Ricardo Ribalda wrote:
>>>>> Hi Sakari
>>>>>
>>>>> Thanks for your review
>>>>>
>>>>> On Mon, 7 Jul 2025 at 23:45, Sakari Ailus <sakari.ailus@linux.intel.com> wrote:
>>>>>>
>>>>>> Hi Ricardo,
>>>>>>
>>>>>> On Thu, Jun 05, 2025 at 05:52:58PM +0000, Ricardo Ribalda wrote:
>>>>>>> The v4l2_fwnode_device_properties contains information about the
>>>>>>> rotation. Use it if the ssdb data is inconclusive.
>>>>>>
>>>>>> As SSDB and _PLD provide the same information, are they always aligned? Do
>>>>>> you have any experience on how is this actually in firmware?
>>>>>
>>>>> Not really, in ChromeOS we are pretty lucky to control the firmware.
>>>>>
>>>>> @HdG Do you have some experience/opinion here?
>>>>>
>>>>>>
>>>>>> _PLD is standardised so it would seem reasonable to stick to that -- if it
>>>>>> exists. Another approach could be to pick the one that doesn't translate to
>>>>>> a sane default (0°).
>>>>>
>>>>> I'd rather stick to the current prioritization unless there is a
>>>>> strong argument against it. Otherwise there is a chance that we will
>>>>> have regressions (outside CrOS)
>>>>
>>>> My point was rather there are no such rules currently for rotation: only
>>>> SSDB was being used by the IPU bridge to obtain the rotation value,
>>>> similarly only _PLD is consulted when it comes to orientation.
>>>
>>> So something like this:?
>>>
>>> static u32 ipu_bridge_parse_rotation(struct acpi_device *adev,
>>> struct ipu_sensor_ssdb *ssdb,
>>> struct
>>> v4l2_fwnode_device_properties *props)
>>> {
>>> if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
>>> return props->rotation;
>>>
>>> switch (ssdb->degree) {
>>> case IPU_SENSOR_ROTATION_NORMAL:
>>> return 0;
>>> case IPU_SENSOR_ROTATION_INVERTED:
>>> return 180;
>>> }
>>>
>>> dev_warn(ADEV_DEV(adev),
>>> "Unknown rotation %d. Assume 0 degree rotation\n",
>>> ssdb->degree);
>>
>> Maybe:
>>
>> acpi_handle_warn(acpi_device_handle(adev), ...);
>>
>> ?
>>
>>> return 0;
>>> }
>>
>> Looks good to me. Maybe something similar for orientation?
>
> Do you mean using ssdb also for orientation or using acpi_handle_warn?
>
>
> I cannot find anything related to orientation for SSDB
> https://github.com/coreboot/coreboot/blob/main/src/drivers/intel/mipi_camera/chip.h#L150
>
> Am I looking in the right place?
I believe that orientation is only available in the PLD,
so for orientation we can just use the value returned in
v4l2_fwnode_device_properties defaulting to front when
it is not set.
Otherwise I agree with what has been discussed in this
thread (for this patch) so far.
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static
2025-06-05 17:53 ` [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static Ricardo Ribalda
2025-06-29 17:43 ` Laurent Pinchart
@ 2025-07-14 13:31 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 13:31 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:53, Ricardo Ribalda wrote:
> The function is useful for other compilation units.
>
> This is just a refactor patch, no new functionality is added.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, patch looks good to me:
Reviewed-by: Hans de Goede <hansg@kernel.org>
Regards,
Hans
> ---
> drivers/media/usb/uvc/uvc_driver.c | 4 ++--
> drivers/media/usb/uvc/uvcvideo.h | 2 ++
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index da24a655ab68cc0957762f2b67387677c22224d1..bcc97f71fa1703aea1119469fb32659c17d9409a 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -792,8 +792,8 @@ static const u8 uvc_media_transport_input_guid[16] =
> UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
> static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
>
> -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
> - unsigned int num_pads, unsigned int extra_size)
> +struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
> + unsigned int extra_size)
> {
> struct uvc_entity *entity;
> unsigned int num_inputs;
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index b9f8eb62ba1d82ea7788cf6c10cc838a429dbc9e..dc23d8a97340dc4615d4182232d395106e6d9ed5 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -684,6 +684,8 @@ do { \
> */
>
> struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
> +struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads,
> + unsigned int extra_size);
>
> /* Video buffers queue management. */
> int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse
2025-07-14 13:03 ` Hans de Goede
@ 2025-07-14 14:14 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-14 14:14 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Mauro Carvalho Chehab, Hans Verkuil,
Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, 14 Jul 2025 at 15:03, Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 5-Jun-25 19:52, Ricardo Ribalda wrote:
> > Currently v4l2_fwnode_device_parse() obtains the orientation and
> > rotation via fwnode properties.
> >
> > Extend the function to support as well ACPI devices with _PLD info.
> >
> > We give a higher priority to fwnode, because it might contain quirks
> > injected via swnodes.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > ---
> > drivers/media/v4l2-core/v4l2-fwnode.c | 85 ++++++++++++++++++++++++++++++++---
> > 1 file changed, 79 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> > index cb153ce42c45d69600a3ec4e59a5584d7e791a2a..379290ab3cfde74c8f663d61837a9a95011b5ae0 100644
> > --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> > +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> > @@ -15,6 +15,7 @@
> > * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > */
> > #include <linux/acpi.h>
> > +#include <acpi/acpi_bus.h>
> > #include <linux/kernel.h>
> > #include <linux/mm.h>
> > #include <linux/module.h>
> > @@ -807,16 +808,65 @@ int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
> > }
> > EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
> >
> > -int v4l2_fwnode_device_parse(struct device *dev,
> > - struct v4l2_fwnode_device_properties *props)
> > +static int v4l2_fwnode_device_parse_acpi(struct device *dev,
> > + struct v4l2_fwnode_device_properties *props)
> > +{
> > + struct acpi_pld_info *pld;
> > + int ret = 0;
> > +
> > + if (!is_acpi_device_node(dev_fwnode(dev)))
> > + return 0;
> > +
> > + if (!acpi_get_physical_device_location(ACPI_HANDLE(dev), &pld)) {
> > + dev_dbg(dev, "acpi _PLD call failed\n");
> > + return 0;
> > + }
> > +
> > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
>
> "!=" should be "==" here. So that we set it when not set already,
> rather then leaving it unset when not set already.
>
> > + switch (pld->panel) {
> > + case ACPI_PLD_PANEL_FRONT:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_FRONT;
> > + break;
> > + case ACPI_PLD_PANEL_BACK:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_BACK;
> > + break;
> > + case ACPI_PLD_PANEL_TOP:
> > + case ACPI_PLD_PANEL_LEFT:
> > + case ACPI_PLD_PANEL_RIGHT:
> > + case ACPI_PLD_PANEL_UNKNOWN:
> > + props->orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL;
> > + break;
> > + default:
> > + dev_dbg(dev, "Unknown _PLD panel val %d\n", pld->panel);
> > + ret = -EINVAL;
> > + goto done;
> > + }
> > + }
> > +
> > + if (props->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
>
> Same here.
>
>
> > + switch (pld->rotation) {
> > + case 0 ... 7:
> > + props->rotation = pld->rotation * 45;
> > + break;
> > + default:
> > + dev_dbg(dev, "Unknown _PLD rotation val %d\n", pld->panel);
> > + ret = -EINVAL;
> > + goto done;
> > + }
> > + }
> > +
> > +done:
> > + ACPI_FREE(pld);
> > + return ret;
> > +}
> > +
> > +static int v4l2_fwnode_device_parse_dt(struct device *dev,
> > + struct v4l2_fwnode_device_properties *props)
> > {
> > struct fwnode_handle *fwnode = dev_fwnode(dev);
> > u32 val;
> > int ret;
> >
> > - memset(props, 0, sizeof(*props));
> > -
> > - props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > ret = fwnode_property_read_u32(fwnode, "orientation", &val);
> > if (!ret) {
> > switch (val) {
> > @@ -833,7 +883,6 @@ int v4l2_fwnode_device_parse(struct device *dev,
> > dev_dbg(dev, "device orientation: %u\n", val);
> > }
> >
> > - props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > ret = fwnode_property_read_u32(fwnode, "rotation", &val);
> > if (!ret) {
> > if (val >= 360) {
> > @@ -847,6 +896,30 @@ int v4l2_fwnode_device_parse(struct device *dev,
> >
> > return 0;
> > }
> > +
> > +int v4l2_fwnode_device_parse(struct device *dev,
> > + struct v4l2_fwnode_device_properties *props)
> > +{
> > + int ret;
> > +
> > + memset(props, 0, sizeof(*props));
> > +
> > + props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
> > + props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
> > +
> > + /* Start by looking into swnodes and dt. */
> > + ret = v4l2_fwnode_device_parse_dt(dev, props);
> > + if (ret)
> > + return ret;
> > +
> > + /* Orientation and rotation found!, we are ready. */
> > + if (props->orientation != V4L2_FWNODE_PROPERTY_UNSET &&
> > + props->rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > + return 0;
>
> As Sakari set, this can be dropped, with the 2 checks above
> fixed to be == v4l2_fwnode_device_parse_acpi() will become
> a no-op in this case.
I wanted to avoid calling he _PLD method if it was not necessary.
But if both Sakari and you dislike the optimization then let's get rid of it :)
Thanks
>
> With these things fixed:
>
> Reviewed-by: Hans de Goede <hansg@kernel.org>
>
> Regards,
>
> Hans
>
>
> > +
> > + /* Let's check the acpi table. */
> > + return v4l2_fwnode_device_parse_acpi(dev, props);
> > +}
> > EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
> >
> > /*
> >
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-07-01 9:22 ` Ricardo Ribalda
@ 2025-07-14 14:15 ` Hans de Goede
2025-07-14 14:23 ` Laurent Pinchart
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 14:15 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart
Cc: Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi,
On 1-Jul-25 11:22, Ricardo Ribalda wrote:
> On Sun, 29 Jun 2025 at 19:51, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
>>
>> Hi Ricardo,
>>
>> On Thu, Jun 05, 2025 at 05:53:01PM +0000, Ricardo Ribalda wrote:
>>> Fetch the orientation from the fwnode and map it into a control.
>>>
>>> The uvc driver does not use the media controller, so we need to create a
>>> virtual entity, like we previously did with the external gpio.
>>>
>>> We do not re-purpose the external gpio entity because its is planned to
>>> remove it.
>>
>> Comparing the GUIDs for the EXT_GPIO_CONTROLLER and SWENTITY, we have
>>
>> #define UVC_GUID_EXT_GPIO_CONTROLLER \
>> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
>> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
>> #define UVC_GUID_SWENTITY \
>> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
>> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
>>
>> The GUIDs don't carry any special meaning in their values. I agree with
>> the plan to drop the existing features of the GPIO entity, but wouldn't
>> it be easier to rename UVC_GUID_EXT_GPIO_CONTROLLER to UVC_GUID_SWENTITY
>> and UVC_EXT_GPIO_UNIT* to UVC_SWENTITY_UNIT* (the macros are not exposed
>> to userspace), and later drop the existing GPIO controls from the entity
>
> It would make my life easier if we keep the naming as is, the final
> result will be identical.
I've no strong preference either way.
> Maybe you want to take a look into
> https://patchwork.linuxtv.org/project/linux-media/list/?series=14066 ?
I can take a look at this next week, I thought this was a bit lower prio
now that we have the granular power-saving stuff, but I agree it would be
good to get this moving forward now that most of the backlog is cleared.
> Will it help if I rebase it to the current media-committers/next. It
> has been hanging around since november.
Yes a new rebased version would help, then I'll try to review that
next week.
Regards,
Hans
>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>>> ---
>>> drivers/media/usb/uvc/Makefile | 3 +-
>>> drivers/media/usb/uvc/uvc_ctrl.c | 21 +++++++++++
>>> drivers/media/usb/uvc/uvc_driver.c | 14 +++++--
>>> drivers/media/usb/uvc/uvc_entity.c | 1 +
>>> drivers/media/usb/uvc/uvc_swentity.c | 73 ++++++++++++++++++++++++++++++++++++
>>> drivers/media/usb/uvc/uvcvideo.h | 14 +++++++
>>> include/linux/usb/uvc.h | 3 ++
>>> 7 files changed, 125 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile
>>> index 4f9eee4f81ab6436a8b90324a688a149b2c3bcd1..b4398177c4bb0a9bd49dfd4ca7f2e933b4a1d7df 100644
>>> --- a/drivers/media/usb/uvc/Makefile
>>> +++ b/drivers/media/usb/uvc/Makefile
>>> @@ -1,6 +1,7 @@
>>> # SPDX-License-Identifier: GPL-2.0
>>> uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
>>> - uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o
>>> + uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o \
>>> + uvc_swentity.o
>>> ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
>>> uvcvideo-objs += uvc_entity.o
>>> endif
>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>>> index 47e8ccc39234d1769384b55539a21df07f3d57c7..b2768080c08aafa85acb9b7f318672c043d84e55 100644
>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>>> @@ -376,6 +376,13 @@ static const struct uvc_control_info uvc_ctrls[] = {
>>> | UVC_CTRL_FLAG_GET_DEF
>>> | UVC_CTRL_FLAG_AUTO_UPDATE,
>>> },
>>> + {
>>> + .entity = UVC_GUID_SWENTITY,
>>> + .selector = 0,
>>> + .index = 0,
>>> + .size = 1,
>>> + .flags = UVC_CTRL_FLAG_GET_CUR,
>>> + },
>>> };
>>>
>>> static const u32 uvc_control_classes[] = {
>>> @@ -975,6 +982,17 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
>>> .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
>>> .name = "Region of Interest Auto Ctrls",
>>> },
>>> + {
>>> + .id = V4L2_CID_CAMERA_ORIENTATION,
>>> + .entity = UVC_GUID_SWENTITY,
>>> + .selector = 0,
>>> + .size = 8,
>>> + .offset = 0,
>>> + .v4l2_type = V4L2_CTRL_TYPE_MENU,
>>> + .data_type = UVC_CTRL_DATA_TYPE_ENUM,
>>> + .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
>>> + V4L2_CAMERA_ORIENTATION_FRONT),
>>> + },
>>> };
>>>
>>> /* ------------------------------------------------------------------------
>>> @@ -3210,6 +3228,9 @@ static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
>>> } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
>>> bmControls = entity->gpio.bmControls;
>>> bControlSize = entity->gpio.bControlSize;
>>> + } else if (UVC_ENTITY_TYPE(entity) == UVC_SWENTITY_UNIT) {
>>> + bmControls = entity->swentity.bmControls;
>>> + bControlSize = entity->swentity.bControlSize;
>>> }
>>>
>>> /* Remove bogus/blacklisted controls */
>>> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
>>> index bcc97f71fa1703aea1119469fb32659c17d9409a..96eeb3aee546487d15f3c30dfe1775189ddf7e47 100644
>>> --- a/drivers/media/usb/uvc/uvc_driver.c
>>> +++ b/drivers/media/usb/uvc/uvc_driver.c
>>> @@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
>>> return -1;
>>> }
>>>
>>> - /* Add GPIO entity to the first chain. */
>>> - if (dev->gpio_unit) {
>>> + /* Add virtual entities to the first chain. */
>>> + if (dev->gpio_unit || dev->swentity_unit) {
>>> chain = list_first_entry(&dev->chains,
>>> struct uvc_video_chain, list);
>>> - list_add_tail(&dev->gpio_unit->chain, &chain->entities);
>>> + if (dev->gpio_unit)
>>> + list_add_tail(&dev->gpio_unit->chain, &chain->entities);
>>> + if (dev->swentity_unit)
>>> + list_add_tail(&dev->swentity_unit->chain,
>>> + &chain->entities);
>>> }
>>>
>>> return 0;
>>> @@ -2249,6 +2253,10 @@ static int uvc_probe(struct usb_interface *intf,
>>> if (ret < 0)
>>> goto error;
>>>
>>> + ret = uvc_swentity_init(dev);
>>> + if (ret < 0)
>>> + goto error;
>>> +
>>> dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
>>> dev->uvc_version >> 8, dev->uvc_version & 0xff,
>>> udev->product ? udev->product : "<unnamed>",
>>> diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
>>> index cc68dd24eb42dce5b2846ca52a8dfa499c8aed96..d1a652ef35ec34801bd39a5124b834edf838a79e 100644
>>> --- a/drivers/media/usb/uvc/uvc_entity.c
>>> +++ b/drivers/media/usb/uvc/uvc_entity.c
>>> @@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
>>> case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
>>> case UVC_EXTERNAL_VENDOR_SPECIFIC:
>>> case UVC_EXT_GPIO_UNIT:
>>> + case UVC_SWENTITY_UNIT:
>>> default:
>>> function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
>>> break;
>>> diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
>>> new file mode 100644
>>> index 0000000000000000000000000000000000000000..702a2c26e029a0655dade177ed2a9b88d7a4136d
>>> --- /dev/null
>>> +++ b/drivers/media/usb/uvc/uvc_swentity.c
>>> @@ -0,0 +1,73 @@
>>> +// SPDX-License-Identifier: GPL-2.0-or-later
>>> +/*
>>> + * uvc_swentity.c -- USB Video Class driver
>>> + *
>>> + * Copyright 2025 Google LLC
>>> + */
>>> +
>>> +#include <linux/kernel.h>
>>> +#include <linux/usb/uvc.h>
>>> +#include <media/v4l2-fwnode.h>
>>> +#include "uvcvideo.h"
>>
>> Blank lines between header groups would be nice.
> ack
>>
>>> +
>>> +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
>>> + u8 cs, void *data, u16 size)
>>> +{
>>> + if (size < 1)
>>> + return -EINVAL;
>>> +
>>> + switch (entity->swentity.props.orientation) {
>>> + case V4L2_FWNODE_ORIENTATION_FRONT:
>>> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_FRONT;
>>> + break;
>>> + case V4L2_FWNODE_ORIENTATION_BACK:
>>> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_BACK;
>>> + break;
>>> + default:
>>> + *(u8 *)data = V4L2_CAMERA_ORIENTATION_EXTERNAL;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int uvc_swentity_get_info(struct uvc_device *dev,
>>> + struct uvc_entity *entity, u8 cs, u8 *caps)
>>> +{
>>> + *caps = UVC_CONTROL_CAP_GET;
>>> + return 0;
>>> +}
>>> +
>>> +int uvc_swentity_init(struct uvc_device *dev)
>>> +{
>>> + static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
>>> + struct v4l2_fwnode_device_properties props;
>>> + struct uvc_entity *unit;
>>> + int ret;
>>> +
>>> + ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
>>> + if (ret)
>>> + return dev_err_probe(&dev->intf->dev, ret,
>>> + "Can't parse fwnode\n");
>>> +
>>> + if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
>>> + return 0;
>>> +
>>> + unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
>>> + if (!unit)
>>> + return -ENOMEM;
>>> +
>>> + memcpy(unit->guid, uvc_swentity_guid, sizeof(unit->guid));
>>> + unit->swentity.props = props;
>>> + unit->swentity.bControlSize = 1;
>>> + unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
>>> + unit->swentity.bmControls[0] = 1;
>>> + unit->get_cur = uvc_swentity_get_cur;
>>> + unit->get_info = uvc_swentity_get_info;
>>> + strscpy(unit->name, "SWENTITY", sizeof(unit->name));
>>> +
>>> + list_add_tail(&unit->list, &dev->entities);
>>> +
>>> + dev->swentity_unit = unit;
>>> +
>>> + return 0;
>>> +}
>>> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
>>> index dc23d8a97340dc4615d4182232d395106e6d9ed5..a931750bdea25b9062dcc7644bf5f2ed89c1cb4c 100644
>>> --- a/drivers/media/usb/uvc/uvcvideo.h
>>> +++ b/drivers/media/usb/uvc/uvcvideo.h
>>> @@ -19,6 +19,7 @@
>>> #include <media/v4l2-event.h>
>>> #include <media/v4l2-fh.h>
>>> #include <media/videobuf2-v4l2.h>
>>> +#include <media/v4l2-fwnode.h>
>>
>> Alphabetical order.
>>
>>>
>>> /* --------------------------------------------------------------------------
>>> * UVC constants
>>> @@ -41,6 +42,9 @@
>>> #define UVC_EXT_GPIO_UNIT 0x7ffe
>>> #define UVC_EXT_GPIO_UNIT_ID 0x100
>>>
>>> +#define UVC_SWENTITY_UNIT 0x7ffd
>>> +#define UVC_SWENTITY_UNIT_ID 0x101
>>> +
>>> /* ------------------------------------------------------------------------
>>> * Driver specific constants.
>>> */
>>> @@ -242,6 +246,12 @@ struct uvc_entity {
>>> int irq;
>>> bool initialized;
>>> } gpio;
>>> +
>>> + struct {
>>> + u8 bControlSize;
>>> + u8 *bmControls;
>>> + struct v4l2_fwnode_device_properties props;
>>> + } swentity;
>>> };
>>>
>>> u8 bNrInPins;
>>> @@ -617,6 +627,7 @@ struct uvc_device {
>>> } async_ctrl;
>>>
>>> struct uvc_entity *gpio_unit;
>>> + struct uvc_entity *swentity_unit;
>>> };
>>>
>>> enum uvc_handle_state {
>>> @@ -836,4 +847,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
>>> size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
>>> size_t size);
>>>
>>> +/* swentity */
>>> +int uvc_swentity_init(struct uvc_device *dev);
>>> +
>>> #endif
>>> diff --git a/include/linux/usb/uvc.h b/include/linux/usb/uvc.h
>>> index bce95153e5a65613a710d7316fc17cf5462b5bce..88a23e8919d1294da4308e0e3ca0eccdc66a318f 100644
>>> --- a/include/linux/usb/uvc.h
>>> +++ b/include/linux/usb/uvc.h
>>> @@ -29,6 +29,9 @@
>>> #define UVC_GUID_EXT_GPIO_CONTROLLER \
>>> {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
>>> 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
>>> +#define UVC_GUID_SWENTITY \
>>> + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
>>> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
>>>
>>> #define UVC_GUID_FORMAT_MJPEG \
>>> { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
>
>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-07-01 9:22 ` Ricardo Ribalda
2025-07-14 14:15 ` Hans de Goede
@ 2025-07-14 14:23 ` Laurent Pinchart
1 sibling, 0 replies; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-14 14:23 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, Jul 01, 2025 at 11:22:10AM +0200, Ricardo Ribalda wrote:
> On Sun, 29 Jun 2025 at 19:51, Laurent Pinchart wrote:
> > On Thu, Jun 05, 2025 at 05:53:01PM +0000, Ricardo Ribalda wrote:
> > > Fetch the orientation from the fwnode and map it into a control.
> > >
> > > The uvc driver does not use the media controller, so we need to create a
> > > virtual entity, like we previously did with the external gpio.
> > >
> > > We do not re-purpose the external gpio entity because its is planned to
> > > remove it.
> >
> > Comparing the GUIDs for the EXT_GPIO_CONTROLLER and SWENTITY, we have
> >
> > #define UVC_GUID_EXT_GPIO_CONTROLLER \
> > {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
> > #define UVC_GUID_SWENTITY \
> > {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
> >
> > The GUIDs don't carry any special meaning in their values. I agree with
> > the plan to drop the existing features of the GPIO entity, but wouldn't
> > it be easier to rename UVC_GUID_EXT_GPIO_CONTROLLER to UVC_GUID_SWENTITY
> > and UVC_EXT_GPIO_UNIT* to UVC_SWENTITY_UNIT* (the macros are not exposed
> > to userspace), and later drop the existing GPIO controls from the entity
>
> It would make my life easier if we keep the naming as is, the final
> result will be identical.
>
> Maybe you want to take a look into
> https://patchwork.linuxtv.org/project/linux-media/list/?series=14066 ?
It seems the series doesn't drop UVC_GUID_EXT_GPIO_CONTROLLER, is that
an oversight ?
> Will it help if I rebase it to the current media-committers/next. It
> has been hanging around since november.
If there are conflicts it could help. There were multiple patch series
conflicting with each other, but I don't know if that's the case of that
one.
> > ?
> >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > > drivers/media/usb/uvc/Makefile | 3 +-
> > > drivers/media/usb/uvc/uvc_ctrl.c | 21 +++++++++++
> > > drivers/media/usb/uvc/uvc_driver.c | 14 +++++--
> > > drivers/media/usb/uvc/uvc_entity.c | 1 +
> > > drivers/media/usb/uvc/uvc_swentity.c | 73 ++++++++++++++++++++++++++++++++++++
> > > drivers/media/usb/uvc/uvcvideo.h | 14 +++++++
> > > include/linux/usb/uvc.h | 3 ++
> > > 7 files changed, 125 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/uvc/Makefile b/drivers/media/usb/uvc/Makefile
> > > index 4f9eee4f81ab6436a8b90324a688a149b2c3bcd1..b4398177c4bb0a9bd49dfd4ca7f2e933b4a1d7df 100644
> > > --- a/drivers/media/usb/uvc/Makefile
> > > +++ b/drivers/media/usb/uvc/Makefile
> > > @@ -1,6 +1,7 @@
> > > # SPDX-License-Identifier: GPL-2.0
> > > uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
> > > - uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o
> > > + uvc_status.o uvc_isight.o uvc_debugfs.o uvc_metadata.o \
> > > + uvc_swentity.o
> > > ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
> > > uvcvideo-objs += uvc_entity.o
> > > endif
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index 47e8ccc39234d1769384b55539a21df07f3d57c7..b2768080c08aafa85acb9b7f318672c043d84e55 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -376,6 +376,13 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > > | UVC_CTRL_FLAG_GET_DEF
> > > | UVC_CTRL_FLAG_AUTO_UPDATE,
> > > },
> > > + {
> > > + .entity = UVC_GUID_SWENTITY,
> > > + .selector = 0,
> > > + .index = 0,
> > > + .size = 1,
> > > + .flags = UVC_CTRL_FLAG_GET_CUR,
> > > + },
> > > };
> > >
> > > static const u32 uvc_control_classes[] = {
> > > @@ -975,6 +982,17 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
> > > .name = "Region of Interest Auto Ctrls",
> > > },
> > > + {
> > > + .id = V4L2_CID_CAMERA_ORIENTATION,
> > > + .entity = UVC_GUID_SWENTITY,
> > > + .selector = 0,
> > > + .size = 8,
> > > + .offset = 0,
> > > + .v4l2_type = V4L2_CTRL_TYPE_MENU,
> > > + .data_type = UVC_CTRL_DATA_TYPE_ENUM,
> > > + .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> > > + V4L2_CAMERA_ORIENTATION_FRONT),
> > > + },
> > > };
> > >
> > > /* ------------------------------------------------------------------------
> > > @@ -3210,6 +3228,9 @@ static int uvc_ctrl_init_chain(struct uvc_video_chain *chain)
> > > } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) {
> > > bmControls = entity->gpio.bmControls;
> > > bControlSize = entity->gpio.bControlSize;
> > > + } else if (UVC_ENTITY_TYPE(entity) == UVC_SWENTITY_UNIT) {
> > > + bmControls = entity->swentity.bmControls;
> > > + bControlSize = entity->swentity.bControlSize;
> > > }
> > >
> > > /* Remove bogus/blacklisted controls */
> > > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> > > index bcc97f71fa1703aea1119469fb32659c17d9409a..96eeb3aee546487d15f3c30dfe1775189ddf7e47 100644
> > > --- a/drivers/media/usb/uvc/uvc_driver.c
> > > +++ b/drivers/media/usb/uvc/uvc_driver.c
> > > @@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
> > > return -1;
> > > }
> > >
> > > - /* Add GPIO entity to the first chain. */
> > > - if (dev->gpio_unit) {
> > > + /* Add virtual entities to the first chain. */
> > > + if (dev->gpio_unit || dev->swentity_unit) {
> > > chain = list_first_entry(&dev->chains,
> > > struct uvc_video_chain, list);
> > > - list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> > > + if (dev->gpio_unit)
> > > + list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> > > + if (dev->swentity_unit)
> > > + list_add_tail(&dev->swentity_unit->chain,
> > > + &chain->entities);
> > > }
> > >
> > > return 0;
> > > @@ -2249,6 +2253,10 @@ static int uvc_probe(struct usb_interface *intf,
> > > if (ret < 0)
> > > goto error;
> > >
> > > + ret = uvc_swentity_init(dev);
> > > + if (ret < 0)
> > > + goto error;
> > > +
> > > dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
> > > dev->uvc_version >> 8, dev->uvc_version & 0xff,
> > > udev->product ? udev->product : "<unnamed>",
> > > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > > index cc68dd24eb42dce5b2846ca52a8dfa499c8aed96..d1a652ef35ec34801bd39a5124b834edf838a79e 100644
> > > --- a/drivers/media/usb/uvc/uvc_entity.c
> > > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > > @@ -106,6 +106,7 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > > case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
> > > case UVC_EXTERNAL_VENDOR_SPECIFIC:
> > > case UVC_EXT_GPIO_UNIT:
> > > + case UVC_SWENTITY_UNIT:
> > > default:
> > > function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
> > > break;
> > > diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> > > new file mode 100644
> > > index 0000000000000000000000000000000000000000..702a2c26e029a0655dade177ed2a9b88d7a4136d
> > > --- /dev/null
> > > +++ b/drivers/media/usb/uvc/uvc_swentity.c
> > > @@ -0,0 +1,73 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + * uvc_swentity.c -- USB Video Class driver
> > > + *
> > > + * Copyright 2025 Google LLC
> > > + */
> > > +
> > > +#include <linux/kernel.h>
> > > +#include <linux/usb/uvc.h>
> > > +#include <media/v4l2-fwnode.h>
> > > +#include "uvcvideo.h"
> >
> > Blank lines between header groups would be nice.
> ack
> >
> > > +
> > > +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size)
> > > +{
> > > + if (size < 1)
> > > + return -EINVAL;
> > > +
> > > + switch (entity->swentity.props.orientation) {
> > > + case V4L2_FWNODE_ORIENTATION_FRONT:
> > > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_FRONT;
> > > + break;
> > > + case V4L2_FWNODE_ORIENTATION_BACK:
> > > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_BACK;
> > > + break;
> > > + default:
> > > + *(u8 *)data = V4L2_CAMERA_ORIENTATION_EXTERNAL;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int uvc_swentity_get_info(struct uvc_device *dev,
> > > + struct uvc_entity *entity, u8 cs, u8 *caps)
> > > +{
> > > + *caps = UVC_CONTROL_CAP_GET;
> > > + return 0;
> > > +}
> > > +
> > > +int uvc_swentity_init(struct uvc_device *dev)
> > > +{
> > > + static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> > > + struct v4l2_fwnode_device_properties props;
> > > + struct uvc_entity *unit;
> > > + int ret;
> > > +
> > > + ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> > > + if (ret)
> > > + return dev_err_probe(&dev->intf->dev, ret,
> > > + "Can't parse fwnode\n");
> > > +
> > > + if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> > > + return 0;
> > > +
> > > + unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> > > + if (!unit)
> > > + return -ENOMEM;
> > > +
> > > + memcpy(unit->guid, uvc_swentity_guid, sizeof(unit->guid));
> > > + unit->swentity.props = props;
> > > + unit->swentity.bControlSize = 1;
> > > + unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> > > + unit->swentity.bmControls[0] = 1;
> > > + unit->get_cur = uvc_swentity_get_cur;
> > > + unit->get_info = uvc_swentity_get_info;
> > > + strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> > > +
> > > + list_add_tail(&unit->list, &dev->entities);
> > > +
> > > + dev->swentity_unit = unit;
> > > +
> > > + return 0;
> > > +}
> > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > index dc23d8a97340dc4615d4182232d395106e6d9ed5..a931750bdea25b9062dcc7644bf5f2ed89c1cb4c 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -19,6 +19,7 @@
> > > #include <media/v4l2-event.h>
> > > #include <media/v4l2-fh.h>
> > > #include <media/videobuf2-v4l2.h>
> > > +#include <media/v4l2-fwnode.h>
> >
> > Alphabetical order.
> >
> > >
> > > /* --------------------------------------------------------------------------
> > > * UVC constants
> > > @@ -41,6 +42,9 @@
> > > #define UVC_EXT_GPIO_UNIT 0x7ffe
> > > #define UVC_EXT_GPIO_UNIT_ID 0x100
> > >
> > > +#define UVC_SWENTITY_UNIT 0x7ffd
> > > +#define UVC_SWENTITY_UNIT_ID 0x101
> > > +
> > > /* ------------------------------------------------------------------------
> > > * Driver specific constants.
> > > */
> > > @@ -242,6 +246,12 @@ struct uvc_entity {
> > > int irq;
> > > bool initialized;
> > > } gpio;
> > > +
> > > + struct {
> > > + u8 bControlSize;
> > > + u8 *bmControls;
> > > + struct v4l2_fwnode_device_properties props;
> > > + } swentity;
> > > };
> > >
> > > u8 bNrInPins;
> > > @@ -617,6 +627,7 @@ struct uvc_device {
> > > } async_ctrl;
> > >
> > > struct uvc_entity *gpio_unit;
> > > + struct uvc_entity *swentity_unit;
> > > };
> > >
> > > enum uvc_handle_state {
> > > @@ -836,4 +847,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
> > > size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
> > > size_t size);
> > >
> > > +/* swentity */
> > > +int uvc_swentity_init(struct uvc_device *dev);
> > > +
> > > #endif
> > > diff --git a/include/linux/usb/uvc.h b/include/linux/usb/uvc.h
> > > index bce95153e5a65613a710d7316fc17cf5462b5bce..88a23e8919d1294da4308e0e3ca0eccdc66a318f 100644
> > > --- a/include/linux/usb/uvc.h
> > > +++ b/include/linux/usb/uvc.h
> > > @@ -29,6 +29,9 @@
> > > #define UVC_GUID_EXT_GPIO_CONTROLLER \
> > > {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
> > > +#define UVC_GUID_SWENTITY \
> > > + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
> > > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04}
> > >
> > > #define UVC_GUID_FORMAT_MJPEG \
> > > { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper
2025-06-05 17:53 ` [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper Ricardo Ribalda
2025-06-29 18:01 ` Laurent Pinchart
@ 2025-07-14 14:24 ` Hans de Goede
2025-07-14 15:51 ` Ricardo Ribalda
1 sibling, 1 reply; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 14:24 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Hans de Goede,
Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi Ricardo,
On 5-Jun-25 19:53, Ricardo Ribalda wrote:
> Create a helper function to query a control. The new function reduces
> the number of arguments, calculates the length of the operation and
> redirects the operation to the hardware or to the entity private
> functions.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Thanks, this looks like a nice cleanup.
> ---
> drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++--------------------
> 1 file changed, 41 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index b2768080c08aafa85acb9b7f318672c043d84e55..21ec7b978bc7aca21db7cb8fd5d135d876f3330c 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -576,6 +576,34 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
> V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
> };
>
> +static int uvc_ctrl_query_entity(struct uvc_device *dev,
> + const struct uvc_control *ctrl, u8 query,
> + void *data)
> +{
> + u16 len;
> +
> + switch (query) {
> + case UVC_GET_INFO:
> + len = 1;
> + break;
> + case UVC_GET_LEN:
> + len = 2;
> + break;
> + default:
> + len = ctrl->info.size;
> + }
> +
> + if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> + return ctrl->entity->get_cur(dev, ctrl->entity,
> + ctrl->info.selector, data, len);
> + if (query == UVC_GET_INFO && ctrl->entity->get_info)
> + return ctrl->entity->get_info(dev, ctrl->entity,
> + ctrl->info.selector, data);
> +
> + return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
> + ctrl->info.selector, data, len);
Maybe:
if (query == UVC_GET_CUR && ctrl->entity->get_cur)
return ctrl->entity->get_cur(dev, ctrl->entity,
ctrl->info.selector, data, len);
else if (query == UVC_GET_INFO && ctrl->entity->get_info)
return ctrl->entity->get_info(dev, ctrl->entity,
ctrl->info.selector, data);
else
return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
ctrl->info.selector, data, len);
?
That + Laurent's well observed remark about info->selector vs
ctrl->info.selector which I would probably have missed...
About Laurent's remark about one case of this pre-existing,
please fix this in a separate patch (I guess you would have done so
anyways, but just to be sure).
Regards,
Hans
> +}
> +
> static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> struct uvc_video_chain *chain, struct uvc_control *ctrl)
> {
> @@ -1222,35 +1250,27 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
> int ret;
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_DEF,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> if (ret < 0)
> return ret;
> }
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> if (ret < 0)
> return ret;
> }
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> if (ret < 0)
> return ret;
> }
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
> - chain->dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
> - ctrl->info.size);
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> if (ret < 0) {
> if (UVC_ENTITY_TYPE(ctrl->entity) !=
> UVC_VC_EXTENSION_UNIT)
> @@ -1291,16 +1311,7 @@ static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
> return 0;
> }
>
> - if (ctrl->entity->get_cur)
> - ret = ctrl->entity->get_cur(chain->dev, ctrl->entity,
> - ctrl->info.selector, data,
> - ctrl->info.size);
> - else
> - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
> - ctrl->entity->id, chain->dev->intfnum,
> - ctrl->info.selector, data,
> - ctrl->info.size);
> -
> + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_CUR, data);
> if (ret < 0)
> return ret;
>
> @@ -2164,11 +2175,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> continue;
>
> if (!rollback)
> - ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
> - dev->intfnum, ctrl->info.selector,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> - ctrl->info.size);
> -
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_SET_CUR,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> if (!ret)
> processed_ctrls++;
>
> @@ -2570,13 +2578,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
> if (data == NULL)
> return -ENOMEM;
>
> - if (ctrl->entity->get_info)
> - ret = ctrl->entity->get_info(dev, ctrl->entity,
> - ctrl->info.selector, data);
> - else
> - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
> - dev->intfnum, info->selector, data, 1);
> -
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_INFO, data);
> if (!ret) {
> info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
> UVC_CTRL_FLAG_SET_CUR |
> @@ -2654,8 +2656,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
> info->selector = ctrl->index + 1;
>
> /* Query and verify the control length (GET_LEN) */
> - ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
> - info->selector, data, 2);
> + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_LEN, data);
> if (ret < 0) {
> uvc_dbg(dev, CONTROL,
> "GET_LEN failed on control %pUl/%u (%d)\n",
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-01 11:13 ` Ricardo Ribalda
@ 2025-07-14 14:28 ` Hans de Goede
2025-07-14 14:29 ` Laurent Pinchart
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 14:28 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo, Laurent,
On 1-Jul-25 13:13, Ricardo Ribalda wrote:
> Hi Laurent
>
> On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
>>
>> Hi Ricardo,
>>
>> Thank you for the patch.
>>
>> On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
>>> Virtual entities need to provide more values than get_cur and get_cur
>>
>> I think you meant "get_info and get_cur".
>>
>>> for their controls. Add support for get_def, get_min, get_max and
>>> get_res.
>>
>> Do they ? The UVC specification defines controls that don't list
>> GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
>> the same for the software controls ? This patch is meant to support the
>> UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
>> patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
>> enough ?
>
> V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> that time requires get_min and get_max.
> We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> fakes min, max and res, but I think that it is cleaner this approach.
If I read this right, then we could at least drop adding get_def and
get_res callbacks from this patch, right?
Can you do that for the next version please?
Regards,
Hans
>>> This is a preparation patch.
>>>
>>> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>>> ---
>>> drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
>>> drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
>>> 2 files changed, 20 insertions(+)
>>>
>>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>>> index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
>>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>>> @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
>>> if (query == UVC_GET_CUR && ctrl->entity->get_cur)
>>> return ctrl->entity->get_cur(dev, ctrl->entity,
>>> ctrl->info.selector, data, len);
>>> + if (query == UVC_GET_DEF && ctrl->entity->get_def)
>>> + return ctrl->entity->get_def(dev, ctrl->entity,
>>> + ctrl->info.selector, data, len);
>>> + if (query == UVC_GET_MIN && ctrl->entity->get_min)
>>> + return ctrl->entity->get_min(dev, ctrl->entity,
>>> + ctrl->info.selector, data, len);
>>> + if (query == UVC_GET_MAX && ctrl->entity->get_max)
>>> + return ctrl->entity->get_max(dev, ctrl->entity,
>>> + ctrl->info.selector, data, len);
>>> + if (query == UVC_GET_RES && ctrl->entity->get_res)
>>> + return ctrl->entity->get_res(dev, ctrl->entity,
>>> + ctrl->info.selector, data, len);
>>> if (query == UVC_GET_INFO && ctrl->entity->get_info)
>>> return ctrl->entity->get_info(dev, ctrl->entity,
>>> ctrl->info.selector, data);
>>> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
>>> index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
>>> --- a/drivers/media/usb/uvc/uvcvideo.h
>>> +++ b/drivers/media/usb/uvc/uvcvideo.h
>>> @@ -261,6 +261,14 @@ struct uvc_entity {
>>> u8 cs, u8 *caps);
>>> int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
>>> u8 cs, void *data, u16 size);
>>> + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
>>> + u8 cs, void *data, u16 size);
>>> + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
>>> + u8 cs, void *data, u16 size);
>>> + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
>>> + u8 cs, void *data, u16 size);
>>> + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
>>> + u8 cs, void *data, u16 size);
>>>
>>> unsigned int ncontrols;
>>> struct uvc_control *controls;
>>
>> --
>> Regards,
>>
>> Laurent Pinchart
>
>
>
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-01 11:13 ` Ricardo Ribalda
2025-07-14 14:28 ` Hans de Goede
@ 2025-07-14 14:29 ` Laurent Pinchart
2025-07-14 15:46 ` Ricardo Ribalda
1 sibling, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-14 14:29 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, Jul 01, 2025 at 01:13:10PM +0200, Ricardo Ribalda wrote:
> On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart wrote:
> > On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > > Virtual entities need to provide more values than get_cur and get_cur
> >
> > I think you meant "get_info and get_cur".
> >
> > > for their controls. Add support for get_def, get_min, get_max and
> > > get_res.
> >
> > Do they ? The UVC specification defines controls that don't list
> > GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> > the same for the software controls ? This patch is meant to support the
> > UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> > patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> > enough ?
>
> V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> that time requires get_min and get_max.
Where does that requirement come from ? Is it because how the
corresponding V4L2 type (V4L2_CTRL_TYPE_INTEGER) is handled in
uvc_ctrl_clamp() ? uvc_ctrl_clamp() is only called when setting a
control, from uvc_ctrl_set(), and V4L2_CID_CAMERA_ROTATION should be
read-only.
> We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> fakes min, max and res, but I think that it is cleaner this approach.
>
> > > This is a preparation patch.
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > > 2 files changed, 20 insertions(+)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > > return ctrl->entity->get_cur(dev, ctrl->entity,
> > > ctrl->info.selector, data, len);
> > > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > > + return ctrl->entity->get_def(dev, ctrl->entity,
> > > + ctrl->info.selector, data, len);
> > > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > > + return ctrl->entity->get_min(dev, ctrl->entity,
> > > + ctrl->info.selector, data, len);
> > > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > > + return ctrl->entity->get_max(dev, ctrl->entity,
> > > + ctrl->info.selector, data, len);
> > > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > > + return ctrl->entity->get_res(dev, ctrl->entity,
> > > + ctrl->info.selector, data, len);
> > > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > > return ctrl->entity->get_info(dev, ctrl->entity,
> > > ctrl->info.selector, data);
> > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -261,6 +261,14 @@ struct uvc_entity {
> > > u8 cs, u8 *caps);
> > > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > > u8 cs, void *data, u16 size);
> > > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size);
> > > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size);
> > > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size);
> > > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size);
> > >
> > > unsigned int ncontrols;
> > > struct uvc_control *controls;
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
2025-07-01 11:26 ` Ricardo Ribalda
@ 2025-07-14 14:31 ` Laurent Pinchart
2025-07-14 15:59 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-14 14:31 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Ricardo,
On Tue, Jul 01, 2025 at 01:26:51PM +0200, Ricardo Ribalda wrote:
> On Sun, 29 Jun 2025 at 20:15, Laurent Pinchart wrote:
> > On Thu, Jun 05, 2025 at 05:53:04PM +0000, Ricardo Ribalda wrote:
> > > Fetch the rotation from the fwnode and map it into a control.
> > >
> > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > ---
> > > drivers/media/usb/uvc/uvc_ctrl.c | 22 +++++++++++++--
> > > drivers/media/usb/uvc/uvc_swentity.c | 55 ++++++++++++++++++++++++++++++++----
> > > drivers/media/usb/uvc/uvcvideo.h | 5 ++++
> > > 3 files changed, 74 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index 59be62ae24a4219fa9d7aacf2ae7382c95362178..5788f0c0f6604da06a7bca1b9999d0957817e75e 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -378,11 +378,18 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > > },
> > > {
> > > .entity = UVC_GUID_SWENTITY,
> > > - .selector = 0,
> > > - .index = 0,
> > > + .selector = UVC_SWENTITY_ORIENTATION,
> > > + .index = UVC_SWENTITY_ORIENTATION,
> > > .size = 1,
> > > .flags = UVC_CTRL_FLAG_GET_CUR,
> > > },
> > > + {
> > > + .entity = UVC_GUID_SWENTITY,
> > > + .selector = UVC_SWENTITY_ROTATION,
> > > + .index = UVC_SWENTITY_ROTATION,
> > > + .size = 2,
> > > + .flags = UVC_CTRL_FLAG_GET_RANGE,
> > > + },
> > > };
> > >
> > > static const u32 uvc_control_classes[] = {
> > > @@ -1025,7 +1032,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > {
> > > .id = V4L2_CID_CAMERA_ORIENTATION,
> > > .entity = UVC_GUID_SWENTITY,
> > > - .selector = 0,
> > > + .selector = UVC_SWENTITY_ORIENTATION,
> > > .size = 8,
> > > .offset = 0,
> > > .v4l2_type = V4L2_CTRL_TYPE_MENU,
> > > @@ -1033,6 +1040,15 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> > > V4L2_CAMERA_ORIENTATION_FRONT),
> > > },
> > > + {
> > > + .id = V4L2_CID_CAMERA_SENSOR_ROTATION,
> > > + .entity = UVC_GUID_SWENTITY,
> > > + .selector = UVC_SWENTITY_ROTATION,
> > > + .size = 16,
> > > + .offset = 0,
> > > + .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
> > > + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
> > > + },
> > > };
> > >
> > > /* ------------------------------------------------------------------------
> > > diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> > > index 702a2c26e029a0655dade177ed2a9b88d7a4136d..60f3166addbeb7d2e431d107b23034d2d11a1812 100644
> > > --- a/drivers/media/usb/uvc/uvc_swentity.c
> > > +++ b/drivers/media/usb/uvc/uvc_swentity.c
> > > @@ -10,10 +10,11 @@
> > > #include <media/v4l2-fwnode.h>
> > > #include "uvcvideo.h"
> > >
> > > -static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > > - u8 cs, void *data, u16 size)
> > > +static int uvc_swentity_get_orientation(struct uvc_device *dev,
> > > + struct uvc_entity *entity, u8 cs,
> > > + void *data, u16 size)
> > > {
> > > - if (size < 1)
> > > + if (cs != UVC_SWENTITY_ORIENTATION || size != 1)
> > > return -EINVAL;
> > >
> > > switch (entity->swentity.props.orientation) {
> > > @@ -30,6 +31,31 @@ static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entit
> > > return 0;
> > > }
> > >
> > > +static int uvc_swentity_get_rotation(struct uvc_device *dev,
> > > + struct uvc_entity *entity, u8 cs, void *data,
> > > + u16 size)
> > > +{
> > > + if (cs != UVC_SWENTITY_ROTATION || size != 2)
> > > + return -EINVAL;
> > > +
> > > + ((u8 *)data)[0] = entity->swentity.props.rotation;
> > > + ((u8 *)data)[1] = entity->swentity.props.rotation >> 8;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *data, u16 size)
> > > +{
> > > + switch (cs) {
> > > + case UVC_SWENTITY_ORIENTATION:
> > > + return uvc_swentity_get_orientation(dev, entity, cs, data, size);
> > > + case UVC_SWENTITY_ROTATION:
> > > + return uvc_swentity_get_rotation(dev, entity, cs, data, size);
> > > + }
> > > + return -EINVAL;
> > > +}
> > > +
> > > static int uvc_swentity_get_info(struct uvc_device *dev,
> > > struct uvc_entity *entity, u8 cs, u8 *caps)
> > > {
> > > @@ -37,11 +63,22 @@ static int uvc_swentity_get_info(struct uvc_device *dev,
> > > return 0;
> > > }
> > >
> > > +static int uvc_swentity_get_res(struct uvc_device *dev, struct uvc_entity *entity,
> > > + u8 cs, void *res, u16 size)
> > > +{
> > > + if (size == 0)
> > > + return -EINVAL;
> >
> > The get_cur functions return an error if the size doesn't match the
> > expected size. I think you can return -EINVAL if size != 1.
> >
> > > + ((u8 *)res)[0] = 1;
> > > + memset(res + 1, 0, size - 1);
> >
> > And drop the memset.
> >
> > > + return 0;
> > > +}
> > > +
> > > int uvc_swentity_init(struct uvc_device *dev)
> > > {
> > > static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> > > struct v4l2_fwnode_device_properties props;
> > > struct uvc_entity *unit;
> > > + u8 controls = 0;
> > > int ret;
> > >
> > > ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> > > @@ -49,7 +86,11 @@ int uvc_swentity_init(struct uvc_device *dev)
> > > return dev_err_probe(&dev->intf->dev, ret,
> > > "Can't parse fwnode\n");
> > >
> > > - if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> > > + if (props.orientation != V4L2_FWNODE_PROPERTY_UNSET)
> > > + controls |= BIT(UVC_SWENTITY_ORIENTATION);
> > > + if (props.rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > > + controls |= BIT(UVC_SWENTITY_ROTATION);
> > > + if (!controls)
> > > return 0;
> > >
> > > unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> > > @@ -60,9 +101,13 @@ int uvc_swentity_init(struct uvc_device *dev)
> > > unit->swentity.props = props;
> > > unit->swentity.bControlSize = 1;
> > > unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> > > - unit->swentity.bmControls[0] = 1;
> > > + unit->swentity.bmControls[0] = controls;
> > > unit->get_cur = uvc_swentity_get_cur;
> > > unit->get_info = uvc_swentity_get_info;
> > > + unit->get_res = uvc_swentity_get_res;
> > > + unit->get_def = uvc_swentity_get_rotation;
> > > + unit->get_min = uvc_swentity_get_rotation;
> > > + unit->get_max = uvc_swentity_get_rotation;
> >
> > Why do you support GET_DEF, GET_MIN and GET_MAX for rotation only ?
>
> Orientation has enum type. It does not require min or max.
>
> For get_def I could use get_cur, but 0 is as good as any other value
> within range.
Both the orientation and rotation are read-only, and should report min
== max == def == cur. What am I missing ?
> > > strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> > >
> > > list_add_tail(&unit->list, &dev->entities);
> > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > index d6da8ed3ad4cf3377df49923e051fe04d83d2e38..7cca0dc75d11f6a13bc4f09676a5a00e80cb38f7 100644
> > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > @@ -45,6 +45,11 @@
> > > #define UVC_SWENTITY_UNIT 0x7ffd
> > > #define UVC_SWENTITY_UNIT_ID 0x101
> > >
> > > +enum {
> > > + UVC_SWENTITY_ORIENTATION,
> > > + UVC_SWENTITY_ROTATION
> > > +};
> > > +
> > > /* ------------------------------------------------------------------------
> > > * Driver specific constants.
> > > */
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-07-08 6:28 ` Ricardo Ribalda
@ 2025-07-14 14:36 ` Laurent Pinchart
2025-07-14 16:04 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-14 14:36 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans Verkuil, Hans de Goede, Mauro Carvalho Chehab, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, Jul 08, 2025 at 08:28:21AM +0200, Ricardo Ribalda wrote:
> On Tue, 1 Jul 2025 at 13:20, Ricardo Ribalda wrote:
> > On Sun, 29 Jun 2025 at 20:06, Laurent Pinchart wrote:
> > > Hi Ricardo,
> > >
> > > Thank you for the patch.
> > >
> > > I would use "software entities" and not "virtual entities" in the
> > > subject line and everywhere else, as those entities are not virtual.
> > >
> > > On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> > > > Neither the GPIO nor the SWENTITY entities form part of the device
> > > > pipeline. We just create them to hold emulated uvc controls.
> > > >
> > > > When the device initializes, a warning is thrown by the v4l2 core:
> > > > uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
> > > >
> > > > There are no entity function that matches what we are doing here, and
> > > > it does not make to much sense to create a function for entities that
> > > > do not really exist.
> > >
> > > I don't agree with this. The purpose of reporting entities to userspace
> > > through the MC API is to let application enumerate what entities a
> > > device contains. Being able to enumerate software entities seems as
> > > useful as being able to enumerate hardware entities.
> >
> > What function shall we use in this case? Nothing here seems to match a
> > software entity
> > https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-types.html
> >
> > Any suggestion for name?
> > Shall we just live with the warning in dmesg?
>
> I just realised that if/when we move to the control framework, the
> software entity will be gone.... So to avoid introducing a uAPI change
> that will be reverted later I think that we should keep this patch.
You know my opinion about moving to the control framework, so that's not
a very compelling argument :-)
We could use MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, as that's the
function already used by XUs, and the SWENTITY fulfills the same role as
XUs in some devices.
> > > > Do not create MC entities for them and pretend nothing happened here.
> > > >
> > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > ---
> > > > drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> > > > 1 file changed, 10 insertions(+)
> > > >
> > > > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > > > index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> > > > --- a/drivers/media/usb/uvc/uvc_entity.c
> > > > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > > > @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > > > {
> > > > int ret;
> > > >
> > > > + /*
> > > > + * Do not initialize virtual entities, they do not really exist
> > > > + * and are not connected to any other entities.
> > > > + */
> > > > + switch (UVC_ENTITY_TYPE(entity)) {
> > > > + case UVC_EXT_GPIO_UNIT:
> > > > + case UVC_SWENTITY_UNIT:
> > > > + return 0;
> > > > + }
> > > > +
> > > > if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> > > > u32 function;
> > > >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION
2025-06-05 17:53 ` [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION Ricardo Ribalda
2025-06-29 17:50 ` Laurent Pinchart
@ 2025-07-14 14:36 ` Hans de Goede
1 sibling, 0 replies; 62+ messages in thread
From: Hans de Goede @ 2025-07-14 14:36 UTC (permalink / raw)
To: Ricardo Ribalda, Laurent Pinchart, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown
Cc: linux-media, linux-kernel, linux-usb, devicetree, linux-gpio,
linux-acpi
Hi,
On 5-Jun-25 19:53, Ricardo Ribalda wrote:
> Fetch the orientation from the fwnode and map it into a control.
>
> The uvc driver does not use the media controller, so we need to create a
> virtual entity, like we previously did with the external gpio.
>
> We do not re-purpose the external gpio entity because its is planned to
> remove it.
>
> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
...
Taking a second look at this I noticed the following:
> @@ -1869,11 +1869,15 @@ static int uvc_scan_device(struct uvc_device *dev)
> return -1;
> }
>
> - /* Add GPIO entity to the first chain. */
> - if (dev->gpio_unit) {
> + /* Add virtual entities to the first chain. */
> + if (dev->gpio_unit || dev->swentity_unit) {
> chain = list_first_entry(&dev->chains,
> struct uvc_video_chain, list);
> - list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> + if (dev->gpio_unit)
> + list_add_tail(&dev->gpio_unit->chain, &chain->entities);
> + if (dev->swentity_unit)
> + list_add_tail(&dev->swentity_unit->chain,
> + &chain->entities);
> }
>
> return 0;
The double checking of if (dev->gpio_unit) / if (dev->swentity_unit) looks
unnecessary here list_first_entry() is pretty cheap and this only runs
once at probe() time. So maybe:
/* Add virtual entities to the first chain. */
chain = list_first_entry(&dev->chains, struct uvc_video_chain, list);
if (dev->gpio_unit)
list_add_tail(&dev->gpio_unit->chain, &chain->entities);
if (dev->swentity_unit)
list_add_tail(&dev->swentity_unit->chain, &chain->entities);
?
...
Regards,
Hans
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-14 14:29 ` Laurent Pinchart
@ 2025-07-14 15:46 ` Ricardo Ribalda
2025-07-15 19:35 ` Laurent Pinchart
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-14 15:46 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Laurent
On Mon, 14 Jul 2025 at 16:30, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Tue, Jul 01, 2025 at 01:13:10PM +0200, Ricardo Ribalda wrote:
> > On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart wrote:
> > > On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > > > Virtual entities need to provide more values than get_cur and get_cur
> > >
> > > I think you meant "get_info and get_cur".
> > >
> > > > for their controls. Add support for get_def, get_min, get_max and
> > > > get_res.
> > >
> > > Do they ? The UVC specification defines controls that don't list
> > > GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> > > the same for the software controls ? This patch is meant to support the
> > > UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> > > patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> > > enough ?
> >
> > V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> > that time requires get_min and get_max.
>
> Where does that requirement come from ? Is it because how the
> corresponding V4L2 type (V4L2_CTRL_TYPE_INTEGER) is handled in
> uvc_ctrl_clamp() ? uvc_ctrl_clamp() is only called when setting a
> control, from uvc_ctrl_set(), and V4L2_CID_CAMERA_ROTATION should be
> read-only.
It its for VIDIOC_QUERY_EXT_CTRL
uvc_query_v4l2_ctrl -> __uvc_query_v4l2_ctrl -> __uvc_queryctrl_boundaries
We need to list the min, max, def and step for every control. They are
fetched with uvc_ctrl_populate_cache()
>
> > We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> > fakes min, max and res, but I think that it is cleaner this approach.
> >
> > > > This is a preparation patch.
> > > >
> > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > ---
> > > > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > > > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > > > 2 files changed, 20 insertions(+)
> > > >
> > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > > > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > > > return ctrl->entity->get_cur(dev, ctrl->entity,
> > > > ctrl->info.selector, data, len);
> > > > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > > > + return ctrl->entity->get_def(dev, ctrl->entity,
> > > > + ctrl->info.selector, data, len);
> > > > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > > > + return ctrl->entity->get_min(dev, ctrl->entity,
> > > > + ctrl->info.selector, data, len);
> > > > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > > > + return ctrl->entity->get_max(dev, ctrl->entity,
> > > > + ctrl->info.selector, data, len);
> > > > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > > > + return ctrl->entity->get_res(dev, ctrl->entity,
> > > > + ctrl->info.selector, data, len);
> > > > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > > > return ctrl->entity->get_info(dev, ctrl->entity,
> > > > ctrl->info.selector, data);
> > > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > @@ -261,6 +261,14 @@ struct uvc_entity {
> > > > u8 cs, u8 *caps);
> > > > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > u8 cs, void *data, u16 size);
> > > > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *data, u16 size);
> > > > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *data, u16 size);
> > > > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *data, u16 size);
> > > > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *data, u16 size);
> > > >
> > > > unsigned int ncontrols;
> > > > struct uvc_control *controls;
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper
2025-07-14 14:24 ` Hans de Goede
@ 2025-07-14 15:51 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-14 15:51 UTC (permalink / raw)
To: Hans de Goede
Cc: Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Hans Verkuil, Sakari Ailus, Greg Kroah-Hartman, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
Bartosz Golaszewski, Rafael J. Wysocki, Len Brown, linux-media,
linux-kernel, linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, 14 Jul 2025 at 16:24, Hans de Goede <hansg@kernel.org> wrote:
>
> Hi Ricardo,
>
> On 5-Jun-25 19:53, Ricardo Ribalda wrote:
> > Create a helper function to query a control. The new function reduces
> > the number of arguments, calculates the length of the operation and
> > redirects the operation to the hardware or to the entity private
> > functions.
> >
> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
>
> Thanks, this looks like a nice cleanup.
>
> > ---
> > drivers/media/usb/uvc/uvc_ctrl.c | 81 ++++++++++++++++++++--------------------
> > 1 file changed, 41 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index b2768080c08aafa85acb9b7f318672c043d84e55..21ec7b978bc7aca21db7cb8fd5d135d876f3330c 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -576,6 +576,34 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
> > V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
> > };
> >
> > +static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > + const struct uvc_control *ctrl, u8 query,
> > + void *data)
> > +{
> > + u16 len;
> > +
> > + switch (query) {
> > + case UVC_GET_INFO:
> > + len = 1;
> > + break;
> > + case UVC_GET_LEN:
> > + len = 2;
> > + break;
> > + default:
> > + len = ctrl->info.size;
> > + }
> > +
> > + if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > + return ctrl->entity->get_cur(dev, ctrl->entity,
> > + ctrl->info.selector, data, len);
> > + if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > + return ctrl->entity->get_info(dev, ctrl->entity,
> > + ctrl->info.selector, data);
> > +
> > + return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
> > + ctrl->info.selector, data, len);
>
> Maybe:
>
> if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> return ctrl->entity->get_cur(dev, ctrl->entity,
> ctrl->info.selector, data, len);
> else if (query == UVC_GET_INFO && ctrl->entity->get_info)
> return ctrl->entity->get_info(dev, ctrl->entity,
> ctrl->info.selector, data);
> else
> return uvc_query_ctrl(dev, query, ctrl->entity->id, dev->intfnum,
> ctrl->info.selector, data, len);
>
> ?
>
> That + Laurent's well observed remark about info->selector vs
> ctrl->info.selector which I would probably have missed...
>
> About Laurent's remark about one case of this pre-existing,
> please fix this in a separate patch (I guess you would have done so
> anyways, but just to be sure).
I have changed the code a bit so we can always rely on
ctrl->info.selector. I have made a small "preparation patch" getting
ready for it. Keep an eye on the next version ;)
There is no need to send a new patch fixing the current code because
the only controls that could have invalid ctrl->info.selector are xu
and software entities are not xu.
Regards!
>
> Regards,
>
> Hans
>
>
>
>
>
> > +}
> > +
> > static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
> > struct uvc_video_chain *chain, struct uvc_control *ctrl)
> > {
> > @@ -1222,35 +1250,27 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
> > int ret;
> >
> > if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
> > - ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
> > - chain->dev->intfnum, ctrl->info.selector,
> > - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
> > - ctrl->info.size);
> > + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_DEF,
> > + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> > if (ret < 0)
> > return ret;
> > }
> >
> > if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
> > - ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
> > - chain->dev->intfnum, ctrl->info.selector,
> > - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
> > - ctrl->info.size);
> > + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MIN,
> > + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> > if (ret < 0)
> > return ret;
> > }
> > if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
> > - ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
> > - chain->dev->intfnum, ctrl->info.selector,
> > - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
> > - ctrl->info.size);
> > + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
> > + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> > if (ret < 0)
> > return ret;
> > }
> > if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
> > - ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
> > - chain->dev->intfnum, ctrl->info.selector,
> > - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
> > - ctrl->info.size);
> > + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
> > + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> > if (ret < 0) {
> > if (UVC_ENTITY_TYPE(ctrl->entity) !=
> > UVC_VC_EXTENSION_UNIT)
> > @@ -1291,16 +1311,7 @@ static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
> > return 0;
> > }
> >
> > - if (ctrl->entity->get_cur)
> > - ret = ctrl->entity->get_cur(chain->dev, ctrl->entity,
> > - ctrl->info.selector, data,
> > - ctrl->info.size);
> > - else
> > - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
> > - ctrl->entity->id, chain->dev->intfnum,
> > - ctrl->info.selector, data,
> > - ctrl->info.size);
> > -
> > + ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_CUR, data);
> > if (ret < 0)
> > return ret;
> >
> > @@ -2164,11 +2175,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
> > continue;
> >
> > if (!rollback)
> > - ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
> > - dev->intfnum, ctrl->info.selector,
> > - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> > - ctrl->info.size);
> > -
> > + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_SET_CUR,
> > + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
> > if (!ret)
> > processed_ctrls++;
> >
> > @@ -2570,13 +2578,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
> > if (data == NULL)
> > return -ENOMEM;
> >
> > - if (ctrl->entity->get_info)
> > - ret = ctrl->entity->get_info(dev, ctrl->entity,
> > - ctrl->info.selector, data);
> > - else
> > - ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
> > - dev->intfnum, info->selector, data, 1);
> > -
> > + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_INFO, data);
> > if (!ret) {
> > info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
> > UVC_CTRL_FLAG_SET_CUR |
> > @@ -2654,8 +2656,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
> > info->selector = ctrl->index + 1;
> >
> > /* Query and verify the control length (GET_LEN) */
> > - ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
> > - info->selector, data, 2);
> > + ret = uvc_ctrl_query_entity(dev, ctrl, UVC_GET_LEN, data);
> > if (ret < 0) {
> > uvc_dbg(dev, CONTROL,
> > "GET_LEN failed on control %pUl/%u (%d)\n",
> >
>
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION
2025-07-14 14:31 ` Laurent Pinchart
@ 2025-07-14 15:59 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-14 15:59 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, 14 Jul 2025 at 16:31, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Ricardo,
>
> On Tue, Jul 01, 2025 at 01:26:51PM +0200, Ricardo Ribalda wrote:
> > On Sun, 29 Jun 2025 at 20:15, Laurent Pinchart wrote:
> > > On Thu, Jun 05, 2025 at 05:53:04PM +0000, Ricardo Ribalda wrote:
> > > > Fetch the rotation from the fwnode and map it into a control.
> > > >
> > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > ---
> > > > drivers/media/usb/uvc/uvc_ctrl.c | 22 +++++++++++++--
> > > > drivers/media/usb/uvc/uvc_swentity.c | 55 ++++++++++++++++++++++++++++++++----
> > > > drivers/media/usb/uvc/uvcvideo.h | 5 ++++
> > > > 3 files changed, 74 insertions(+), 8 deletions(-)
> > > >
> > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > index 59be62ae24a4219fa9d7aacf2ae7382c95362178..5788f0c0f6604da06a7bca1b9999d0957817e75e 100644
> > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > @@ -378,11 +378,18 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > > > },
> > > > {
> > > > .entity = UVC_GUID_SWENTITY,
> > > > - .selector = 0,
> > > > - .index = 0,
> > > > + .selector = UVC_SWENTITY_ORIENTATION,
> > > > + .index = UVC_SWENTITY_ORIENTATION,
> > > > .size = 1,
> > > > .flags = UVC_CTRL_FLAG_GET_CUR,
> > > > },
> > > > + {
> > > > + .entity = UVC_GUID_SWENTITY,
> > > > + .selector = UVC_SWENTITY_ROTATION,
> > > > + .index = UVC_SWENTITY_ROTATION,
> > > > + .size = 2,
> > > > + .flags = UVC_CTRL_FLAG_GET_RANGE,
> > > > + },
> > > > };
> > > >
> > > > static const u32 uvc_control_classes[] = {
> > > > @@ -1025,7 +1032,7 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > > {
> > > > .id = V4L2_CID_CAMERA_ORIENTATION,
> > > > .entity = UVC_GUID_SWENTITY,
> > > > - .selector = 0,
> > > > + .selector = UVC_SWENTITY_ORIENTATION,
> > > > .size = 8,
> > > > .offset = 0,
> > > > .v4l2_type = V4L2_CTRL_TYPE_MENU,
> > > > @@ -1033,6 +1040,15 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
> > > > .menu_mask = GENMASK(V4L2_CAMERA_ORIENTATION_EXTERNAL,
> > > > V4L2_CAMERA_ORIENTATION_FRONT),
> > > > },
> > > > + {
> > > > + .id = V4L2_CID_CAMERA_SENSOR_ROTATION,
> > > > + .entity = UVC_GUID_SWENTITY,
> > > > + .selector = UVC_SWENTITY_ROTATION,
> > > > + .size = 16,
> > > > + .offset = 0,
> > > > + .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
> > > > + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
> > > > + },
> > > > };
> > > >
> > > > /* ------------------------------------------------------------------------
> > > > diff --git a/drivers/media/usb/uvc/uvc_swentity.c b/drivers/media/usb/uvc/uvc_swentity.c
> > > > index 702a2c26e029a0655dade177ed2a9b88d7a4136d..60f3166addbeb7d2e431d107b23034d2d11a1812 100644
> > > > --- a/drivers/media/usb/uvc/uvc_swentity.c
> > > > +++ b/drivers/media/usb/uvc/uvc_swentity.c
> > > > @@ -10,10 +10,11 @@
> > > > #include <media/v4l2-fwnode.h>
> > > > #include "uvcvideo.h"
> > > >
> > > > -static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > > > - u8 cs, void *data, u16 size)
> > > > +static int uvc_swentity_get_orientation(struct uvc_device *dev,
> > > > + struct uvc_entity *entity, u8 cs,
> > > > + void *data, u16 size)
> > > > {
> > > > - if (size < 1)
> > > > + if (cs != UVC_SWENTITY_ORIENTATION || size != 1)
> > > > return -EINVAL;
> > > >
> > > > switch (entity->swentity.props.orientation) {
> > > > @@ -30,6 +31,31 @@ static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entit
> > > > return 0;
> > > > }
> > > >
> > > > +static int uvc_swentity_get_rotation(struct uvc_device *dev,
> > > > + struct uvc_entity *entity, u8 cs, void *data,
> > > > + u16 size)
> > > > +{
> > > > + if (cs != UVC_SWENTITY_ROTATION || size != 2)
> > > > + return -EINVAL;
> > > > +
> > > > + ((u8 *)data)[0] = entity->swentity.props.rotation;
> > > > + ((u8 *)data)[1] = entity->swentity.props.rotation >> 8;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int uvc_swentity_get_cur(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *data, u16 size)
> > > > +{
> > > > + switch (cs) {
> > > > + case UVC_SWENTITY_ORIENTATION:
> > > > + return uvc_swentity_get_orientation(dev, entity, cs, data, size);
> > > > + case UVC_SWENTITY_ROTATION:
> > > > + return uvc_swentity_get_rotation(dev, entity, cs, data, size);
> > > > + }
> > > > + return -EINVAL;
> > > > +}
> > > > +
> > > > static int uvc_swentity_get_info(struct uvc_device *dev,
> > > > struct uvc_entity *entity, u8 cs, u8 *caps)
> > > > {
> > > > @@ -37,11 +63,22 @@ static int uvc_swentity_get_info(struct uvc_device *dev,
> > > > return 0;
> > > > }
> > > >
> > > > +static int uvc_swentity_get_res(struct uvc_device *dev, struct uvc_entity *entity,
> > > > + u8 cs, void *res, u16 size)
> > > > +{
> > > > + if (size == 0)
> > > > + return -EINVAL;
> > >
> > > The get_cur functions return an error if the size doesn't match the
> > > expected size. I think you can return -EINVAL if size != 1.
> > >
> > > > + ((u8 *)res)[0] = 1;
> > > > + memset(res + 1, 0, size - 1);
> > >
> > > And drop the memset.
> > >
> > > > + return 0;
> > > > +}
> > > > +
> > > > int uvc_swentity_init(struct uvc_device *dev)
> > > > {
> > > > static const u8 uvc_swentity_guid[] = UVC_GUID_SWENTITY;
> > > > struct v4l2_fwnode_device_properties props;
> > > > struct uvc_entity *unit;
> > > > + u8 controls = 0;
> > > > int ret;
> > > >
> > > > ret = v4l2_fwnode_device_parse(&dev->udev->dev, &props);
> > > > @@ -49,7 +86,11 @@ int uvc_swentity_init(struct uvc_device *dev)
> > > > return dev_err_probe(&dev->intf->dev, ret,
> > > > "Can't parse fwnode\n");
> > > >
> > > > - if (props.orientation == V4L2_FWNODE_PROPERTY_UNSET)
> > > > + if (props.orientation != V4L2_FWNODE_PROPERTY_UNSET)
> > > > + controls |= BIT(UVC_SWENTITY_ORIENTATION);
> > > > + if (props.rotation != V4L2_FWNODE_PROPERTY_UNSET)
> > > > + controls |= BIT(UVC_SWENTITY_ROTATION);
> > > > + if (!controls)
> > > > return 0;
> > > >
> > > > unit = uvc_alloc_entity(UVC_SWENTITY_UNIT, UVC_SWENTITY_UNIT_ID, 0, 1);
> > > > @@ -60,9 +101,13 @@ int uvc_swentity_init(struct uvc_device *dev)
> > > > unit->swentity.props = props;
> > > > unit->swentity.bControlSize = 1;
> > > > unit->swentity.bmControls = (u8 *)unit + sizeof(*unit);
> > > > - unit->swentity.bmControls[0] = 1;
> > > > + unit->swentity.bmControls[0] = controls;
> > > > unit->get_cur = uvc_swentity_get_cur;
> > > > unit->get_info = uvc_swentity_get_info;
> > > > + unit->get_res = uvc_swentity_get_res;
> > > > + unit->get_def = uvc_swentity_get_rotation;
> > > > + unit->get_min = uvc_swentity_get_rotation;
> > > > + unit->get_max = uvc_swentity_get_rotation;
> > >
> > > Why do you support GET_DEF, GET_MIN and GET_MAX for rotation only ?
> >
> > Orientation has enum type. It does not require min or max.
> >
> > For get_def I could use get_cur, but 0 is as good as any other value
> > within range.
>
> Both the orientation and rotation are read-only, and should report min
> == max == def == cur. What am I missing ?
V4L2_CID_CAMERA_ORIENTATION has type V4L2_CTRL_TYPE_MENU
In _uvc_queryctrl_boundaries(), min and max are auto calculated, they
are not based on information from the device.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/media/usb/uvc/uvc_ctrl.c#n1504
I can change unit->get_(def|min|max)=uvc_swentity_get_cur if you
think that it is cleaner...
Regards!
>
> > > > strscpy(unit->name, "SWENTITY", sizeof(unit->name));
> > > >
> > > > list_add_tail(&unit->list, &dev->entities);
> > > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > > index d6da8ed3ad4cf3377df49923e051fe04d83d2e38..7cca0dc75d11f6a13bc4f09676a5a00e80cb38f7 100644
> > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > @@ -45,6 +45,11 @@
> > > > #define UVC_SWENTITY_UNIT 0x7ffd
> > > > #define UVC_SWENTITY_UNIT_ID 0x101
> > > >
> > > > +enum {
> > > > + UVC_SWENTITY_ORIENTATION,
> > > > + UVC_SWENTITY_ROTATION
> > > > +};
> > > > +
> > > > /* ------------------------------------------------------------------------
> > > > * Driver specific constants.
> > > > */
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-07-14 14:36 ` Laurent Pinchart
@ 2025-07-14 16:04 ` Ricardo Ribalda
2025-07-14 16:30 ` Laurent Pinchart
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-14 16:04 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans Verkuil, Hans de Goede, Mauro Carvalho Chehab, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, 14 Jul 2025 at 16:36, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Tue, Jul 08, 2025 at 08:28:21AM +0200, Ricardo Ribalda wrote:
> > On Tue, 1 Jul 2025 at 13:20, Ricardo Ribalda wrote:
> > > On Sun, 29 Jun 2025 at 20:06, Laurent Pinchart wrote:
> > > > Hi Ricardo,
> > > >
> > > > Thank you for the patch.
> > > >
> > > > I would use "software entities" and not "virtual entities" in the
> > > > subject line and everywhere else, as those entities are not virtual.
> > > >
> > > > On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> > > > > Neither the GPIO nor the SWENTITY entities form part of the device
> > > > > pipeline. We just create them to hold emulated uvc controls.
> > > > >
> > > > > When the device initializes, a warning is thrown by the v4l2 core:
> > > > > uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
> > > > >
> > > > > There are no entity function that matches what we are doing here, and
> > > > > it does not make to much sense to create a function for entities that
> > > > > do not really exist.
> > > >
> > > > I don't agree with this. The purpose of reporting entities to userspace
> > > > through the MC API is to let application enumerate what entities a
> > > > device contains. Being able to enumerate software entities seems as
> > > > useful as being able to enumerate hardware entities.
> > >
> > > What function shall we use in this case? Nothing here seems to match a
> > > software entity
> > > https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-types.html
> > >
> > > Any suggestion for name?
> > > Shall we just live with the warning in dmesg?
> >
> > I just realised that if/when we move to the control framework, the
> > software entity will be gone.... So to avoid introducing a uAPI change
> > that will be reverted later I think that we should keep this patch.
>
> You know my opinion about moving to the control framework, so that's not
> a very compelling argument :-)
Correct me if I am wrong, your opinion is that it will take too much
work, not that it can't be done or that it is a bad idea.
Will send a patch using MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, but
when/if we use the control framework, please let me drop the swentity.
Thanks!
>
> We could use MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, as that's the
> function already used by XUs, and the SWENTITY fulfills the same role as
> XUs in some devices.
>
> > > > > Do not create MC entities for them and pretend nothing happened here.
> > > > >
> > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > > ---
> > > > > drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> > > > > 1 file changed, 10 insertions(+)
> > > > >
> > > > > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > > > > index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> > > > > --- a/drivers/media/usb/uvc/uvc_entity.c
> > > > > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > > > > @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > > > > {
> > > > > int ret;
> > > > >
> > > > > + /*
> > > > > + * Do not initialize virtual entities, they do not really exist
> > > > > + * and are not connected to any other entities.
> > > > > + */
> > > > > + switch (UVC_ENTITY_TYPE(entity)) {
> > > > > + case UVC_EXT_GPIO_UNIT:
> > > > > + case UVC_SWENTITY_UNIT:
> > > > > + return 0;
> > > > > + }
> > > > > +
> > > > > if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> > > > > u32 function;
> > > > >
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities
2025-07-14 16:04 ` Ricardo Ribalda
@ 2025-07-14 16:30 ` Laurent Pinchart
0 siblings, 0 replies; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-14 16:30 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans Verkuil, Hans de Goede, Mauro Carvalho Chehab, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, Jul 14, 2025 at 06:04:50PM +0200, Ricardo Ribalda wrote:
> On Mon, 14 Jul 2025 at 16:36, Laurent Pinchart wrote:
> > On Tue, Jul 08, 2025 at 08:28:21AM +0200, Ricardo Ribalda wrote:
> > > On Tue, 1 Jul 2025 at 13:20, Ricardo Ribalda wrote:
> > > > On Sun, 29 Jun 2025 at 20:06, Laurent Pinchart wrote:
> > > > > Hi Ricardo,
> > > > >
> > > > > Thank you for the patch.
> > > > >
> > > > > I would use "software entities" and not "virtual entities" in the
> > > > > subject line and everywhere else, as those entities are not virtual.
> > > > >
> > > > > On Thu, Jun 05, 2025 at 05:53:05PM +0000, Ricardo Ribalda wrote:
> > > > > > Neither the GPIO nor the SWENTITY entities form part of the device
> > > > > > pipeline. We just create them to hold emulated uvc controls.
> > > > > >
> > > > > > When the device initializes, a warning is thrown by the v4l2 core:
> > > > > > uvcvideo 1-1:1.0: Entity type for entity SWENTITY was not initialized!
> > > > > >
> > > > > > There are no entity function that matches what we are doing here, and
> > > > > > it does not make to much sense to create a function for entities that
> > > > > > do not really exist.
> > > > >
> > > > > I don't agree with this. The purpose of reporting entities to userspace
> > > > > through the MC API is to let application enumerate what entities a
> > > > > device contains. Being able to enumerate software entities seems as
> > > > > useful as being able to enumerate hardware entities.
> > > >
> > > > What function shall we use in this case? Nothing here seems to match a
> > > > software entity
> > > > https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/media-types.html
> > > >
> > > > Any suggestion for name?
> > > > Shall we just live with the warning in dmesg?
> > >
> > > I just realised that if/when we move to the control framework, the
> > > software entity will be gone.... So to avoid introducing a uAPI change
> > > that will be reverted later I think that we should keep this patch.
> >
> > You know my opinion about moving to the control framework, so that's not
> > a very compelling argument :-)
>
> Correct me if I am wrong, your opinion is that it will take too much
> work, not that it can't be done or that it is a bad idea.
My opinion is that it's not worth the time needed to write patches, nor
the time needed to review them. It would be a big change, with risks of
regressions, for minimal gain, if any. I don't know if it can be done,
but I think it's a bad idea. Don't fix something that isn't broken, the
patches backlog is big enough, let's focus on useful changes.
> Will send a patch using MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, but
> when/if we use the control framework, please let me drop the swentity.
>
> Thanks!
>
> > We could use MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER, as that's the
> > function already used by XUs, and the SWENTITY fulfills the same role as
> > XUs in some devices.
> >
> > > > > > Do not create MC entities for them and pretend nothing happened here.
> > > > > >
> > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > > > ---
> > > > > > drivers/media/usb/uvc/uvc_entity.c | 10 ++++++++++
> > > > > > 1 file changed, 10 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
> > > > > > index d1a652ef35ec34801bd39a5124b834edf838a79e..2dbeb4ab0c4c8cc763ff2dcd2d836a50f3c6a040 100644
> > > > > > --- a/drivers/media/usb/uvc/uvc_entity.c
> > > > > > +++ b/drivers/media/usb/uvc/uvc_entity.c
> > > > > > @@ -72,6 +72,16 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
> > > > > > {
> > > > > > int ret;
> > > > > >
> > > > > > + /*
> > > > > > + * Do not initialize virtual entities, they do not really exist
> > > > > > + * and are not connected to any other entities.
> > > > > > + */
> > > > > > + switch (UVC_ENTITY_TYPE(entity)) {
> > > > > > + case UVC_EXT_GPIO_UNIT:
> > > > > > + case UVC_SWENTITY_UNIT:
> > > > > > + return 0;
> > > > > > + }
> > > > > > +
> > > > > > if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
> > > > > > u32 function;
> > > > > >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-14 15:46 ` Ricardo Ribalda
@ 2025-07-15 19:35 ` Laurent Pinchart
2025-07-16 10:32 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Laurent Pinchart @ 2025-07-15 19:35 UTC (permalink / raw)
To: Ricardo Ribalda
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Mon, Jul 14, 2025 at 05:46:40PM +0200, Ricardo Ribalda wrote:
> On Mon, 14 Jul 2025 at 16:30, Laurent Pinchart wrote:
> > On Tue, Jul 01, 2025 at 01:13:10PM +0200, Ricardo Ribalda wrote:
> > > On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart wrote:
> > > > On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > > > > Virtual entities need to provide more values than get_cur and get_cur
> > > >
> > > > I think you meant "get_info and get_cur".
> > > >
> > > > > for their controls. Add support for get_def, get_min, get_max and
> > > > > get_res.
> > > >
> > > > Do they ? The UVC specification defines controls that don't list
> > > > GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> > > > the same for the software controls ? This patch is meant to support the
> > > > UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> > > > patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> > > > enough ?
> > >
> > > V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> > > that time requires get_min and get_max.
> >
> > Where does that requirement come from ? Is it because how the
> > corresponding V4L2 type (V4L2_CTRL_TYPE_INTEGER) is handled in
> > uvc_ctrl_clamp() ? uvc_ctrl_clamp() is only called when setting a
> > control, from uvc_ctrl_set(), and V4L2_CID_CAMERA_ROTATION should be
> > read-only.
>
> It its for VIDIOC_QUERY_EXT_CTRL
>
> uvc_query_v4l2_ctrl -> __uvc_query_v4l2_ctrl -> __uvc_queryctrl_boundaries
>
> We need to list the min, max, def and step for every control. They are
> fetched with uvc_ctrl_populate_cache()
Ah, I see, thanks.
For GET_RES, I think we can leave it unimplemented.
__uvc_queryctrl_boundaries() will set v4l2_ctrl->step = 0 which seems to
be the right behaviour for a read-only control whose value never
changes.
As for the minimum and maximum, they are currently set to 0 if the
corresponding operations are not supported. I wonder if we should set
them to the current value instead for read-only controls (as in controls
whose flags report support for GET_CUR only)..
> > > We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> > > fakes min, max and res, but I think that it is cleaner this approach.
> > >
> > > > > This is a preparation patch.
> > > > >
> > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > > ---
> > > > > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > > > > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > > > > 2 files changed, 20 insertions(+)
> > > > >
> > > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > > > > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > > > > return ctrl->entity->get_cur(dev, ctrl->entity,
> > > > > ctrl->info.selector, data, len);
> > > > > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > > > > + return ctrl->entity->get_def(dev, ctrl->entity,
> > > > > + ctrl->info.selector, data, len);
> > > > > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > > > > + return ctrl->entity->get_min(dev, ctrl->entity,
> > > > > + ctrl->info.selector, data, len);
> > > > > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > > > > + return ctrl->entity->get_max(dev, ctrl->entity,
> > > > > + ctrl->info.selector, data, len);
> > > > > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > > > > + return ctrl->entity->get_res(dev, ctrl->entity,
> > > > > + ctrl->info.selector, data, len);
> > > > > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > > > > return ctrl->entity->get_info(dev, ctrl->entity,
> > > > > ctrl->info.selector, data);
> > > > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > > > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > > @@ -261,6 +261,14 @@ struct uvc_entity {
> > > > > u8 cs, u8 *caps);
> > > > > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > u8 cs, void *data, u16 size);
> > > > > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > + u8 cs, void *data, u16 size);
> > > > > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > + u8 cs, void *data, u16 size);
> > > > > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > + u8 cs, void *data, u16 size);
> > > > > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > + u8 cs, void *data, u16 size);
> > > > >
> > > > > unsigned int ncontrols;
> > > > > struct uvc_control *controls;
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-15 19:35 ` Laurent Pinchart
@ 2025-07-16 10:32 ` Ricardo Ribalda
2025-08-07 7:35 ` Ricardo Ribalda
0 siblings, 1 reply; 62+ messages in thread
From: Ricardo Ribalda @ 2025-07-16 10:32 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
On Tue, 15 Jul 2025 at 21:35, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> On Mon, Jul 14, 2025 at 05:46:40PM +0200, Ricardo Ribalda wrote:
> > On Mon, 14 Jul 2025 at 16:30, Laurent Pinchart wrote:
> > > On Tue, Jul 01, 2025 at 01:13:10PM +0200, Ricardo Ribalda wrote:
> > > > On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart wrote:
> > > > > On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > > > > > Virtual entities need to provide more values than get_cur and get_cur
> > > > >
> > > > > I think you meant "get_info and get_cur".
> > > > >
> > > > > > for their controls. Add support for get_def, get_min, get_max and
> > > > > > get_res.
> > > > >
> > > > > Do they ? The UVC specification defines controls that don't list
> > > > > GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> > > > > the same for the software controls ? This patch is meant to support the
> > > > > UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> > > > > patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> > > > > enough ?
> > > >
> > > > V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> > > > that time requires get_min and get_max.
> > >
> > > Where does that requirement come from ? Is it because how the
> > > corresponding V4L2 type (V4L2_CTRL_TYPE_INTEGER) is handled in
> > > uvc_ctrl_clamp() ? uvc_ctrl_clamp() is only called when setting a
> > > control, from uvc_ctrl_set(), and V4L2_CID_CAMERA_ROTATION should be
> > > read-only.
> >
> > It its for VIDIOC_QUERY_EXT_CTRL
> >
> > uvc_query_v4l2_ctrl -> __uvc_query_v4l2_ctrl -> __uvc_queryctrl_boundaries
> >
> > We need to list the min, max, def and step for every control. They are
> > fetched with uvc_ctrl_populate_cache()
>
> Ah, I see, thanks.
>
> For GET_RES, I think we can leave it unimplemented.
> __uvc_queryctrl_boundaries() will set v4l2_ctrl->step = 0 which seems to
> be the right behaviour for a read-only control whose value never
> changes.
That will break v4l2-compatiblity. Step needs to be != 0
https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-compliance/v4l2-test-controls.cpp#n77
Control ioctls (Input 0):
fail: v4l2-test-controls.cpp(77): step == 0
fail: v4l2-test-controls.cpp(201): invalid control 009a0923
>
> As for the minimum and maximum, they are currently set to 0 if the
> corresponding operations are not supported. I wonder if we should set
> them to the current value instead for read-only controls (as in controls
> whose flags report support for GET_CUR only)..
I am not sure that I like that approach IMO the code looks worse...
but if you prefer that, we can go that way
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index ec472e111248..47224437018b 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -35,6 +35,8 @@
/* ------------------------------------------------------------------------
* Controls
*/
+static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl);
static const struct uvc_control_info uvc_ctrls[] = {
{
@@ -1272,6 +1274,13 @@ static int uvc_ctrl_populate_cache(struct
uvc_video_chain *chain,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
if (ret < 0)
return ret;
+ } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
+ ret = __uvc_ctrl_load_cur(chain, ctrl);
+ if (!ret) {
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info.size);
+ }
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
@@ -1279,14 +1288,31 @@ static int uvc_ctrl_populate_cache(struct
uvc_video_chain *chain,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
if (ret < 0)
return ret;
+ } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
+ ret = __uvc_ctrl_load_cur(chain, ctrl);
+ if (!ret) {
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info.size);
+ }
}
+
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
if (ret < 0)
return ret;
+ } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
+ ret = __uvc_ctrl_load_cur(chain, ctrl);
+ if (!ret) {
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info.size);
+ }
}
+
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+ u8 *res;
ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (ret < 0) {
@@ -1304,7 +1330,13 @@ static int uvc_ctrl_populate_cache(struct
uvc_video_chain *chain,
"an XU control. Enabling workaround.\n");
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
ctrl->info.size);
+ res = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES);
+ *res = 1
}
+ } else {
+ memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
ctrl->info.size);
+ res = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES);
+ *res = 1;
}
ctrl->cached = 1;
@@ -1541,11 +1573,8 @@ static int __uvc_queryctrl_boundaries(struct
uvc_video_chain *chain,
return ret;
}
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF)
v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
UVC_GET_DEF, uvc_ctrl_data(ctrl,
UVC_CTRL_DATA_DEF));
- else
- v4l2_ctrl->default_value = 0;
switch (mapping->v4l2_type) {
case V4L2_CTRL_TYPE_MENU:
@@ -1576,23 +1605,14 @@ static int __uvc_queryctrl_boundaries(struct
uvc_video_chain *chain,
break;
}
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
- v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- else
- v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
- v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- else
- v4l2_ctrl->maximum = 0;
+ v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
- v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- else
- v4l2_ctrl->step = 0;
+ v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
return 0;
}
>
> > > > We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> > > > fakes min, max and res, but I think that it is cleaner this approach.
> > > >
> > > > > > This is a preparation patch.
> > > > > >
> > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > > > ---
> > > > > > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > > > > > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > > > > > 2 files changed, 20 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > > > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > > > > > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > > > > > return ctrl->entity->get_cur(dev, ctrl->entity,
> > > > > > ctrl->info.selector, data, len);
> > > > > > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > > > > > + return ctrl->entity->get_def(dev, ctrl->entity,
> > > > > > + ctrl->info.selector, data, len);
> > > > > > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > > > > > + return ctrl->entity->get_min(dev, ctrl->entity,
> > > > > > + ctrl->info.selector, data, len);
> > > > > > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > > > > > + return ctrl->entity->get_max(dev, ctrl->entity,
> > > > > > + ctrl->info.selector, data, len);
> > > > > > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > > > > > + return ctrl->entity->get_res(dev, ctrl->entity,
> > > > > > + ctrl->info.selector, data, len);
> > > > > > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > > > > > return ctrl->entity->get_info(dev, ctrl->entity,
> > > > > > ctrl->info.selector, data);
> > > > > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > > > > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > > > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > > > @@ -261,6 +261,14 @@ struct uvc_entity {
> > > > > > u8 cs, u8 *caps);
> > > > > > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > u8 cs, void *data, u16 size);
> > > > > > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > + u8 cs, void *data, u16 size);
> > > > > > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > + u8 cs, void *data, u16 size);
> > > > > > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > + u8 cs, void *data, u16 size);
> > > > > > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > + u8 cs, void *data, u16 size);
> > > > > >
> > > > > > unsigned int ncontrols;
> > > > > > struct uvc_control *controls;
>
> --
> Regards,
>
> Laurent Pinchart
--
Ricardo Ribalda
^ permalink raw reply related [flat|nested] 62+ messages in thread
* Re: [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity
2025-07-16 10:32 ` Ricardo Ribalda
@ 2025-08-07 7:35 ` Ricardo Ribalda
0 siblings, 0 replies; 62+ messages in thread
From: Ricardo Ribalda @ 2025-08-07 7:35 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Hans de Goede, Mauro Carvalho Chehab, Hans Verkuil, Sakari Ailus,
Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Linus Walleij, Bartosz Golaszewski,
Rafael J. Wysocki, Len Brown, linux-media, linux-kernel,
linux-usb, devicetree, linux-gpio, linux-acpi
Hi Laurent
On Wed, 16 Jul 2025 at 12:32, Ricardo Ribalda <ribalda@chromium.org> wrote:
>
> On Tue, 15 Jul 2025 at 21:35, Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > On Mon, Jul 14, 2025 at 05:46:40PM +0200, Ricardo Ribalda wrote:
> > > On Mon, 14 Jul 2025 at 16:30, Laurent Pinchart wrote:
> > > > On Tue, Jul 01, 2025 at 01:13:10PM +0200, Ricardo Ribalda wrote:
> > > > > On Sun, 29 Jun 2025 at 20:13, Laurent Pinchart wrote:
> > > > > > On Thu, Jun 05, 2025 at 05:53:03PM +0000, Ricardo Ribalda wrote:
> > > > > > > Virtual entities need to provide more values than get_cur and get_cur
> > > > > >
> > > > > > I think you meant "get_info and get_cur".
> > > > > >
> > > > > > > for their controls. Add support for get_def, get_min, get_max and
> > > > > > > get_res.
> > > > > >
> > > > > > Do they ? The UVC specification defines controls that don't list
> > > > > > GET_DEF, GET_MIN, GET_MAX and GET_RES as mandatory requests. Can't we do
> > > > > > the same for the software controls ? This patch is meant to support the
> > > > > > UVC_SWENTITY_ORIENTATION and UVC_SWENTITY_ROTATION control in the next
> > > > > > patch, and those are read-only controls. Aren't GET_INFO and GET_CUR
> > > > > > enough ?
> > > > >
> > > > > V4L2_CID_CAMERA_ROTATION has the type UVC_CTRL_DATA_TYPE_UNSIGNED,
> > > > > that time requires get_min and get_max.
> > > >
> > > > Where does that requirement come from ? Is it because how the
> > > > corresponding V4L2 type (V4L2_CTRL_TYPE_INTEGER) is handled in
> > > > uvc_ctrl_clamp() ? uvc_ctrl_clamp() is only called when setting a
> > > > control, from uvc_ctrl_set(), and V4L2_CID_CAMERA_ROTATION should be
> > > > read-only.
> > >
> > > It its for VIDIOC_QUERY_EXT_CTRL
> > >
> > > uvc_query_v4l2_ctrl -> __uvc_query_v4l2_ctrl -> __uvc_queryctrl_boundaries
> > >
> > > We need to list the min, max, def and step for every control. They are
> > > fetched with uvc_ctrl_populate_cache()
> >
> > Ah, I see, thanks.
> >
> > For GET_RES, I think we can leave it unimplemented.
> > __uvc_queryctrl_boundaries() will set v4l2_ctrl->step = 0 which seems to
> > be the right behaviour for a read-only control whose value never
> > changes.
>
> That will break v4l2-compatiblity. Step needs to be != 0
> https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-compliance/v4l2-test-controls.cpp#n77
>
> Control ioctls (Input 0):
> fail: v4l2-test-controls.cpp(77): step == 0
> fail: v4l2-test-controls.cpp(201): invalid control 009a0923
>
> >
> > As for the minimum and maximum, they are currently set to 0 if the
> > corresponding operations are not supported. I wonder if we should set
> > them to the current value instead for read-only controls (as in controls
> > whose flags report support for GET_CUR only)..
>
> I am not sure that I like that approach IMO the code looks worse...
> but if you prefer that, we can go that way
I am almost ready to send a new version.
What approach do you prefer?
Regards!
>
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index ec472e111248..47224437018b 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -35,6 +35,8 @@
> /* ------------------------------------------------------------------------
> * Controls
> */
> +static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain,
> + struct uvc_control *ctrl);
>
> static const struct uvc_control_info uvc_ctrls[] = {
> {
> @@ -1272,6 +1274,13 @@ static int uvc_ctrl_populate_cache(struct
> uvc_video_chain *chain,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
> if (ret < 0)
> return ret;
> + } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + if (!ret) {
> + memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> + ctrl->info.size);
> + }
> }
>
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
> @@ -1279,14 +1288,31 @@ static int uvc_ctrl_populate_cache(struct
> uvc_video_chain *chain,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> if (ret < 0)
> return ret;
> + } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + if (!ret) {
> + memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> + ctrl->info.size);
> + }
> }
> +
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
> ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_MAX,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> if (ret < 0)
> return ret;
> + } else if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) {
> + ret = __uvc_ctrl_load_cur(chain, ctrl);
> + if (!ret) {
> + memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
> + ctrl->info.size);
> + }
> }
> +
> if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
> + u8 *res;
> ret = uvc_ctrl_query_entity(chain->dev, ctrl, UVC_GET_RES,
> uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> if (ret < 0) {
> @@ -1304,7 +1330,13 @@ static int uvc_ctrl_populate_cache(struct
> uvc_video_chain *chain,
> "an XU control. Enabling workaround.\n");
> memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
> ctrl->info.size);
> + res = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES);
> + *res = 1
> }
> + } else {
> + memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
> ctrl->info.size);
> + res = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES);
> + *res = 1;
> }
>
> ctrl->cached = 1;
> @@ -1541,11 +1573,8 @@ static int __uvc_queryctrl_boundaries(struct
> uvc_video_chain *chain,
> return ret;
> }
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF)
> v4l2_ctrl->default_value = uvc_mapping_get_s32(mapping,
> UVC_GET_DEF, uvc_ctrl_data(ctrl,
> UVC_CTRL_DATA_DEF));
> - else
> - v4l2_ctrl->default_value = 0;
>
> switch (mapping->v4l2_type) {
> case V4L2_CTRL_TYPE_MENU:
> @@ -1576,23 +1605,14 @@ static int __uvc_queryctrl_boundaries(struct
> uvc_video_chain *chain,
> break;
> }
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
> - v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
> - else
> - v4l2_ctrl->minimum = 0;
> + v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
> - v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
> - else
> - v4l2_ctrl->maximum = 0;
> + v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
>
> - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
> - v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
> - else
> - v4l2_ctrl->step = 0;
> + v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
> + uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
>
> return 0;
> }
>
> >
> > > > > We can create a new type UVC_CTRL_DATA_TYPE_UNSIGNED_READ_ONLY that
> > > > > fakes min, max and res, but I think that it is cleaner this approach.
> > > > >
> > > > > > > This is a preparation patch.
> > > > > > >
> > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
> > > > > > > ---
> > > > > > > drivers/media/usb/uvc/uvc_ctrl.c | 12 ++++++++++++
> > > > > > > drivers/media/usb/uvc/uvcvideo.h | 8 ++++++++
> > > > > > > 2 files changed, 20 insertions(+)
> > > > > > >
> > > > > > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > > index 21ec7b978bc7aca21db7cb8fd5d135d876f3330c..59be62ae24a4219fa9d7aacf2ae7382c95362178 100644
> > > > > > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > > > > > @@ -596,6 +596,18 @@ static int uvc_ctrl_query_entity(struct uvc_device *dev,
> > > > > > > if (query == UVC_GET_CUR && ctrl->entity->get_cur)
> > > > > > > return ctrl->entity->get_cur(dev, ctrl->entity,
> > > > > > > ctrl->info.selector, data, len);
> > > > > > > + if (query == UVC_GET_DEF && ctrl->entity->get_def)
> > > > > > > + return ctrl->entity->get_def(dev, ctrl->entity,
> > > > > > > + ctrl->info.selector, data, len);
> > > > > > > + if (query == UVC_GET_MIN && ctrl->entity->get_min)
> > > > > > > + return ctrl->entity->get_min(dev, ctrl->entity,
> > > > > > > + ctrl->info.selector, data, len);
> > > > > > > + if (query == UVC_GET_MAX && ctrl->entity->get_max)
> > > > > > > + return ctrl->entity->get_max(dev, ctrl->entity,
> > > > > > > + ctrl->info.selector, data, len);
> > > > > > > + if (query == UVC_GET_RES && ctrl->entity->get_res)
> > > > > > > + return ctrl->entity->get_res(dev, ctrl->entity,
> > > > > > > + ctrl->info.selector, data, len);
> > > > > > > if (query == UVC_GET_INFO && ctrl->entity->get_info)
> > > > > > > return ctrl->entity->get_info(dev, ctrl->entity,
> > > > > > > ctrl->info.selector, data);
> > > > > > > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > > > > > > index a931750bdea25b9062dcc7644bf5f2ed89c1cb4c..d6da8ed3ad4cf3377df49923e051fe04d83d2e38 100644
> > > > > > > --- a/drivers/media/usb/uvc/uvcvideo.h
> > > > > > > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > > > > > > @@ -261,6 +261,14 @@ struct uvc_entity {
> > > > > > > u8 cs, u8 *caps);
> > > > > > > int (*get_cur)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > > u8 cs, void *data, u16 size);
> > > > > > > + int (*get_def)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > > + u8 cs, void *data, u16 size);
> > > > > > > + int (*get_min)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > > + u8 cs, void *data, u16 size);
> > > > > > > + int (*get_max)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > > + u8 cs, void *data, u16 size);
> > > > > > > + int (*get_res)(struct uvc_device *dev, struct uvc_entity *entity,
> > > > > > > + u8 cs, void *data, u16 size);
> > > > > > >
> > > > > > > unsigned int ncontrols;
> > > > > > > struct uvc_control *controls;
> >
> > --
> > Regards,
> >
> > Laurent Pinchart
>
>
>
> --
> Ricardo Ribalda
--
Ricardo Ribalda
^ permalink raw reply [flat|nested] 62+ messages in thread
end of thread, other threads:[~2025-08-07 7:35 UTC | newest]
Thread overview: 62+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-05 17:52 [PATCH v2 00/12] media: uvcvideo: Add support for orientation and rotation Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 01/12] media: uvcvideo: Always set default_value Ricardo Ribalda
2025-06-29 17:39 ` Laurent Pinchart
2025-07-14 13:00 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 02/12] media: v4l: fwnode: Support ACPI's _PLD for v4l2_fwnode_device_parse Ricardo Ribalda
2025-06-29 9:21 ` Sakari Ailus
2025-07-01 9:04 ` Ricardo Ribalda
2025-07-07 21:01 ` Sakari Ailus
2025-07-14 13:03 ` Hans de Goede
2025-07-14 14:14 ` Ricardo Ribalda
2025-06-05 17:52 ` [PATCH v2 03/12] ACPI: mipi-disco-img: Do not duplicate rotation info into swnodes Ricardo Ribalda
2025-06-29 9:24 ` Sakari Ailus
2025-07-07 21:05 ` Sakari Ailus
2025-07-14 13:08 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 04/12] media: ipu-bridge: Use v4l2_fwnode_device_parse helper Ricardo Ribalda
2025-06-06 4:27 ` kernel test robot
2025-07-14 13:11 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 05/12] media: ipu-bridge: Use v4l2_fwnode for unknown rotations Ricardo Ribalda
2025-07-07 21:44 ` Sakari Ailus
2025-07-08 9:16 ` Ricardo Ribalda
2025-07-08 9:22 ` Sakari Ailus
2025-07-08 12:09 ` Ricardo Ribalda
2025-07-08 12:20 ` Sakari Ailus
2025-07-08 14:58 ` Ricardo Ribalda
2025-07-08 23:46 ` Sakari Ailus
2025-07-14 13:11 ` Hans de Goede
2025-06-05 17:52 ` [PATCH v2 06/12] dt-bindings: usb: usb-device: Add orientation and rotation Ricardo Ribalda
2025-06-25 18:56 ` Rob Herring
2025-06-05 17:53 ` [PATCH v2 07/12] media: uvcvideo: Make uvc_alloc_entity non static Ricardo Ribalda
2025-06-29 17:43 ` Laurent Pinchart
2025-07-14 13:31 ` Hans de Goede
2025-06-05 17:53 ` [PATCH v2 08/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ORIENTATION Ricardo Ribalda
2025-06-29 17:50 ` Laurent Pinchart
2025-07-01 9:22 ` Ricardo Ribalda
2025-07-14 14:15 ` Hans de Goede
2025-07-14 14:23 ` Laurent Pinchart
2025-07-14 14:36 ` Hans de Goede
2025-06-05 17:53 ` [PATCH v2 09/12] media: uvcvideo: Add uvc_ctrl_query_entity helper Ricardo Ribalda
2025-06-29 18:01 ` Laurent Pinchart
2025-07-14 14:24 ` Hans de Goede
2025-07-14 15:51 ` Ricardo Ribalda
2025-06-05 17:53 ` [PATCH v2 10/12] media: uvcvideo: Add get_* functions to uvc_entity Ricardo Ribalda
2025-06-29 18:12 ` Laurent Pinchart
2025-07-01 11:13 ` Ricardo Ribalda
2025-07-14 14:28 ` Hans de Goede
2025-07-14 14:29 ` Laurent Pinchart
2025-07-14 15:46 ` Ricardo Ribalda
2025-07-15 19:35 ` Laurent Pinchart
2025-07-16 10:32 ` Ricardo Ribalda
2025-08-07 7:35 ` Ricardo Ribalda
2025-06-05 17:53 ` [PATCH v2 11/12] media: uvcvideo: Add support for V4L2_CID_CAMERA_ROTATION Ricardo Ribalda
2025-06-29 18:14 ` Laurent Pinchart
2025-07-01 11:26 ` Ricardo Ribalda
2025-07-14 14:31 ` Laurent Pinchart
2025-07-14 15:59 ` Ricardo Ribalda
2025-06-05 17:53 ` [PATCH v2 12/12] media: uvcvideo: Do not create MC entities for virtual entities Ricardo Ribalda
2025-06-29 18:05 ` Laurent Pinchart
2025-07-01 11:20 ` Ricardo Ribalda
2025-07-08 6:28 ` Ricardo Ribalda
2025-07-14 14:36 ` Laurent Pinchart
2025-07-14 16:04 ` Ricardo Ribalda
2025-07-14 16:30 ` Laurent Pinchart
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).