^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * vimc-streamer.c Virtual Media Controller Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018 Lucas A. M. Magalhães <lucmaga@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/freezer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kthread.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "vimc-streamer.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * vimc_get_source_entity - get the entity connected with the first sink pad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * @ent: reference media_entity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * Helper function that returns the media entity containing the source pad
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * linked with the first sink pad from the given media entity pad list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Return: The source pad or NULL, if it wasn't found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct media_pad *pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) for (i = 0; i < ent->num_pads; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) pad = media_entity_remote_pad(&ent->pads[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return pad ? pad->entity : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * @stream: the pointer to the stream structure with the pipeline to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Calls s_stream to disable the stream in each entity of the pipeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct vimc_ent_device *ved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct v4l2_subdev *sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) while (stream->pipe_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) stream->pipe_size--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ved = stream->ved_pipeline[stream->pipe_size];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) stream->ved_pipeline[stream->pipe_size] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (!is_media_entity_v4l2_subdev(ved->ent))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) sd = media_entity_to_v4l2_subdev(ved->ent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) v4l2_subdev_call(sd, video, s_stream, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * vimc_streamer_pipeline_init - Initializes the stream structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * @stream: the pointer to the stream structure to be initialized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * @ved: the pointer to the vimc entity initializing the stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Initializes the stream structure. Walks through the entity graph to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * construct the pipeline used later on the streamer thread.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Calls vimc_streamer_s_stream() to enable stream in all entities of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * the pipeline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * Return: 0 if success, error code otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct vimc_ent_device *ved)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct media_entity *entity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct video_device *vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct v4l2_subdev *sd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) stream->pipe_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (!ved) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) stream->ved_pipeline[stream->pipe_size++] = ved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (is_media_entity_v4l2_subdev(ved->ent)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) sd = media_entity_to_v4l2_subdev(ved->ent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) ret = v4l2_subdev_call(sd, video, s_stream, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (ret && ret != -ENOIOCTLCMD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) dev_err(ved->dev, "subdev_call error %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ved->ent->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) entity = vimc_get_source_entity(ved->ent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* Check if the end of the pipeline was reached */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!entity) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) /* the first entity of the pipe should be source only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!vimc_is_source(ved->ent)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) dev_err(ved->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) "first entity in the pipe '%s' is not a source\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) ved->ent->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EPIPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Get the next device in the pipeline */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (is_media_entity_v4l2_subdev(entity)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) sd = media_entity_to_v4l2_subdev(entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ved = v4l2_get_subdevdata(sd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) vdev = container_of(entity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct video_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) entity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ved = video_get_drvdata(vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * vimc_streamer_thread - Process frames through the pipeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @data: vimc_stream struct of the current stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * From the source to the sink, gets a frame from each subdevice and send to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * the next one of the pipeline at a fixed framerate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * Return:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * Always zero (created as ``int`` instead of ``void`` to comply with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * kthread API).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int vimc_streamer_thread(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct vimc_stream *stream = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) u8 *frame = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) set_freezable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) try_to_freeze();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (kthread_should_stop())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) for (i = stream->pipe_size - 1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) frame = stream->ved_pipeline[i]->process_frame(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) stream->ved_pipeline[i], frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!frame || IS_ERR(frame))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) //wait for 60hz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) set_current_state(TASK_UNINTERRUPTIBLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) schedule_timeout(HZ / 60);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * vimc_streamer_s_stream - Start/stop the streaming on the media pipeline
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * @stream: the pointer to the stream structure of the current stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * @ved: pointer to the vimc entity of the entity of the stream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * @enable: flag to determine if stream should start/stop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * When starting, check if there is no ``stream->kthread`` allocated. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * should indicate that a stream is already running. Then, it initializes the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * pipeline, creates and runs a kthread to consume buffers through the pipeline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * When stopping, analogously check if there is a stream running, stop the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * thread and terminates the pipeline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * Return: 0 if success, error code otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int vimc_streamer_s_stream(struct vimc_stream *stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct vimc_ent_device *ved,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) int enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (!stream || !ved)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (stream->kthread)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) ret = vimc_streamer_pipeline_init(stream, ved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) stream->kthread = kthread_run(vimc_streamer_thread, stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) "vimc-streamer thread");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (IS_ERR(stream->kthread)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) ret = PTR_ERR(stream->kthread);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) dev_err(ved->dev, "kthread_run failed with %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) stream->kthread = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!stream->kthread)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = kthread_stop(stream->kthread);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * kthread_stop returns -EINTR in cases when streamon was
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * immediately followed by streamoff, and the thread didn't had
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * a chance to run. Ignore errors to stop the stream in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * pipeline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) stream->kthread = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) vimc_streamer_pipeline_terminate(stream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }