1dacca5f0SHans Verkuil // SPDX-License-Identifier: GPL-2.0-only
2dacca5f0SHans Verkuil /*
3dacca5f0SHans Verkuil * vivid-kthread-touch.c - touch capture thread support functions.
4dacca5f0SHans Verkuil *
5dacca5f0SHans Verkuil */
6dacca5f0SHans Verkuil
7dacca5f0SHans Verkuil #include <linux/freezer.h>
8*84db51f5SWang Qing #include <linux/jiffies.h>
9dacca5f0SHans Verkuil #include "vivid-core.h"
10dacca5f0SHans Verkuil #include "vivid-kthread-touch.h"
11dacca5f0SHans Verkuil #include "vivid-touch-cap.h"
12dacca5f0SHans Verkuil
vivid_thread_tch_cap_tick(struct vivid_dev * dev,int dropped_bufs)13dacca5f0SHans Verkuil static noinline_for_stack void vivid_thread_tch_cap_tick(struct vivid_dev *dev,
14dacca5f0SHans Verkuil int dropped_bufs)
15dacca5f0SHans Verkuil {
16dacca5f0SHans Verkuil struct vivid_buffer *tch_cap_buf = NULL;
17dacca5f0SHans Verkuil
18dacca5f0SHans Verkuil spin_lock(&dev->slock);
19dacca5f0SHans Verkuil if (!list_empty(&dev->touch_cap_active)) {
20dacca5f0SHans Verkuil tch_cap_buf = list_entry(dev->touch_cap_active.next,
21dacca5f0SHans Verkuil struct vivid_buffer, list);
22dacca5f0SHans Verkuil list_del(&tch_cap_buf->list);
23dacca5f0SHans Verkuil }
24dacca5f0SHans Verkuil
25dacca5f0SHans Verkuil spin_unlock(&dev->slock);
26dacca5f0SHans Verkuil
27dacca5f0SHans Verkuil if (tch_cap_buf) {
28dacca5f0SHans Verkuil v4l2_ctrl_request_setup(tch_cap_buf->vb.vb2_buf.req_obj.req,
29dacca5f0SHans Verkuil &dev->ctrl_hdl_touch_cap);
30dacca5f0SHans Verkuil
31dacca5f0SHans Verkuil vivid_fillbuff_tch(dev, tch_cap_buf);
32dacca5f0SHans Verkuil v4l2_ctrl_request_complete(tch_cap_buf->vb.vb2_buf.req_obj.req,
33dacca5f0SHans Verkuil &dev->ctrl_hdl_touch_cap);
34dacca5f0SHans Verkuil vb2_buffer_done(&tch_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
35dacca5f0SHans Verkuil VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
36dacca5f0SHans Verkuil dprintk(dev, 2, "touch_cap buffer %d done\n",
37dacca5f0SHans Verkuil tch_cap_buf->vb.vb2_buf.index);
38dacca5f0SHans Verkuil
39dacca5f0SHans Verkuil tch_cap_buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
40dacca5f0SHans Verkuil }
41dacca5f0SHans Verkuil dev->dqbuf_error = false;
42dacca5f0SHans Verkuil }
43dacca5f0SHans Verkuil
vivid_thread_touch_cap(void * data)44dacca5f0SHans Verkuil static int vivid_thread_touch_cap(void *data)
45dacca5f0SHans Verkuil {
46dacca5f0SHans Verkuil struct vivid_dev *dev = data;
47dacca5f0SHans Verkuil u64 numerators_since_start;
48dacca5f0SHans Verkuil u64 buffers_since_start;
49dacca5f0SHans Verkuil u64 next_jiffies_since_start;
50dacca5f0SHans Verkuil unsigned long jiffies_since_start;
51dacca5f0SHans Verkuil unsigned long cur_jiffies;
52dacca5f0SHans Verkuil unsigned int wait_jiffies;
53dacca5f0SHans Verkuil unsigned int numerator;
54dacca5f0SHans Verkuil unsigned int denominator;
55dacca5f0SHans Verkuil int dropped_bufs;
56dacca5f0SHans Verkuil
57dacca5f0SHans Verkuil dprintk(dev, 1, "Touch Capture Thread Start\n");
58dacca5f0SHans Verkuil
59dacca5f0SHans Verkuil set_freezable();
60dacca5f0SHans Verkuil
61dacca5f0SHans Verkuil /* Resets frame counters */
62dacca5f0SHans Verkuil dev->touch_cap_seq_offset = 0;
63dacca5f0SHans Verkuil dev->touch_cap_seq_count = 0;
64dacca5f0SHans Verkuil dev->touch_cap_seq_resync = false;
65dacca5f0SHans Verkuil dev->jiffies_touch_cap = jiffies;
6657c1d5deSDeborah Brouwer if (dev->time_wrap)
6757c1d5deSDeborah Brouwer dev->time_wrap_offset = dev->time_wrap - ktime_get_ns();
6857c1d5deSDeborah Brouwer else
6957c1d5deSDeborah Brouwer dev->time_wrap_offset = 0;
70dacca5f0SHans Verkuil
71dacca5f0SHans Verkuil for (;;) {
72dacca5f0SHans Verkuil try_to_freeze();
73dacca5f0SHans Verkuil if (kthread_should_stop())
74dacca5f0SHans Verkuil break;
75dacca5f0SHans Verkuil
76dacca5f0SHans Verkuil if (!mutex_trylock(&dev->mutex)) {
776e8c09bbSHans Verkuil schedule();
78dacca5f0SHans Verkuil continue;
79dacca5f0SHans Verkuil }
80dacca5f0SHans Verkuil cur_jiffies = jiffies;
81dacca5f0SHans Verkuil if (dev->touch_cap_seq_resync) {
82dacca5f0SHans Verkuil dev->jiffies_touch_cap = cur_jiffies;
83dacca5f0SHans Verkuil dev->touch_cap_seq_offset = dev->touch_cap_seq_count + 1;
84dacca5f0SHans Verkuil dev->touch_cap_seq_count = 0;
85dacca5f0SHans Verkuil dev->cap_seq_resync = false;
86dacca5f0SHans Verkuil }
87dacca5f0SHans Verkuil denominator = dev->timeperframe_tch_cap.denominator;
88dacca5f0SHans Verkuil numerator = dev->timeperframe_tch_cap.numerator;
89dacca5f0SHans Verkuil
90dacca5f0SHans Verkuil /* Calculate the number of jiffies since we started streaming */
91dacca5f0SHans Verkuil jiffies_since_start = cur_jiffies - dev->jiffies_touch_cap;
92dacca5f0SHans Verkuil /* Get the number of buffers streamed since the start */
93dacca5f0SHans Verkuil buffers_since_start = (u64)jiffies_since_start * denominator +
94dacca5f0SHans Verkuil (HZ * numerator) / 2;
95dacca5f0SHans Verkuil do_div(buffers_since_start, HZ * numerator);
96dacca5f0SHans Verkuil
97dacca5f0SHans Verkuil /*
98dacca5f0SHans Verkuil * After more than 0xf0000000 (rounded down to a multiple of
99dacca5f0SHans Verkuil * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
100dacca5f0SHans Verkuil * jiffies have passed since we started streaming reset the
101dacca5f0SHans Verkuil * counters and keep track of the sequence offset.
102dacca5f0SHans Verkuil */
103dacca5f0SHans Verkuil if (jiffies_since_start > JIFFIES_RESYNC) {
104dacca5f0SHans Verkuil dev->jiffies_touch_cap = cur_jiffies;
105dacca5f0SHans Verkuil dev->cap_seq_offset = buffers_since_start;
106dacca5f0SHans Verkuil buffers_since_start = 0;
107dacca5f0SHans Verkuil }
108dacca5f0SHans Verkuil dropped_bufs = buffers_since_start + dev->touch_cap_seq_offset - dev->touch_cap_seq_count;
109dacca5f0SHans Verkuil dev->touch_cap_seq_count = buffers_since_start + dev->touch_cap_seq_offset;
11057c1d5deSDeborah Brouwer dev->touch_cap_with_seq_wrap_count =
11157c1d5deSDeborah Brouwer dev->touch_cap_seq_count - dev->touch_cap_seq_start;
112dacca5f0SHans Verkuil
113dacca5f0SHans Verkuil vivid_thread_tch_cap_tick(dev, dropped_bufs);
114dacca5f0SHans Verkuil
115dacca5f0SHans Verkuil /*
116dacca5f0SHans Verkuil * Calculate the number of 'numerators' streamed
117dacca5f0SHans Verkuil * since we started, including the current buffer.
118dacca5f0SHans Verkuil */
119dacca5f0SHans Verkuil numerators_since_start = ++buffers_since_start * numerator;
120dacca5f0SHans Verkuil
121dacca5f0SHans Verkuil /* And the number of jiffies since we started */
122dacca5f0SHans Verkuil jiffies_since_start = jiffies - dev->jiffies_touch_cap;
123dacca5f0SHans Verkuil
124dacca5f0SHans Verkuil mutex_unlock(&dev->mutex);
125dacca5f0SHans Verkuil
126dacca5f0SHans Verkuil /*
127dacca5f0SHans Verkuil * Calculate when that next buffer is supposed to start
128dacca5f0SHans Verkuil * in jiffies since we started streaming.
129dacca5f0SHans Verkuil */
130dacca5f0SHans Verkuil next_jiffies_since_start = numerators_since_start * HZ +
131dacca5f0SHans Verkuil denominator / 2;
132dacca5f0SHans Verkuil do_div(next_jiffies_since_start, denominator);
133dacca5f0SHans Verkuil /* If it is in the past, then just schedule asap */
134dacca5f0SHans Verkuil if (next_jiffies_since_start < jiffies_since_start)
135dacca5f0SHans Verkuil next_jiffies_since_start = jiffies_since_start;
136dacca5f0SHans Verkuil
137dacca5f0SHans Verkuil wait_jiffies = next_jiffies_since_start - jiffies_since_start;
138*84db51f5SWang Qing while (time_is_after_jiffies(cur_jiffies + wait_jiffies) &&
1396e8c09bbSHans Verkuil !kthread_should_stop())
1406e8c09bbSHans Verkuil schedule();
141dacca5f0SHans Verkuil }
142dacca5f0SHans Verkuil dprintk(dev, 1, "Touch Capture Thread End\n");
143dacca5f0SHans Verkuil return 0;
144dacca5f0SHans Verkuil }
145dacca5f0SHans Verkuil
vivid_start_generating_touch_cap(struct vivid_dev * dev)146dacca5f0SHans Verkuil int vivid_start_generating_touch_cap(struct vivid_dev *dev)
147dacca5f0SHans Verkuil {
148dacca5f0SHans Verkuil if (dev->kthread_touch_cap) {
149dacca5f0SHans Verkuil dev->touch_cap_streaming = true;
150dacca5f0SHans Verkuil return 0;
151dacca5f0SHans Verkuil }
152dacca5f0SHans Verkuil
15357c1d5deSDeborah Brouwer dev->touch_cap_seq_start = dev->seq_wrap * 128;
154dacca5f0SHans Verkuil dev->kthread_touch_cap = kthread_run(vivid_thread_touch_cap, dev,
155dacca5f0SHans Verkuil "%s-tch-cap", dev->v4l2_dev.name);
156dacca5f0SHans Verkuil
157dacca5f0SHans Verkuil if (IS_ERR(dev->kthread_touch_cap)) {
158dacca5f0SHans Verkuil int err = PTR_ERR(dev->kthread_touch_cap);
159dacca5f0SHans Verkuil
160dacca5f0SHans Verkuil dev->kthread_touch_cap = NULL;
161dacca5f0SHans Verkuil v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
162dacca5f0SHans Verkuil return err;
163dacca5f0SHans Verkuil }
164dacca5f0SHans Verkuil dev->touch_cap_streaming = true;
165dacca5f0SHans Verkuil dprintk(dev, 1, "returning from %s\n", __func__);
166dacca5f0SHans Verkuil return 0;
167dacca5f0SHans Verkuil }
168dacca5f0SHans Verkuil
vivid_stop_generating_touch_cap(struct vivid_dev * dev)169dacca5f0SHans Verkuil void vivid_stop_generating_touch_cap(struct vivid_dev *dev)
170dacca5f0SHans Verkuil {
171dacca5f0SHans Verkuil if (!dev->kthread_touch_cap)
172dacca5f0SHans Verkuil return;
173dacca5f0SHans Verkuil
174dacca5f0SHans Verkuil dev->touch_cap_streaming = false;
175dacca5f0SHans Verkuil
176dacca5f0SHans Verkuil while (!list_empty(&dev->touch_cap_active)) {
177dacca5f0SHans Verkuil struct vivid_buffer *buf;
178dacca5f0SHans Verkuil
179dacca5f0SHans Verkuil buf = list_entry(dev->touch_cap_active.next,
180dacca5f0SHans Verkuil struct vivid_buffer, list);
181dacca5f0SHans Verkuil list_del(&buf->list);
182dacca5f0SHans Verkuil v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
183dacca5f0SHans Verkuil &dev->ctrl_hdl_touch_cap);
184dacca5f0SHans Verkuil vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
185dacca5f0SHans Verkuil dprintk(dev, 2, "touch_cap buffer %d done\n",
186dacca5f0SHans Verkuil buf->vb.vb2_buf.index);
187dacca5f0SHans Verkuil }
188dacca5f0SHans Verkuil
189dacca5f0SHans Verkuil kthread_stop(dev->kthread_touch_cap);
190dacca5f0SHans Verkuil dev->kthread_touch_cap = NULL;
191dacca5f0SHans Verkuil }
192