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 (*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 30 static 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() returns 39 * 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 54 static 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 66 static 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 */ 92 static 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 99 static 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 106 const 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 117 int 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 126 int 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 136 int 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 149 int 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 165 int 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 176 int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i) 177 { 178 *i = 0; 179 return 0; 180 } 181 182 int 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 199 int vivid_s_input_tch(struct file *file, void *priv, unsigned int i) 200 { 201 return vivid_set_touch(video_drvdata(file), i); 202 } 203 204 static 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 else 215 tch_buf[i] = (rand / 10) % 7 - 3; 216 } 217 } 218 219 static inline int get_random_pressure(void) 220 { 221 return get_random_u32_below(VIVID_PRESSURE_LIMIT); 222 } 223 224 static 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 253 void 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 #endif 338 } 339