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