{
int ret;
+ /*
+ * The .s_stream() operation must never be called to start or stop an
+ * already started or stopped subdev. Catch offenders but don't return
+ * an error yet to avoid regressions.
+ *
+ * As .s_stream() is mutually exclusive with the .enable_streams() and
+ * .disable_streams() operation, we can use the enabled_streams field
+ * to store the subdev streaming state.
+ */
+ if (WARN_ON(!!sd->enabled_streams == !!enable))
+ return 0;
+
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
if (enable)
if (!enable && ret < 0) {
dev_warn(sd->dev, "disabling streaming failed (%d)\n", ret);
- return 0;
+ ret = 0;
}
+ if (!ret)
+ sd->enabled_streams = enable ? BIT(0) : 0;
+
return ret;
}
* @s_stream: start (enabled == 1) or stop (enabled == 0) streaming on the
* sub-device. Failure on stop will remove any resources acquired in
* streaming start, while the error code is still returned by the driver.
- * Also see call_s_stream wrapper in v4l2-subdev.c.
+ * The caller shall track the subdev state, and shall not start or stop an
+ * already started or stopped subdev. Also see call_s_stream wrapper in
+ * v4l2-subdev.c.
*
* @g_pixelaspect: callback to return the pixelaspect ratio.
*