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. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> --- Changes since v1: - Include <linux/cleanup.h> and <linux/mutex.h> --- .../media/platform/renesas/vsp1/vsp1_entity.c | 49 ++++++++++++------- .../media/platform/renesas/vsp1/vsp1_sru.c | 38 +++++++------- .../media/platform/renesas/vsp1/vsp1_uds.c | 38 +++++++------- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 04b7ae6fb935..892a2adfdf3a 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -7,8 +7,10 @@ * Contact: Laurent Pinchart (laurent.pinchart@xxxxxxxxxxxxxxxx) */ +#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> @@ -238,42 +240,51 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, 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); - - mutex_lock(&entity->lock); - - if (fse->index || fse->code != format->code) { - ret = -EINVAL; - goto done; - } - if (fse->pad == 0) { + unsigned int i; + + for (i = 0; i < entity->num_codes; ++i) { + if (fse->code == entity->codes[i]) + break; + } + + if (i == entity->num_codes) + return -EINVAL; + 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; } /* diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c index 1dc34e6a510d..37fd36d09045 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c @@ -7,8 +7,10 @@ * Contact: Laurent Pinchart (laurent.pinchart@xxxxxxxxxxxxxxxx) */ +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/gfp.h> +#include <linux/mutex.h> #include <media/v4l2-subdev.h> @@ -116,29 +118,25 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, 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 && @@ -151,9 +149,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, } } -done: - mutex_unlock(&sru->entity.lock); - return ret; + return 0; } static void sru_try_format(struct vsp1_sru *sru, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c index 8006d49ffbea..dd4722315c56 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c @@ -7,8 +7,10 @@ * Contact: Laurent Pinchart (laurent.pinchart@xxxxxxxxxxxxxxxx) */ +#include <linux/cleanup.h> #include <linux/device.h> #include <linux/gfp.h> +#include <linux/mutex.h> #include <media/v4l2-subdev.h> @@ -121,38 +123,32 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, 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, -- Regards, Laurent Pinchart