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