1dacca5f0SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only
2dacca5f0SHans Verkuil /*
3dacca5f0SHans Verkuil * vivid-kthread-out.h - video/vbi output thread support functions.
4dacca5f0SHans Verkuil *
5dacca5f0SHans Verkuil * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6dacca5f0SHans Verkuil */
7dacca5f0SHans Verkuil
8dacca5f0SHans Verkuil #include <linux/module.h>
9dacca5f0SHans Verkuil #include <linux/errno.h>
10dacca5f0SHans Verkuil #include <linux/kernel.h>
11dacca5f0SHans Verkuil #include <linux/init.h>
12dacca5f0SHans Verkuil #include <linux/sched.h>
13dacca5f0SHans Verkuil #include <linux/slab.h>
14dacca5f0SHans Verkuil #include <linux/font.h>
15dacca5f0SHans Verkuil #include <linux/mutex.h>
16dacca5f0SHans Verkuil #include <linux/videodev2.h>
17dacca5f0SHans Verkuil #include <linux/kthread.h>
18dacca5f0SHans Verkuil #include <linux/freezer.h>
19dacca5f0SHans Verkuil #include <linux/random.h>
20dacca5f0SHans Verkuil #include <linux/v4l2-dv-timings.h>
2184db51f5SWang Qing #include <linux/jiffies.h>
22dacca5f0SHans Verkuil #include <asm/div64.h>
23dacca5f0SHans Verkuil #include <media/videobuf2-vmalloc.h>
24dacca5f0SHans Verkuil #include <media/v4l2-dv-timings.h>
25dacca5f0SHans Verkuil #include <media/v4l2-ioctl.h>
26dacca5f0SHans Verkuil #include <media/v4l2-fh.h>
27dacca5f0SHans Verkuil #include <media/v4l2-event.h>
28dacca5f0SHans Verkuil
29dacca5f0SHans Verkuil #include "vivid-core.h"
30dacca5f0SHans Verkuil #include "vivid-vid-common.h"
31dacca5f0SHans Verkuil #include "vivid-vid-cap.h"
32dacca5f0SHans Verkuil #include "vivid-vid-out.h"
33dacca5f0SHans Verkuil #include "vivid-radio-common.h"
34dacca5f0SHans Verkuil #include "vivid-radio-rx.h"
35dacca5f0SHans Verkuil #include "vivid-radio-tx.h"
36dacca5f0SHans Verkuil #include "vivid-sdr-cap.h"
37dacca5f0SHans Verkuil #include "vivid-vbi-cap.h"
38dacca5f0SHans Verkuil #include "vivid-vbi-out.h"
39dacca5f0SHans Verkuil #include "vivid-osd.h"
40dacca5f0SHans Verkuil #include "vivid-ctrls.h"
41dacca5f0SHans Verkuil #include "vivid-kthread-out.h"
42dacca5f0SHans Verkuil #include "vivid-meta-out.h"
43dacca5f0SHans Verkuil
vivid_thread_vid_out_tick(struct vivid_dev * dev)44dacca5f0SHans Verkuil static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
45dacca5f0SHans Verkuil {
46dacca5f0SHans Verkuil struct vivid_buffer *vid_out_buf = NULL;
47dacca5f0SHans Verkuil struct vivid_buffer *vbi_out_buf = NULL;
48dacca5f0SHans Verkuil struct vivid_buffer *meta_out_buf = NULL;
49dacca5f0SHans Verkuil
50dacca5f0SHans Verkuil dprintk(dev, 1, "Video Output Thread Tick\n");
51dacca5f0SHans Verkuil
52dacca5f0SHans Verkuil /* Drop a certain percentage of buffers. */
53dacca5f0SHans Verkuil if (dev->perc_dropped_buffers &&
54*8032bf12SJason A. Donenfeld get_random_u32_below(100) < dev->perc_dropped_buffers)
55dacca5f0SHans Verkuil return;
56dacca5f0SHans Verkuil
57dacca5f0SHans Verkuil spin_lock(&dev->slock);
58dacca5f0SHans Verkuil /*
59dacca5f0SHans Verkuil * Only dequeue buffer if there is at least one more pending.
60dacca5f0SHans Verkuil * This makes video loopback possible.
61dacca5f0SHans Verkuil */
62dacca5f0SHans Verkuil if (!list_empty(&dev->vid_out_active) &&
63dacca5f0SHans Verkuil !list_is_singular(&dev->vid_out_active)) {
64dacca5f0SHans Verkuil vid_out_buf = list_entry(dev->vid_out_active.next,
65dacca5f0SHans Verkuil struct vivid_buffer, list);
66dacca5f0SHans Verkuil list_del(&vid_out_buf->list);
67dacca5f0SHans Verkuil }
68dacca5f0SHans Verkuil if (!list_empty(&dev->vbi_out_active) &&
69dacca5f0SHans Verkuil (dev->field_out != V4L2_FIELD_ALTERNATE ||
70dacca5f0SHans Verkuil (dev->vbi_out_seq_count & 1))) {
71dacca5f0SHans Verkuil vbi_out_buf = list_entry(dev->vbi_out_active.next,
72dacca5f0SHans Verkuil struct vivid_buffer, list);
73dacca5f0SHans Verkuil list_del(&vbi_out_buf->list);
74dacca5f0SHans Verkuil }
75dacca5f0SHans Verkuil if (!list_empty(&dev->meta_out_active)) {
76dacca5f0SHans Verkuil meta_out_buf = list_entry(dev->meta_out_active.next,
77dacca5f0SHans Verkuil struct vivid_buffer, list);
78dacca5f0SHans Verkuil list_del(&meta_out_buf->list);
79dacca5f0SHans Verkuil }
80dacca5f0SHans Verkuil spin_unlock(&dev->slock);
81dacca5f0SHans Verkuil
82dacca5f0SHans Verkuil if (!vid_out_buf && !vbi_out_buf && !meta_out_buf)
83dacca5f0SHans Verkuil return;
84dacca5f0SHans Verkuil
85dacca5f0SHans Verkuil if (vid_out_buf) {
86dacca5f0SHans Verkuil v4l2_ctrl_request_setup(vid_out_buf->vb.vb2_buf.req_obj.req,
87dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_out);
88dacca5f0SHans Verkuil v4l2_ctrl_request_complete(vid_out_buf->vb.vb2_buf.req_obj.req,
89dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_out);
90dacca5f0SHans Verkuil vid_out_buf->vb.sequence = dev->vid_out_seq_count;
91dacca5f0SHans Verkuil if (dev->field_out == V4L2_FIELD_ALTERNATE) {
92dacca5f0SHans Verkuil /*
93dacca5f0SHans Verkuil * The sequence counter counts frames, not fields.
94dacca5f0SHans Verkuil * So divide by two.
95dacca5f0SHans Verkuil */
96dacca5f0SHans Verkuil vid_out_buf->vb.sequence /= 2;
97dacca5f0SHans Verkuil }
98dacca5f0SHans Verkuil vid_out_buf->vb.vb2_buf.timestamp =
99dacca5f0SHans Verkuil ktime_get_ns() + dev->time_wrap_offset;
100dacca5f0SHans Verkuil vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ?
101dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
102dacca5f0SHans Verkuil dprintk(dev, 2, "vid_out buffer %d done\n",
103dacca5f0SHans Verkuil vid_out_buf->vb.vb2_buf.index);
104dacca5f0SHans Verkuil }
105dacca5f0SHans Verkuil
106dacca5f0SHans Verkuil if (vbi_out_buf) {
107dacca5f0SHans Verkuil v4l2_ctrl_request_setup(vbi_out_buf->vb.vb2_buf.req_obj.req,
108dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_out);
109dacca5f0SHans Verkuil v4l2_ctrl_request_complete(vbi_out_buf->vb.vb2_buf.req_obj.req,
110dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_out);
111dacca5f0SHans Verkuil if (dev->stream_sliced_vbi_out)
112dacca5f0SHans Verkuil vivid_sliced_vbi_out_process(dev, vbi_out_buf);
113dacca5f0SHans Verkuil
114dacca5f0SHans Verkuil vbi_out_buf->vb.sequence = dev->vbi_out_seq_count;
115dacca5f0SHans Verkuil vbi_out_buf->vb.vb2_buf.timestamp =
116dacca5f0SHans Verkuil ktime_get_ns() + dev->time_wrap_offset;
117dacca5f0SHans Verkuil vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ?
118dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
119dacca5f0SHans Verkuil dprintk(dev, 2, "vbi_out buffer %d done\n",
120dacca5f0SHans Verkuil vbi_out_buf->vb.vb2_buf.index);
121dacca5f0SHans Verkuil }
122dacca5f0SHans Verkuil if (meta_out_buf) {
123dacca5f0SHans Verkuil v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req,
124dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_out);
125dacca5f0SHans Verkuil v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req,
126dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_out);
127dacca5f0SHans Verkuil vivid_meta_out_process(dev, meta_out_buf);
128dacca5f0SHans Verkuil meta_out_buf->vb.sequence = dev->meta_out_seq_count;
129dacca5f0SHans Verkuil meta_out_buf->vb.vb2_buf.timestamp =
130dacca5f0SHans Verkuil ktime_get_ns() + dev->time_wrap_offset;
131dacca5f0SHans Verkuil vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ?
132dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
133dacca5f0SHans Verkuil dprintk(dev, 2, "meta_out buffer %d done\n",
134dacca5f0SHans Verkuil meta_out_buf->vb.vb2_buf.index);
135dacca5f0SHans Verkuil }
136dacca5f0SHans Verkuil
137dacca5f0SHans Verkuil dev->dqbuf_error = false;
138dacca5f0SHans Verkuil }
139dacca5f0SHans Verkuil
vivid_thread_vid_out(void * data)140dacca5f0SHans Verkuil static int vivid_thread_vid_out(void *data)
141dacca5f0SHans Verkuil {
142dacca5f0SHans Verkuil struct vivid_dev *dev = data;
143dacca5f0SHans Verkuil u64 numerators_since_start;
144dacca5f0SHans Verkuil u64 buffers_since_start;
145dacca5f0SHans Verkuil u64 next_jiffies_since_start;
146dacca5f0SHans Verkuil unsigned long jiffies_since_start;
147dacca5f0SHans Verkuil unsigned long cur_jiffies;
148dacca5f0SHans Verkuil unsigned wait_jiffies;
149dacca5f0SHans Verkuil unsigned numerator;
150dacca5f0SHans Verkuil unsigned denominator;
151dacca5f0SHans Verkuil
152dacca5f0SHans Verkuil dprintk(dev, 1, "Video Output Thread Start\n");
153dacca5f0SHans Verkuil
154dacca5f0SHans Verkuil set_freezable();
155dacca5f0SHans Verkuil
156dacca5f0SHans Verkuil /* Resets frame counters */
157dacca5f0SHans Verkuil dev->out_seq_offset = 0;
15857c1d5deSDeborah Brouwer dev->out_seq_count = 0;
159dacca5f0SHans Verkuil dev->jiffies_vid_out = jiffies;
160dacca5f0SHans Verkuil dev->out_seq_resync = false;
16157c1d5deSDeborah Brouwer if (dev->time_wrap)
16257c1d5deSDeborah Brouwer dev->time_wrap_offset = dev->time_wrap - ktime_get_ns();
16357c1d5deSDeborah Brouwer else
16457c1d5deSDeborah Brouwer dev->time_wrap_offset = 0;
165dacca5f0SHans Verkuil
166dacca5f0SHans Verkuil for (;;) {
167dacca5f0SHans Verkuil try_to_freeze();
168dacca5f0SHans Verkuil if (kthread_should_stop())
169dacca5f0SHans Verkuil break;
170dacca5f0SHans Verkuil
171dacca5f0SHans Verkuil if (!mutex_trylock(&dev->mutex)) {
1726e8c09bbSHans Verkuil schedule();
173dacca5f0SHans Verkuil continue;
174dacca5f0SHans Verkuil }
175dacca5f0SHans Verkuil
176dacca5f0SHans Verkuil cur_jiffies = jiffies;
177dacca5f0SHans Verkuil if (dev->out_seq_resync) {
178dacca5f0SHans Verkuil dev->jiffies_vid_out = cur_jiffies;
179dacca5f0SHans Verkuil dev->out_seq_offset = dev->out_seq_count + 1;
180dacca5f0SHans Verkuil dev->out_seq_count = 0;
181dacca5f0SHans Verkuil dev->out_seq_resync = false;
182dacca5f0SHans Verkuil }
183dacca5f0SHans Verkuil numerator = dev->timeperframe_vid_out.numerator;
184dacca5f0SHans Verkuil denominator = dev->timeperframe_vid_out.denominator;
185dacca5f0SHans Verkuil
186dacca5f0SHans Verkuil if (dev->field_out == V4L2_FIELD_ALTERNATE)
187dacca5f0SHans Verkuil denominator *= 2;
188dacca5f0SHans Verkuil
189dacca5f0SHans Verkuil /* Calculate the number of jiffies since we started streaming */
190dacca5f0SHans Verkuil jiffies_since_start = cur_jiffies - dev->jiffies_vid_out;
191dacca5f0SHans Verkuil /* Get the number of buffers streamed since the start */
192dacca5f0SHans Verkuil buffers_since_start = (u64)jiffies_since_start * denominator +
193dacca5f0SHans Verkuil (HZ * numerator) / 2;
194dacca5f0SHans Verkuil do_div(buffers_since_start, HZ * numerator);
195dacca5f0SHans Verkuil
196dacca5f0SHans Verkuil /*
197dacca5f0SHans Verkuil * After more than 0xf0000000 (rounded down to a multiple of
198dacca5f0SHans Verkuil * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
199dacca5f0SHans Verkuil * jiffies have passed since we started streaming reset the
200dacca5f0SHans Verkuil * counters and keep track of the sequence offset.
201dacca5f0SHans Verkuil */
202dacca5f0SHans Verkuil if (jiffies_since_start > JIFFIES_RESYNC) {
203dacca5f0SHans Verkuil dev->jiffies_vid_out = cur_jiffies;
204dacca5f0SHans Verkuil dev->out_seq_offset = buffers_since_start;
205dacca5f0SHans Verkuil buffers_since_start = 0;
206dacca5f0SHans Verkuil }
207dacca5f0SHans Verkuil dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
208dacca5f0SHans Verkuil dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
209dacca5f0SHans Verkuil dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
210dacca5f0SHans Verkuil dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start;
211dacca5f0SHans Verkuil
212dacca5f0SHans Verkuil vivid_thread_vid_out_tick(dev);
213dacca5f0SHans Verkuil mutex_unlock(&dev->mutex);
214dacca5f0SHans Verkuil
215dacca5f0SHans Verkuil /*
216dacca5f0SHans Verkuil * Calculate the number of 'numerators' streamed since we started,
217dacca5f0SHans Verkuil * not including the current buffer.
218dacca5f0SHans Verkuil */
219dacca5f0SHans Verkuil numerators_since_start = buffers_since_start * numerator;
220dacca5f0SHans Verkuil
221dacca5f0SHans Verkuil /* And the number of jiffies since we started */
222dacca5f0SHans Verkuil jiffies_since_start = jiffies - dev->jiffies_vid_out;
223dacca5f0SHans Verkuil
224dacca5f0SHans Verkuil /* Increase by the 'numerator' of one buffer */
225dacca5f0SHans Verkuil numerators_since_start += numerator;
226dacca5f0SHans Verkuil /*
227dacca5f0SHans Verkuil * Calculate when that next buffer is supposed to start
228dacca5f0SHans Verkuil * in jiffies since we started streaming.
229dacca5f0SHans Verkuil */
230dacca5f0SHans Verkuil next_jiffies_since_start = numerators_since_start * HZ +
231dacca5f0SHans Verkuil denominator / 2;
232dacca5f0SHans Verkuil do_div(next_jiffies_since_start, denominator);
233dacca5f0SHans Verkuil /* If it is in the past, then just schedule asap */
234dacca5f0SHans Verkuil if (next_jiffies_since_start < jiffies_since_start)
235dacca5f0SHans Verkuil next_jiffies_since_start = jiffies_since_start;
236dacca5f0SHans Verkuil
237dacca5f0SHans Verkuil wait_jiffies = next_jiffies_since_start - jiffies_since_start;
23884db51f5SWang Qing while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
2396e8c09bbSHans Verkuil !kthread_should_stop())
2406e8c09bbSHans Verkuil schedule();
241dacca5f0SHans Verkuil }
242dacca5f0SHans Verkuil dprintk(dev, 1, "Video Output Thread End\n");
243dacca5f0SHans Verkuil return 0;
244dacca5f0SHans Verkuil }
245dacca5f0SHans Verkuil
vivid_grab_controls(struct vivid_dev * dev,bool grab)246dacca5f0SHans Verkuil static void vivid_grab_controls(struct vivid_dev *dev, bool grab)
247dacca5f0SHans Verkuil {
248dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab);
249dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab);
250dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab);
251dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_tx_mode, grab);
252dacca5f0SHans Verkuil v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab);
253dacca5f0SHans Verkuil }
254dacca5f0SHans Verkuil
vivid_start_generating_vid_out(struct vivid_dev * dev,bool * pstreaming)255dacca5f0SHans Verkuil int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
256dacca5f0SHans Verkuil {
257dacca5f0SHans Verkuil dprintk(dev, 1, "%s\n", __func__);
258dacca5f0SHans Verkuil
259dacca5f0SHans Verkuil if (dev->kthread_vid_out) {
260dacca5f0SHans Verkuil u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128;
261dacca5f0SHans Verkuil
262dacca5f0SHans Verkuil if (pstreaming == &dev->vid_out_streaming)
263dacca5f0SHans Verkuil dev->vid_out_seq_start = seq_count;
264dacca5f0SHans Verkuil else if (pstreaming == &dev->vbi_out_streaming)
265dacca5f0SHans Verkuil dev->vbi_out_seq_start = seq_count;
266dacca5f0SHans Verkuil else
267dacca5f0SHans Verkuil dev->meta_out_seq_start = seq_count;
268dacca5f0SHans Verkuil *pstreaming = true;
269dacca5f0SHans Verkuil return 0;
270dacca5f0SHans Verkuil }
271dacca5f0SHans Verkuil
272dacca5f0SHans Verkuil /* Resets frame counters */
273dacca5f0SHans Verkuil dev->jiffies_vid_out = jiffies;
274dacca5f0SHans Verkuil dev->vid_out_seq_start = dev->seq_wrap * 128;
275dacca5f0SHans Verkuil dev->vbi_out_seq_start = dev->seq_wrap * 128;
276dacca5f0SHans Verkuil dev->meta_out_seq_start = dev->seq_wrap * 128;
277dacca5f0SHans Verkuil
278dacca5f0SHans Verkuil dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
279dacca5f0SHans Verkuil "%s-vid-out", dev->v4l2_dev.name);
280dacca5f0SHans Verkuil
281dacca5f0SHans Verkuil if (IS_ERR(dev->kthread_vid_out)) {
282dacca5f0SHans Verkuil int err = PTR_ERR(dev->kthread_vid_out);
283dacca5f0SHans Verkuil
284dacca5f0SHans Verkuil dev->kthread_vid_out = NULL;
285dacca5f0SHans Verkuil v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
286dacca5f0SHans Verkuil return err;
287dacca5f0SHans Verkuil }
288dacca5f0SHans Verkuil *pstreaming = true;
289dacca5f0SHans Verkuil vivid_grab_controls(dev, true);
290dacca5f0SHans Verkuil
291dacca5f0SHans Verkuil dprintk(dev, 1, "returning from %s\n", __func__);
292dacca5f0SHans Verkuil return 0;
293dacca5f0SHans Verkuil }
294dacca5f0SHans Verkuil
vivid_stop_generating_vid_out(struct vivid_dev * dev,bool * pstreaming)295dacca5f0SHans Verkuil void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
296dacca5f0SHans Verkuil {
297dacca5f0SHans Verkuil dprintk(dev, 1, "%s\n", __func__);
298dacca5f0SHans Verkuil
299dacca5f0SHans Verkuil if (dev->kthread_vid_out == NULL)
300dacca5f0SHans Verkuil return;
301dacca5f0SHans Verkuil
302dacca5f0SHans Verkuil *pstreaming = false;
303dacca5f0SHans Verkuil if (pstreaming == &dev->vid_out_streaming) {
304dacca5f0SHans Verkuil /* Release all active buffers */
305dacca5f0SHans Verkuil while (!list_empty(&dev->vid_out_active)) {
306dacca5f0SHans Verkuil struct vivid_buffer *buf;
307dacca5f0SHans Verkuil
308dacca5f0SHans Verkuil buf = list_entry(dev->vid_out_active.next,
309dacca5f0SHans Verkuil struct vivid_buffer, list);
310dacca5f0SHans Verkuil list_del(&buf->list);
311dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
312dacca5f0SHans Verkuil &dev->ctrl_hdl_vid_out);
313dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
314dacca5f0SHans Verkuil dprintk(dev, 2, "vid_out buffer %d done\n",
315dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
316dacca5f0SHans Verkuil }
317dacca5f0SHans Verkuil }
318dacca5f0SHans Verkuil
319dacca5f0SHans Verkuil if (pstreaming == &dev->vbi_out_streaming) {
320dacca5f0SHans Verkuil while (!list_empty(&dev->vbi_out_active)) {
321dacca5f0SHans Verkuil struct vivid_buffer *buf;
322dacca5f0SHans Verkuil
323dacca5f0SHans Verkuil buf = list_entry(dev->vbi_out_active.next,
324dacca5f0SHans Verkuil struct vivid_buffer, list);
325dacca5f0SHans Verkuil list_del(&buf->list);
326dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
327dacca5f0SHans Verkuil &dev->ctrl_hdl_vbi_out);
328dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
329dacca5f0SHans Verkuil dprintk(dev, 2, "vbi_out buffer %d done\n",
330dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
331dacca5f0SHans Verkuil }
332dacca5f0SHans Verkuil }
333dacca5f0SHans Verkuil
334dacca5f0SHans Verkuil if (pstreaming == &dev->meta_out_streaming) {
335dacca5f0SHans Verkuil while (!list_empty(&dev->meta_out_active)) {
336dacca5f0SHans Verkuil struct vivid_buffer *buf;
337dacca5f0SHans Verkuil
338dacca5f0SHans Verkuil buf = list_entry(dev->meta_out_active.next,
339dacca5f0SHans Verkuil struct vivid_buffer, list);
340dacca5f0SHans Verkuil list_del(&buf->list);
341dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
342dacca5f0SHans Verkuil &dev->ctrl_hdl_meta_out);
343dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
344dacca5f0SHans Verkuil dprintk(dev, 2, "meta_out buffer %d done\n",
345dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
346dacca5f0SHans Verkuil }
347dacca5f0SHans Verkuil }
348dacca5f0SHans Verkuil
349dacca5f0SHans Verkuil if (dev->vid_out_streaming || dev->vbi_out_streaming ||
350dacca5f0SHans Verkuil dev->meta_out_streaming)
351dacca5f0SHans Verkuil return;
352dacca5f0SHans Verkuil
353dacca5f0SHans Verkuil /* shutdown control thread */
354dacca5f0SHans Verkuil vivid_grab_controls(dev, false);
355dacca5f0SHans Verkuil kthread_stop(dev->kthread_vid_out);
356dacca5f0SHans Verkuil dev->kthread_vid_out = NULL;
357dacca5f0SHans Verkuil }
358