1 // SPDX-License-Identifier: GPL-2.0-only
3 * vivid-touch-cap.c - touch support functions.
6 #include "vivid-core.h"
7 #include "vivid-kthread-touch.h"
8 #include "vivid-vid-common.h"
9 #include "vivid-touch-cap.h"
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
[])
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
;
26 if (vq
->num_buffers
+ *nbuffers
< 2)
27 *nbuffers
= 2 - vq
->num_buffers
;
33 static int touch_cap_buf_prepare(struct vb2_buffer
*vb
)
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
;
39 if (dev
->buf_prepare_error
) {
41 * Error injection: test what happens if buf_prepare() returns
44 dev
->buf_prepare_error
= false;
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
);
52 vb2_set_plane_payload(vb
, 0, size
);
57 static void touch_cap_buf_queue(struct vb2_buffer
*vb
)
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
);
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
);
69 static int touch_cap_start_streaming(struct vb2_queue
*vq
, unsigned int count
)
71 struct vivid_dev
*dev
= vb2_get_drv_priv(vq
);
74 dev
->touch_cap_seq_count
= 0;
75 if (dev
->start_streaming_error
) {
76 dev
->start_streaming_error
= false;
79 err
= vivid_start_generating_touch_cap(dev
);
82 struct vivid_buffer
*buf
, *tmp
;
84 list_for_each_entry_safe(buf
, tmp
,
85 &dev
->touch_cap_active
, list
) {
87 vb2_buffer_done(&buf
->vb
.vb2_buf
,
88 VB2_BUF_STATE_QUEUED
);
94 /* abort streaming and wait for last buffer */
95 static void touch_cap_stop_streaming(struct vb2_queue
*vq
)
97 struct vivid_dev
*dev
= vb2_get_drv_priv(vq
);
99 vivid_stop_generating_touch_cap(dev
);
102 static void touch_cap_buf_request_complete(struct vb2_buffer
*vb
)
104 struct vivid_dev
*dev
= vb2_get_drv_priv(vb
->vb2_queue
);
106 v4l2_ctrl_request_complete(vb
->req_obj
.req
, &dev
->ctrl_hdl_touch_cap
);
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
,
120 int vivid_enum_fmt_tch(struct file
*file
, void *priv
, struct v4l2_fmtdesc
*f
)
125 f
->pixelformat
= V4L2_TCH_FMT_DELTA_TD16
;
129 int vivid_g_fmt_tch(struct file
*file
, void *priv
, struct v4l2_format
*f
)
131 struct vivid_dev
*dev
= video_drvdata(file
);
133 if (dev
->multiplanar
)
135 f
->fmt
.pix
= dev
->tch_format
;
139 int vivid_g_fmt_tch_mplane(struct file
*file
, void *priv
, struct v4l2_format
*f
)
141 struct vivid_dev
*dev
= video_drvdata(file
);
142 struct v4l2_format sp_fmt
;
144 if (!dev
->multiplanar
)
146 sp_fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
147 sp_fmt
.fmt
.pix
= dev
->tch_format
;
148 fmt_sp2mp(&sp_fmt
, f
);
152 int vivid_g_parm_tch(struct file
*file
, void *priv
,
153 struct v4l2_streamparm
*parm
)
155 struct vivid_dev
*dev
= video_drvdata(file
);
157 if (parm
->type
!= (dev
->multiplanar
?
158 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
:
159 V4L2_BUF_TYPE_VIDEO_CAPTURE
))
162 parm
->parm
.capture
.capability
= V4L2_CAP_TIMEPERFRAME
;
163 parm
->parm
.capture
.timeperframe
= dev
->timeperframe_tch_cap
;
164 parm
->parm
.capture
.readbuffers
= 1;
168 int vivid_enum_input_tch(struct file
*file
, void *priv
, struct v4l2_input
*inp
)
173 inp
->type
= V4L2_INPUT_TYPE_TOUCH
;
174 strscpy(inp
->name
, "Vivid Touch", sizeof(inp
->name
));
175 inp
->capabilities
= 0;
179 int vivid_g_input_tch(struct file
*file
, void *priv
, unsigned int *i
)
185 int vivid_set_touch(struct vivid_dev
*dev
, unsigned int i
)
187 struct v4l2_pix_format
*f
= &dev
->tch_format
;
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
);
202 int vivid_s_input_tch(struct file
*file
, void *priv
, unsigned int i
)
204 return vivid_set_touch(video_drvdata(file
), i
);
207 static void vivid_fill_buff_noise(__s16
*tch_buf
, int size
)
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();
218 tch_buf
[i
] = (rand
/ 10) % 7 - 3;
222 static inline int get_random_pressure(void)
224 return get_random_int() % VIVID_PRESSURE_LIMIT
;
227 static void vivid_tch_buf_set(struct v4l2_pix_format
*f
,
231 unsigned int x
= index
% f
->width
;
232 unsigned int y
= index
/ f
->width
;
233 unsigned int offset
= VIVID_MIN_PRESSURE
;
235 tch_buf
[index
] = offset
+ get_random_pressure();
238 tch_buf
[index
- 1] = offset
+ get_random_pressure();
239 if (x
< f
->width
- 1)
240 tch_buf
[index
+ 1] = offset
+ get_random_pressure();
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();
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();
256 void vivid_fillbuff_tch(struct vivid_dev
*dev
, struct vivid_buffer
*buf
)
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
;
263 __s16
*tch_buf
= vb2_plane_vaddr(&buf
->vb
.vb2_buf
, 0);
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
;
269 vivid_fill_buff_noise(tch_buf
, size
);
271 if (test_pat_idx
>= TCH_PATTERN_COUNT
)
274 if (test_pat_idx
== 0)
275 dev
->tch_pat_random
= get_random_int();
276 rand
= dev
->tch_pat_random
;
278 switch (test_pattern
) {
280 if (test_pat_idx
== 2)
281 vivid_tch_buf_set(f
, tch_buf
, rand
% size
);
284 if (test_pat_idx
== 2 || test_pat_idx
== 4)
285 vivid_tch_buf_set(f
, tch_buf
, rand
% size
);
288 if (test_pat_idx
== 2 || test_pat_idx
== 4 || test_pat_idx
== 6)
289 vivid_tch_buf_set(f
, tch_buf
, rand
% size
);
291 case MOVE_LEFT_TO_RIGHT
:
292 vivid_tch_buf_set(f
, tch_buf
,
293 (rand
% f
->height
) * f
->width
+
295 (f
->width
/ TCH_PATTERN_COUNT
));
300 offset_x
= ((TCH_PATTERN_COUNT
- 1 - test_pat_idx
) * x
) /
302 offset_y
= ((TCH_PATTERN_COUNT
- 1 - test_pat_idx
) * y
) /
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
));
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
));
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();
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
);
337 #ifdef __BIG_ENDIAN__
338 for (x
= 0; x
< size
; x
++)
339 tch_buf
[x
] = (__force s16
)__cpu_to_le16((u16
)tch_buf
[x
]);