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