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