18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * vivid-kthread-out.h - video/vbi output thread support functions.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/errno.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/sched.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/font.h>
158c2ecf20Sopenharmony_ci#include <linux/mutex.h>
168c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
178c2ecf20Sopenharmony_ci#include <linux/kthread.h>
188c2ecf20Sopenharmony_ci#include <linux/freezer.h>
198c2ecf20Sopenharmony_ci#include <linux/random.h>
208c2ecf20Sopenharmony_ci#include <linux/v4l2-dv-timings.h>
218c2ecf20Sopenharmony_ci#include <asm/div64.h>
228c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h>
238c2ecf20Sopenharmony_ci#include <media/v4l2-dv-timings.h>
248c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h>
258c2ecf20Sopenharmony_ci#include <media/v4l2-fh.h>
268c2ecf20Sopenharmony_ci#include <media/v4l2-event.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "vivid-core.h"
298c2ecf20Sopenharmony_ci#include "vivid-vid-common.h"
308c2ecf20Sopenharmony_ci#include "vivid-vid-cap.h"
318c2ecf20Sopenharmony_ci#include "vivid-vid-out.h"
328c2ecf20Sopenharmony_ci#include "vivid-radio-common.h"
338c2ecf20Sopenharmony_ci#include "vivid-radio-rx.h"
348c2ecf20Sopenharmony_ci#include "vivid-radio-tx.h"
358c2ecf20Sopenharmony_ci#include "vivid-sdr-cap.h"
368c2ecf20Sopenharmony_ci#include "vivid-vbi-cap.h"
378c2ecf20Sopenharmony_ci#include "vivid-vbi-out.h"
388c2ecf20Sopenharmony_ci#include "vivid-osd.h"
398c2ecf20Sopenharmony_ci#include "vivid-ctrls.h"
408c2ecf20Sopenharmony_ci#include "vivid-kthread-out.h"
418c2ecf20Sopenharmony_ci#include "vivid-meta-out.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void vivid_thread_vid_out_tick(struct vivid_dev *dev)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct vivid_buffer *vid_out_buf = NULL;
468c2ecf20Sopenharmony_ci	struct vivid_buffer *vbi_out_buf = NULL;
478c2ecf20Sopenharmony_ci	struct vivid_buffer *meta_out_buf = NULL;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	dprintk(dev, 1, "Video Output Thread Tick\n");
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Drop a certain percentage of buffers. */
528c2ecf20Sopenharmony_ci	if (dev->perc_dropped_buffers &&
538c2ecf20Sopenharmony_ci	    prandom_u32_max(100) < dev->perc_dropped_buffers)
548c2ecf20Sopenharmony_ci		return;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	spin_lock(&dev->slock);
578c2ecf20Sopenharmony_ci	/*
588c2ecf20Sopenharmony_ci	 * Only dequeue buffer if there is at least one more pending.
598c2ecf20Sopenharmony_ci	 * This makes video loopback possible.
608c2ecf20Sopenharmony_ci	 */
618c2ecf20Sopenharmony_ci	if (!list_empty(&dev->vid_out_active) &&
628c2ecf20Sopenharmony_ci	    !list_is_singular(&dev->vid_out_active)) {
638c2ecf20Sopenharmony_ci		vid_out_buf = list_entry(dev->vid_out_active.next,
648c2ecf20Sopenharmony_ci					 struct vivid_buffer, list);
658c2ecf20Sopenharmony_ci		list_del(&vid_out_buf->list);
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci	if (!list_empty(&dev->vbi_out_active) &&
688c2ecf20Sopenharmony_ci	    (dev->field_out != V4L2_FIELD_ALTERNATE ||
698c2ecf20Sopenharmony_ci	     (dev->vbi_out_seq_count & 1))) {
708c2ecf20Sopenharmony_ci		vbi_out_buf = list_entry(dev->vbi_out_active.next,
718c2ecf20Sopenharmony_ci					 struct vivid_buffer, list);
728c2ecf20Sopenharmony_ci		list_del(&vbi_out_buf->list);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci	if (!list_empty(&dev->meta_out_active)) {
758c2ecf20Sopenharmony_ci		meta_out_buf = list_entry(dev->meta_out_active.next,
768c2ecf20Sopenharmony_ci					  struct vivid_buffer, list);
778c2ecf20Sopenharmony_ci		list_del(&meta_out_buf->list);
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	spin_unlock(&dev->slock);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (!vid_out_buf && !vbi_out_buf && !meta_out_buf)
828c2ecf20Sopenharmony_ci		return;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (vid_out_buf) {
858c2ecf20Sopenharmony_ci		v4l2_ctrl_request_setup(vid_out_buf->vb.vb2_buf.req_obj.req,
868c2ecf20Sopenharmony_ci					&dev->ctrl_hdl_vid_out);
878c2ecf20Sopenharmony_ci		v4l2_ctrl_request_complete(vid_out_buf->vb.vb2_buf.req_obj.req,
888c2ecf20Sopenharmony_ci					   &dev->ctrl_hdl_vid_out);
898c2ecf20Sopenharmony_ci		vid_out_buf->vb.sequence = dev->vid_out_seq_count;
908c2ecf20Sopenharmony_ci		if (dev->field_out == V4L2_FIELD_ALTERNATE) {
918c2ecf20Sopenharmony_ci			/*
928c2ecf20Sopenharmony_ci			 * The sequence counter counts frames, not fields.
938c2ecf20Sopenharmony_ci			 * So divide by two.
948c2ecf20Sopenharmony_ci			 */
958c2ecf20Sopenharmony_ci			vid_out_buf->vb.sequence /= 2;
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci		vid_out_buf->vb.vb2_buf.timestamp =
988c2ecf20Sopenharmony_ci			ktime_get_ns() + dev->time_wrap_offset;
998c2ecf20Sopenharmony_ci		vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ?
1008c2ecf20Sopenharmony_ci				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
1018c2ecf20Sopenharmony_ci		dprintk(dev, 2, "vid_out buffer %d done\n",
1028c2ecf20Sopenharmony_ci			vid_out_buf->vb.vb2_buf.index);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (vbi_out_buf) {
1068c2ecf20Sopenharmony_ci		v4l2_ctrl_request_setup(vbi_out_buf->vb.vb2_buf.req_obj.req,
1078c2ecf20Sopenharmony_ci					&dev->ctrl_hdl_vbi_out);
1088c2ecf20Sopenharmony_ci		v4l2_ctrl_request_complete(vbi_out_buf->vb.vb2_buf.req_obj.req,
1098c2ecf20Sopenharmony_ci					   &dev->ctrl_hdl_vbi_out);
1108c2ecf20Sopenharmony_ci		if (dev->stream_sliced_vbi_out)
1118c2ecf20Sopenharmony_ci			vivid_sliced_vbi_out_process(dev, vbi_out_buf);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		vbi_out_buf->vb.sequence = dev->vbi_out_seq_count;
1148c2ecf20Sopenharmony_ci		vbi_out_buf->vb.vb2_buf.timestamp =
1158c2ecf20Sopenharmony_ci			ktime_get_ns() + dev->time_wrap_offset;
1168c2ecf20Sopenharmony_ci		vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ?
1178c2ecf20Sopenharmony_ci				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
1188c2ecf20Sopenharmony_ci		dprintk(dev, 2, "vbi_out buffer %d done\n",
1198c2ecf20Sopenharmony_ci			vbi_out_buf->vb.vb2_buf.index);
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci	if (meta_out_buf) {
1228c2ecf20Sopenharmony_ci		v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req,
1238c2ecf20Sopenharmony_ci					&dev->ctrl_hdl_meta_out);
1248c2ecf20Sopenharmony_ci		v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req,
1258c2ecf20Sopenharmony_ci					   &dev->ctrl_hdl_meta_out);
1268c2ecf20Sopenharmony_ci		vivid_meta_out_process(dev, meta_out_buf);
1278c2ecf20Sopenharmony_ci		meta_out_buf->vb.sequence = dev->meta_out_seq_count;
1288c2ecf20Sopenharmony_ci		meta_out_buf->vb.vb2_buf.timestamp =
1298c2ecf20Sopenharmony_ci			ktime_get_ns() + dev->time_wrap_offset;
1308c2ecf20Sopenharmony_ci		vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ?
1318c2ecf20Sopenharmony_ci				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
1328c2ecf20Sopenharmony_ci		dprintk(dev, 2, "meta_out buffer %d done\n",
1338c2ecf20Sopenharmony_ci			meta_out_buf->vb.vb2_buf.index);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	dev->dqbuf_error = false;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int vivid_thread_vid_out(void *data)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct vivid_dev *dev = data;
1428c2ecf20Sopenharmony_ci	u64 numerators_since_start;
1438c2ecf20Sopenharmony_ci	u64 buffers_since_start;
1448c2ecf20Sopenharmony_ci	u64 next_jiffies_since_start;
1458c2ecf20Sopenharmony_ci	unsigned long jiffies_since_start;
1468c2ecf20Sopenharmony_ci	unsigned long cur_jiffies;
1478c2ecf20Sopenharmony_ci	unsigned wait_jiffies;
1488c2ecf20Sopenharmony_ci	unsigned numerator;
1498c2ecf20Sopenharmony_ci	unsigned denominator;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	dprintk(dev, 1, "Video Output Thread Start\n");
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	set_freezable();
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* Resets frame counters */
1568c2ecf20Sopenharmony_ci	dev->out_seq_offset = 0;
1578c2ecf20Sopenharmony_ci	if (dev->seq_wrap)
1588c2ecf20Sopenharmony_ci		dev->out_seq_count = 0xffffff80U;
1598c2ecf20Sopenharmony_ci	dev->jiffies_vid_out = jiffies;
1608c2ecf20Sopenharmony_ci	dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
1618c2ecf20Sopenharmony_ci	dev->meta_out_seq_start = 0;
1628c2ecf20Sopenharmony_ci	dev->out_seq_resync = false;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	for (;;) {
1658c2ecf20Sopenharmony_ci		try_to_freeze();
1668c2ecf20Sopenharmony_ci		if (kthread_should_stop())
1678c2ecf20Sopenharmony_ci			break;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		if (!mutex_trylock(&dev->mutex)) {
1708c2ecf20Sopenharmony_ci			schedule_timeout_uninterruptible(1);
1718c2ecf20Sopenharmony_ci			continue;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		cur_jiffies = jiffies;
1758c2ecf20Sopenharmony_ci		if (dev->out_seq_resync) {
1768c2ecf20Sopenharmony_ci			dev->jiffies_vid_out = cur_jiffies;
1778c2ecf20Sopenharmony_ci			dev->out_seq_offset = dev->out_seq_count + 1;
1788c2ecf20Sopenharmony_ci			dev->out_seq_count = 0;
1798c2ecf20Sopenharmony_ci			dev->out_seq_resync = false;
1808c2ecf20Sopenharmony_ci		}
1818c2ecf20Sopenharmony_ci		numerator = dev->timeperframe_vid_out.numerator;
1828c2ecf20Sopenharmony_ci		denominator = dev->timeperframe_vid_out.denominator;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		if (dev->field_out == V4L2_FIELD_ALTERNATE)
1858c2ecf20Sopenharmony_ci			denominator *= 2;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		/* Calculate the number of jiffies since we started streaming */
1888c2ecf20Sopenharmony_ci		jiffies_since_start = cur_jiffies - dev->jiffies_vid_out;
1898c2ecf20Sopenharmony_ci		/* Get the number of buffers streamed since the start */
1908c2ecf20Sopenharmony_ci		buffers_since_start = (u64)jiffies_since_start * denominator +
1918c2ecf20Sopenharmony_ci				      (HZ * numerator) / 2;
1928c2ecf20Sopenharmony_ci		do_div(buffers_since_start, HZ * numerator);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		/*
1958c2ecf20Sopenharmony_ci		 * After more than 0xf0000000 (rounded down to a multiple of
1968c2ecf20Sopenharmony_ci		 * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
1978c2ecf20Sopenharmony_ci		 * jiffies have passed since we started streaming reset the
1988c2ecf20Sopenharmony_ci		 * counters and keep track of the sequence offset.
1998c2ecf20Sopenharmony_ci		 */
2008c2ecf20Sopenharmony_ci		if (jiffies_since_start > JIFFIES_RESYNC) {
2018c2ecf20Sopenharmony_ci			dev->jiffies_vid_out = cur_jiffies;
2028c2ecf20Sopenharmony_ci			dev->out_seq_offset = buffers_since_start;
2038c2ecf20Sopenharmony_ci			buffers_since_start = 0;
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci		dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
2068c2ecf20Sopenharmony_ci		dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
2078c2ecf20Sopenharmony_ci		dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
2088c2ecf20Sopenharmony_ci		dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		vivid_thread_vid_out_tick(dev);
2118c2ecf20Sopenharmony_ci		mutex_unlock(&dev->mutex);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		/*
2148c2ecf20Sopenharmony_ci		 * Calculate the number of 'numerators' streamed since we started,
2158c2ecf20Sopenharmony_ci		 * not including the current buffer.
2168c2ecf20Sopenharmony_ci		 */
2178c2ecf20Sopenharmony_ci		numerators_since_start = buffers_since_start * numerator;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci		/* And the number of jiffies since we started */
2208c2ecf20Sopenharmony_ci		jiffies_since_start = jiffies - dev->jiffies_vid_out;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		/* Increase by the 'numerator' of one buffer */
2238c2ecf20Sopenharmony_ci		numerators_since_start += numerator;
2248c2ecf20Sopenharmony_ci		/*
2258c2ecf20Sopenharmony_ci		 * Calculate when that next buffer is supposed to start
2268c2ecf20Sopenharmony_ci		 * in jiffies since we started streaming.
2278c2ecf20Sopenharmony_ci		 */
2288c2ecf20Sopenharmony_ci		next_jiffies_since_start = numerators_since_start * HZ +
2298c2ecf20Sopenharmony_ci					   denominator / 2;
2308c2ecf20Sopenharmony_ci		do_div(next_jiffies_since_start, denominator);
2318c2ecf20Sopenharmony_ci		/* If it is in the past, then just schedule asap */
2328c2ecf20Sopenharmony_ci		if (next_jiffies_since_start < jiffies_since_start)
2338c2ecf20Sopenharmony_ci			next_jiffies_since_start = jiffies_since_start;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		wait_jiffies = next_jiffies_since_start - jiffies_since_start;
2368c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	dprintk(dev, 1, "Video Output Thread End\n");
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void vivid_grab_controls(struct vivid_dev *dev, bool grab)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab);
2458c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab);
2468c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab);
2478c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(dev->ctrl_tx_mode, grab);
2488c2ecf20Sopenharmony_ci	v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciint vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	dprintk(dev, 1, "%s\n", __func__);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (dev->kthread_vid_out) {
2568c2ecf20Sopenharmony_ci		u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		if (pstreaming == &dev->vid_out_streaming)
2598c2ecf20Sopenharmony_ci			dev->vid_out_seq_start = seq_count;
2608c2ecf20Sopenharmony_ci		else if (pstreaming == &dev->vbi_out_streaming)
2618c2ecf20Sopenharmony_ci			dev->vbi_out_seq_start = seq_count;
2628c2ecf20Sopenharmony_ci		else
2638c2ecf20Sopenharmony_ci			dev->meta_out_seq_start = seq_count;
2648c2ecf20Sopenharmony_ci		*pstreaming = true;
2658c2ecf20Sopenharmony_ci		return 0;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* Resets frame counters */
2698c2ecf20Sopenharmony_ci	dev->jiffies_vid_out = jiffies;
2708c2ecf20Sopenharmony_ci	dev->vid_out_seq_start = dev->seq_wrap * 128;
2718c2ecf20Sopenharmony_ci	dev->vbi_out_seq_start = dev->seq_wrap * 128;
2728c2ecf20Sopenharmony_ci	dev->meta_out_seq_start = dev->seq_wrap * 128;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
2758c2ecf20Sopenharmony_ci			"%s-vid-out", dev->v4l2_dev.name);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (IS_ERR(dev->kthread_vid_out)) {
2788c2ecf20Sopenharmony_ci		int err = PTR_ERR(dev->kthread_vid_out);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		dev->kthread_vid_out = NULL;
2818c2ecf20Sopenharmony_ci		v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
2828c2ecf20Sopenharmony_ci		return err;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci	*pstreaming = true;
2858c2ecf20Sopenharmony_ci	vivid_grab_controls(dev, true);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	dprintk(dev, 1, "returning from %s\n", __func__);
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_civoid vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	dprintk(dev, 1, "%s\n", __func__);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (dev->kthread_vid_out == NULL)
2968c2ecf20Sopenharmony_ci		return;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	*pstreaming = false;
2998c2ecf20Sopenharmony_ci	if (pstreaming == &dev->vid_out_streaming) {
3008c2ecf20Sopenharmony_ci		/* Release all active buffers */
3018c2ecf20Sopenharmony_ci		while (!list_empty(&dev->vid_out_active)) {
3028c2ecf20Sopenharmony_ci			struct vivid_buffer *buf;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci			buf = list_entry(dev->vid_out_active.next,
3058c2ecf20Sopenharmony_ci					 struct vivid_buffer, list);
3068c2ecf20Sopenharmony_ci			list_del(&buf->list);
3078c2ecf20Sopenharmony_ci			v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
3088c2ecf20Sopenharmony_ci						   &dev->ctrl_hdl_vid_out);
3098c2ecf20Sopenharmony_ci			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
3108c2ecf20Sopenharmony_ci			dprintk(dev, 2, "vid_out buffer %d done\n",
3118c2ecf20Sopenharmony_ci				buf->vb.vb2_buf.index);
3128c2ecf20Sopenharmony_ci		}
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	if (pstreaming == &dev->vbi_out_streaming) {
3168c2ecf20Sopenharmony_ci		while (!list_empty(&dev->vbi_out_active)) {
3178c2ecf20Sopenharmony_ci			struct vivid_buffer *buf;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci			buf = list_entry(dev->vbi_out_active.next,
3208c2ecf20Sopenharmony_ci					 struct vivid_buffer, list);
3218c2ecf20Sopenharmony_ci			list_del(&buf->list);
3228c2ecf20Sopenharmony_ci			v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
3238c2ecf20Sopenharmony_ci						   &dev->ctrl_hdl_vbi_out);
3248c2ecf20Sopenharmony_ci			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
3258c2ecf20Sopenharmony_ci			dprintk(dev, 2, "vbi_out buffer %d done\n",
3268c2ecf20Sopenharmony_ci				buf->vb.vb2_buf.index);
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (pstreaming == &dev->meta_out_streaming) {
3318c2ecf20Sopenharmony_ci		while (!list_empty(&dev->meta_out_active)) {
3328c2ecf20Sopenharmony_ci			struct vivid_buffer *buf;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci			buf = list_entry(dev->meta_out_active.next,
3358c2ecf20Sopenharmony_ci					 struct vivid_buffer, list);
3368c2ecf20Sopenharmony_ci			list_del(&buf->list);
3378c2ecf20Sopenharmony_ci			v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
3388c2ecf20Sopenharmony_ci						   &dev->ctrl_hdl_meta_out);
3398c2ecf20Sopenharmony_ci			vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
3408c2ecf20Sopenharmony_ci			dprintk(dev, 2, "meta_out buffer %d done\n",
3418c2ecf20Sopenharmony_ci				buf->vb.vb2_buf.index);
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (dev->vid_out_streaming || dev->vbi_out_streaming ||
3468c2ecf20Sopenharmony_ci	    dev->meta_out_streaming)
3478c2ecf20Sopenharmony_ci		return;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/* shutdown control thread */
3508c2ecf20Sopenharmony_ci	vivid_grab_controls(dev, false);
3518c2ecf20Sopenharmony_ci	kthread_stop(dev->kthread_vid_out);
3528c2ecf20Sopenharmony_ci	dev->kthread_vid_out = NULL;
3538c2ecf20Sopenharmony_ci}
354