GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / media / test-drivers / vivid / vivid-touch-cap.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * vivid-touch-cap.c - touch support functions.
4  */
5
6 #include "vivid-core.h"
7 #include "vivid-kthread-touch.h"
8 #include "vivid-vid-common.h"
9 #include "vivid-touch-cap.h"
10
11 static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
12                                  unsigned int *nplanes, unsigned int sizes[],
13                                  struct device *alloc_devs[])
14 {
15         struct vivid_dev *dev = vb2_get_drv_priv(vq);
16         struct v4l2_pix_format *f = &dev->tch_format;
17         unsigned int size = f->sizeimage;
18
19         if (*nplanes) {
20                 if (sizes[0] < size)
21                         return -EINVAL;
22         } else {
23                 sizes[0] = size;
24         }
25
26         if (vq->num_buffers + *nbuffers < 2)
27                 *nbuffers = 2 - vq->num_buffers;
28
29         *nplanes = 1;
30         return 0;
31 }
32
33 static int touch_cap_buf_prepare(struct vb2_buffer *vb)
34 {
35         struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
36         struct v4l2_pix_format *f = &dev->tch_format;
37         unsigned int size = f->sizeimage;
38
39         if (dev->buf_prepare_error) {
40                 /*
41                  * Error injection: test what happens if buf_prepare() returns
42                  * an error.
43                  */
44                 dev->buf_prepare_error = false;
45                 return -EINVAL;
46         }
47         if (vb2_plane_size(vb, 0) < size) {
48                 dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
49                         __func__, vb2_plane_size(vb, 0), size);
50                 return -EINVAL;
51         }
52         vb2_set_plane_payload(vb, 0, size);
53
54         return 0;
55 }
56
57 static void touch_cap_buf_queue(struct vb2_buffer *vb)
58 {
59         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
60         struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
61         struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
62
63         vbuf->field = V4L2_FIELD_NONE;
64         spin_lock(&dev->slock);
65         list_add_tail(&buf->list, &dev->touch_cap_active);
66         spin_unlock(&dev->slock);
67 }
68
69 static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
70 {
71         struct vivid_dev *dev = vb2_get_drv_priv(vq);
72         int err;
73
74         dev->touch_cap_seq_count = 0;
75         if (dev->start_streaming_error) {
76                 dev->start_streaming_error = false;
77                 err = -EINVAL;
78         } else {
79                 err = vivid_start_generating_touch_cap(dev);
80         }
81         if (err) {
82                 struct vivid_buffer *buf, *tmp;
83
84                 list_for_each_entry_safe(buf, tmp,
85                                          &dev->touch_cap_active, list) {
86                         list_del(&buf->list);
87                         vb2_buffer_done(&buf->vb.vb2_buf,
88                                         VB2_BUF_STATE_QUEUED);
89                 }
90         }
91         return err;
92 }
93
94 /* abort streaming and wait for last buffer */
95 static void touch_cap_stop_streaming(struct vb2_queue *vq)
96 {
97         struct vivid_dev *dev = vb2_get_drv_priv(vq);
98
99         vivid_stop_generating_touch_cap(dev);
100 }
101
102 static void touch_cap_buf_request_complete(struct vb2_buffer *vb)
103 {
104         struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
105
106         v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap);
107 }
108
109 const struct vb2_ops vivid_touch_cap_qops = {
110         .queue_setup            = touch_cap_queue_setup,
111         .buf_prepare            = touch_cap_buf_prepare,
112         .buf_queue              = touch_cap_buf_queue,
113         .start_streaming        = touch_cap_start_streaming,
114         .stop_streaming         = touch_cap_stop_streaming,
115         .buf_request_complete   = touch_cap_buf_request_complete,
116         .wait_prepare           = vb2_ops_wait_prepare,
117         .wait_finish            = vb2_ops_wait_finish,
118 };
119
120 int vivid_enum_fmt_tch(struct file *file, void  *priv, struct v4l2_fmtdesc *f)
121 {
122         if (f->index)
123                 return -EINVAL;
124
125         f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
126         return 0;
127 }
128
129 int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
130 {
131         struct vivid_dev *dev = video_drvdata(file);
132
133         if (dev->multiplanar)
134                 return -ENOTTY;
135         f->fmt.pix = dev->tch_format;
136         return 0;
137 }
138
139 int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f)
140 {
141         struct vivid_dev *dev = video_drvdata(file);
142         struct v4l2_format sp_fmt;
143
144         if (!dev->multiplanar)
145                 return -ENOTTY;
146         sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
147         sp_fmt.fmt.pix = dev->tch_format;
148         fmt_sp2mp(&sp_fmt, f);
149         return 0;
150 }
151
152 int vivid_g_parm_tch(struct file *file, void *priv,
153                      struct v4l2_streamparm *parm)
154 {
155         struct vivid_dev *dev = video_drvdata(file);
156
157         if (parm->type != (dev->multiplanar ?
158                            V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
159                            V4L2_BUF_TYPE_VIDEO_CAPTURE))
160                 return -EINVAL;
161
162         parm->parm.capture.capability   = V4L2_CAP_TIMEPERFRAME;
163         parm->parm.capture.timeperframe = dev->timeperframe_tch_cap;
164         parm->parm.capture.readbuffers  = 1;
165         return 0;
166 }
167
168 int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp)
169 {
170         if (inp->index)
171                 return -EINVAL;
172
173         inp->type = V4L2_INPUT_TYPE_TOUCH;
174         strscpy(inp->name, "Vivid Touch", sizeof(inp->name));
175         inp->capabilities = 0;
176         return 0;
177 }
178
179 int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i)
180 {
181         *i = 0;
182         return 0;
183 }
184
185 int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
186 {
187         struct v4l2_pix_format *f = &dev->tch_format;
188
189         if (i)
190                 return -EINVAL;
191
192         f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
193         f->width =  VIVID_TCH_WIDTH;
194         f->height = VIVID_TCH_HEIGHT;
195         f->field = V4L2_FIELD_NONE;
196         f->colorspace = V4L2_COLORSPACE_RAW;
197         f->bytesperline = f->width * sizeof(s16);
198         f->sizeimage = f->width * f->height * sizeof(s16);
199         return 0;
200 }
201
202 int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
203 {
204         return vivid_set_touch(video_drvdata(file), i);
205 }
206
207 static void vivid_fill_buff_noise(__s16 *tch_buf, int size)
208 {
209         int i;
210
211         /* Fill 10% of the values within range -3 and 3, zero the others */
212         for (i = 0; i < size; i++) {
213                 unsigned int rand = get_random_int();
214
215                 if (rand % 10)
216                         tch_buf[i] = 0;
217                 else
218                         tch_buf[i] = (rand / 10) % 7 - 3;
219         }
220 }
221
222 static inline int get_random_pressure(void)
223 {
224         return get_random_int() % VIVID_PRESSURE_LIMIT;
225 }
226
227 static void vivid_tch_buf_set(struct v4l2_pix_format *f,
228                               __s16 *tch_buf,
229                               int index)
230 {
231         unsigned int x = index % f->width;
232         unsigned int y = index / f->width;
233         unsigned int offset = VIVID_MIN_PRESSURE;
234
235         tch_buf[index] = offset + get_random_pressure();
236         offset /= 2;
237         if (x)
238                 tch_buf[index - 1] = offset + get_random_pressure();
239         if (x < f->width - 1)
240                 tch_buf[index + 1] = offset + get_random_pressure();
241         if (y)
242                 tch_buf[index - f->width] = offset + get_random_pressure();
243         if (y < f->height - 1)
244                 tch_buf[index + f->width] = offset + get_random_pressure();
245         offset /= 2;
246         if (x && y)
247                 tch_buf[index - 1 - f->width] = offset + get_random_pressure();
248         if (x < f->width - 1 && y)
249                 tch_buf[index + 1 - f->width] = offset + get_random_pressure();
250         if (x && y < f->height - 1)
251                 tch_buf[index - 1 + f->width] = offset + get_random_pressure();
252         if (x < f->width - 1 && y < f->height - 1)
253                 tch_buf[index + 1 + f->width] = offset + get_random_pressure();
254 }
255
256 void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
257 {
258         struct v4l2_pix_format *f = &dev->tch_format;
259         int size = f->width * f->height;
260         int x, y, xstart, ystart, offset_x, offset_y;
261         unsigned int test_pattern, test_pat_idx, rand;
262
263         __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
264
265         buf->vb.sequence = dev->touch_cap_seq_count;
266         test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX;
267         test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT;
268
269         vivid_fill_buff_noise(tch_buf, size);
270
271         if (test_pat_idx >= TCH_PATTERN_COUNT)
272                 return;
273
274         if (test_pat_idx == 0)
275                 dev->tch_pat_random = get_random_int();
276         rand = dev->tch_pat_random;
277
278         switch (test_pattern) {
279         case SINGLE_TAP:
280                 if (test_pat_idx == 2)
281                         vivid_tch_buf_set(f, tch_buf, rand % size);
282                 break;
283         case DOUBLE_TAP:
284                 if (test_pat_idx == 2 || test_pat_idx == 4)
285                         vivid_tch_buf_set(f, tch_buf, rand % size);
286                 break;
287         case TRIPLE_TAP:
288                 if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6)
289                         vivid_tch_buf_set(f, tch_buf, rand % size);
290                 break;
291         case MOVE_LEFT_TO_RIGHT:
292                 vivid_tch_buf_set(f, tch_buf,
293                                   (rand % f->height) * f->width +
294                                   test_pat_idx *
295                                   (f->width / TCH_PATTERN_COUNT));
296                 break;
297         case ZOOM_IN:
298                 x = f->width / 2;
299                 y = f->height / 2;
300                 offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) /
301                                 TCH_PATTERN_COUNT;
302                 offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) /
303                                 TCH_PATTERN_COUNT;
304                 vivid_tch_buf_set(f, tch_buf,
305                                   (x - offset_x) + f->width * (y - offset_y));
306                 vivid_tch_buf_set(f, tch_buf,
307                                   (x + offset_x) + f->width * (y + offset_y));
308                 break;
309         case ZOOM_OUT:
310                 x = f->width / 2;
311                 y = f->height / 2;
312                 offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT;
313                 offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT;
314                 vivid_tch_buf_set(f, tch_buf,
315                                   (x - offset_x) + f->width * (y - offset_y));
316                 vivid_tch_buf_set(f, tch_buf,
317                                   (x + offset_x) + f->width * (y + offset_y));
318                 break;
319         case PALM_PRESS:
320                 for (x = 0; x < f->width; x++)
321                         for (y = f->height / 2; y < f->height; y++)
322                                 tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE +
323                                                         get_random_pressure();
324                 break;
325         case MULTIPLE_PRESS:
326                 /* 16 pressure points */
327                 for (y = 0; y < 4; y++) {
328                         for (x = 0; x < 4; x++) {
329                                 ystart = (y * f->height) / 4 + f->height / 8;
330                                 xstart = (x * f->width) / 4 + f->width / 8;
331                                 vivid_tch_buf_set(f, tch_buf,
332                                                   ystart * f->width + xstart);
333                         }
334                 }
335                 break;
336         }
337 #ifdef __BIG_ENDIAN__
338         for (x = 0; x < size; x++)
339                 tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]);
340 #endif
341 }