Moi, Thanks for the patch. On Thu, Apr 04, 2024 at 01:50:02PM +0300, Tomi Valkeinen wrote: > v4l2_subdev_enable/disable_streams_fallback() supports falling back to > .s_stream() for subdevs with a single source pad. It also tracks the > enabled streams for that one pad in the sd->enabled_streams field. > > Tracking the enabled streams with sd->enabled_streams does not make > sense, as with .s_stream() there can only be a single stream per pad. > Thus, as the v4l2_subdev_enable/disable_streams_fallback() only supports > a single source pad, all we really need is a boolean which tells whether > streaming has been enabled on this pad or not. > > However, as we only need a true/false state for a pad (instead of > tracking which streams have been enabled for a pad), we can easily > extend the fallback mechanism to support multiple source pads as we only > need to keep track of which pads have been enabled. > > Change the sd->enabled_streams field to sd->enabled_pads, which is a > 64-bit bitmask tracking the enabled source pads. With this change we can > remove the restriction that > v4l2_subdev_enable/disable_streams_fallback() only supports a single > soruce pad. > > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx> > --- > drivers/media/v4l2-core/v4l2-subdev.c | 68 ++++++++++++++++++++--------------- > include/media/v4l2-subdev.h | 9 +++-- > 2 files changed, 44 insertions(+), 33 deletions(-) > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c > index 3b3310bce5d4..91298bb84e6b 100644 > --- a/drivers/media/v4l2-core/v4l2-subdev.c > +++ b/drivers/media/v4l2-core/v4l2-subdev.c > @@ -2090,37 +2090,43 @@ static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad, > u64 streams_mask) > { > struct device *dev = sd->entity.graph_obj.mdev->dev; > - unsigned int i; > int ret; > > /* > * The subdev doesn't implement pad-based stream enable, fall back > - * on the .s_stream() operation. This can only be done for subdevs that > - * have a single source pad, as sd->enabled_streams is global to the > - * subdev. > + * on the .s_stream() operation. > */ > if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) > return -EOPNOTSUPP; > > - for (i = 0; i < sd->entity.num_pads; ++i) { > - if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) > - return -EOPNOTSUPP; > - } > + /* > + * .s_stream() means there is no streams support, so only allowed stream > + * is the imlicit stream 0. > + */ > + if (streams_mask != BIT_ULL(0)) > + return -EOPNOTSUPP; > + > + /* > + * We use a 64-bit bitmask for tracking enabled pads, so only subdevices > + * with 64 pads or less can be supported. > + */ > + if (pad >= sizeof(sd->enabled_pads) * 8) s/8/BITS_PER_BYTE/ > + return -EOPNOTSUPP; > > - if (sd->enabled_streams & streams_mask) { > - dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n", > - streams_mask, sd->entity.name, pad); > + if (sd->enabled_pads & BIT_ULL(pad)) { > + dev_dbg(dev, "pad %u already enabled on %s\n", > + pad, sd->entity.name); > return -EALREADY; > } > > - /* Start streaming when the first streams are enabled. */ > - if (!sd->enabled_streams) { > + /* Start streaming when the first pad is enabled. */ > + if (!sd->enabled_pads) { > ret = v4l2_subdev_call(sd, video, s_stream, 1); > if (ret) > return ret; > } > > - sd->enabled_streams |= streams_mask; > + sd->enabled_pads |= BIT_ULL(pad); > > return 0; > } > @@ -2207,37 +2213,43 @@ static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad, > u64 streams_mask) > { > struct device *dev = sd->entity.graph_obj.mdev->dev; > - unsigned int i; > int ret; > > /* > - * If the subdev doesn't implement pad-based stream enable, fall back > - * on the .s_stream() operation. This can only be done for subdevs that > - * have a single source pad, as sd->enabled_streams is global to the > - * subdev. > + * If the subdev doesn't implement pad-based stream enable, fall back > + * on the .s_stream() operation. > */ > if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) > return -EOPNOTSUPP; > > - for (i = 0; i < sd->entity.num_pads; ++i) { > - if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) > - return -EOPNOTSUPP; > - } > + /* > + * .s_stream() means there is no streams support, so only allowed stream > + * is the imlicit stream 0. > + */ > + if (streams_mask != BIT_ULL(0)) > + return -EOPNOTSUPP; > + > + /* > + * We use a 64-bit bitmask for tracking enabled pads, so only subdevices > + * with 64 pads or less can be supported. > + */ > + if (pad >= sizeof(sd->enabled_pads) * 8) Ditto. How much of the code of the two functions is the same? Could some of this be put to a common function both would call? They look (almost) exactly the same. > + return -EOPNOTSUPP; > > - if ((sd->enabled_streams & streams_mask) != streams_mask) { > - dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n", > - streams_mask, sd->entity.name, pad); > + if ((sd->enabled_pads & BIT_ULL(pad)) != BIT_ULL(pad)) { > + dev_dbg(dev, "pad %u already disabled on %s\n", > + pad, sd->entity.name); > return -EALREADY; > } > > /* Stop streaming when the last streams are disabled. */ > - if (!(sd->enabled_streams & ~streams_mask)) { > + if (!(sd->enabled_pads & ~BIT_ULL(pad))) { > ret = v4l2_subdev_call(sd, video, s_stream, 0); > if (ret) > return ret; > } > > - sd->enabled_streams &= ~streams_mask; > + sd->enabled_pads &= ~BIT_ULL(pad); > > return 0; > } > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h > index 8bd1e3c96d2b..7077aec3176c 100644 > --- a/include/media/v4l2-subdev.h > +++ b/include/media/v4l2-subdev.h > @@ -1039,10 +1039,9 @@ struct v4l2_subdev_platform_data { > * @active_state: Active state for the subdev (NULL for subdevs tracking the > * state internally). Initialized by calling > * v4l2_subdev_init_finalize(). > - * @enabled_streams: Bitmask of enabled streams used by > - * v4l2_subdev_enable_streams() and > - * v4l2_subdev_disable_streams() helper functions for fallback > - * cases. > + * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams() > + * and v4l2_subdev_disable_streams() helper functions for > + * fallback cases. > * @streaming_enabled: Tracks whether streaming has been enabled with s_stream. > * > * Each instance of a subdev driver should create this struct, either > @@ -1091,7 +1090,7 @@ struct v4l2_subdev { > * doesn't support it. > */ > struct v4l2_subdev_state *active_state; > - u64 enabled_streams; > + u64 enabled_pads; > bool streaming_enabled; > }; > > -- Kind regards, Sakari Ailus