The media bus code passed to the .enum_frame_size() operation for the
sink pad is required to be supported by the device, but not to match the
current format. All entities that use the vsp1_subdev_enum_frame_size()
helper, as well as the SRU and UDS entities that implement the operation
manually, perform the check incorrectly.
Fix the issue by implementing the correct code check in the
vsp1_subdev_enum_frame_size(). For the SRU and UDS, to avoid duplicating
code, use the vsp1_subdev_enum_frame_size() as a base and override the
enumerated size on the source pad with entity-specific constraints.
While at it, include the missing <linux/mutex.h> as the code locks
mutexes.
Tested-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> # HiHope RZ/G2M
Link: https://patch.msgid.link/20260318235907.831556-4-laurent.pinchart+renesas@ideasonboard.com
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/gfp.h>
+#include <linux/mutex.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_state *state;
- struct v4l2_mbus_framefmt *format;
- int ret = 0;
- state = vsp1_entity_get_state(entity, sd_state, fse->which);
- if (!state)
+ if (fse->index)
return -EINVAL;
- format = v4l2_subdev_state_get_format(state, fse->pad);
+ if (fse->pad == 0) {
+ unsigned int i;
- mutex_lock(&entity->lock);
+ for (i = 0; i < entity->num_codes; ++i) {
+ if (fse->code == entity->codes[i])
+ break;
+ }
- if (fse->index || fse->code != format->code) {
- ret = -EINVAL;
- goto done;
- }
+ if (i == entity->num_codes)
+ return -EINVAL;
- if (fse->pad == 0) {
fse->min_width = entity->min_width;
fse->max_width = entity->max_width;
fse->min_height = entity->min_height;
fse->max_height = entity->max_height;
} else {
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *format;
+
+ state = vsp1_entity_get_state(entity, sd_state, fse->which);
+ if (!state)
+ return -EINVAL;
+
/*
- * The size on the source pad are fixed and always identical to
- * the size on the sink pad.
+ * The media bus code and size on the source pad are fixed and
+ * always identical to the sink pad.
*/
+ format = v4l2_subdev_state_get_format(state, 0);
+
+ guard(mutex)(&entity->lock);
+
+ if (fse->code != format->code)
+ return -EINVAL;
+
fse->min_width = format->width;
fse->max_width = format->width;
fse->min_height = format->height;
fse->max_height = format->height;
}
-done:
- mutex_unlock(&entity->lock);
- return ret;
+ return 0;
}
/*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/gfp.h>
+#include <linux/mutex.h>
#include <media/v4l2-subdev.h>
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_sru *sru = to_sru(subdev);
- struct v4l2_subdev_state *state;
- struct v4l2_mbus_framefmt *format;
- int ret = 0;
+ int ret;
- state = vsp1_entity_get_state(&sru->entity, sd_state, fse->which);
- if (!state)
- return -EINVAL;
+ ret = vsp1_subdev_enum_frame_size(subdev, sd_state, fse);
+ if (ret)
+ return ret;
- format = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ if (fse->pad == SRU_PAD_SOURCE) {
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *format;
- mutex_lock(&sru->entity.lock);
+ state = vsp1_entity_get_state(&sru->entity, sd_state,
+ fse->which);
+ if (!state)
+ return -EINVAL;
- if (fse->index || fse->code != format->code) {
- ret = -EINVAL;
- goto done;
- }
+ format = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+
+ guard(mutex)(&sru->entity.lock);
- if (fse->pad == SRU_PAD_SINK) {
- fse->min_width = SRU_MIN_SIZE;
- fse->max_width = SRU_MAX_SIZE;
- fse->min_height = SRU_MIN_SIZE;
- fse->max_height = SRU_MAX_SIZE;
- } else {
fse->min_width = format->width;
fse->min_height = format->height;
if (format->width <= SRU_MAX_SIZE / 2 &&
}
}
-done:
- mutex_unlock(&sru->entity.lock);
- return ret;
+ return 0;
}
static void sru_try_format(struct vsp1_sru *sru,
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/gfp.h>
+#include <linux/mutex.h>
#include <media/v4l2-subdev.h>
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_uds *uds = to_uds(subdev);
- struct v4l2_subdev_state *state;
- struct v4l2_mbus_framefmt *format;
- int ret = 0;
+ int ret;
- state = vsp1_entity_get_state(&uds->entity, sd_state, fse->which);
- if (!state)
- return -EINVAL;
+ ret = vsp1_subdev_enum_frame_size(subdev, sd_state, fse);
+ if (ret)
+ return ret;
- format = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ if (fse->pad == UDS_PAD_SOURCE) {
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *format;
- mutex_lock(&uds->entity.lock);
+ state = vsp1_entity_get_state(&uds->entity, sd_state,
+ fse->which);
+ if (!state)
+ return -EINVAL;
- if (fse->index || fse->code != format->code) {
- ret = -EINVAL;
- goto done;
- }
+ format = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+
+ guard(mutex)(&uds->entity.lock);
- if (fse->pad == UDS_PAD_SINK) {
- fse->min_width = UDS_MIN_SIZE;
- fse->max_width = UDS_MAX_SIZE;
- fse->min_height = UDS_MIN_SIZE;
- fse->max_height = UDS_MAX_SIZE;
- } else {
uds_output_limits(format->width, &fse->min_width,
&fse->max_width);
uds_output_limits(format->height, &fse->min_height,
&fse->max_height);
}
-done:
- mutex_unlock(&uds->entity.lock);
- return ret;
+ return 0;
}
static void uds_try_format(struct vsp1_uds *uds,