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 }; 114 115 int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) 116 { 117 if (f->index) 118 return -EINVAL; 119 120 f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; 121 return 0; 122 } 123 124 int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f) 125 { 126 struct vivid_dev *dev = video_drvdata(file); 127 128 if (dev->multiplanar) 129 return -ENOTTY; 130 f->fmt.pix = dev->tch_format; 131 return 0; 132 } 133 134 int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f) 135 { 136 struct vivid_dev *dev = video_drvdata(file); 137 struct v4l2_format sp_fmt; 138 139 if (!dev->multiplanar) 140 return -ENOTTY; 141 sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 142 sp_fmt.fmt.pix = dev->tch_format; 143 fmt_sp2mp(&sp_fmt, f); 144 return 0; 145 } 146 147 int vivid_g_parm_tch(struct file *file, void *priv, 148 struct v4l2_streamparm *parm) 149 { 150 struct vivid_dev *dev = video_drvdata(file); 151 152 if (parm->type != (dev->multiplanar ? 153 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : 154 V4L2_BUF_TYPE_VIDEO_CAPTURE)) 155 return -EINVAL; 156 157 parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 158 parm->parm.capture.timeperframe = dev->timeperframe_tch_cap; 159 parm->parm.capture.readbuffers = 1; 160 return 0; 161 } 162 163 int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp) 164 { 165 if (inp->index) 166 return -EINVAL; 167 168 inp->type = V4L2_INPUT_TYPE_TOUCH; 169 strscpy(inp->name, "Vivid Touch", sizeof(inp->name)); 170 inp->capabilities = 0; 171 return 0; 172 } 173 174 int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i) 175 { 176 *i = 0; 177 return 0; 178 } 179 180 int vivid_set_touch(struct vivid_dev *dev, unsigned int i) 181 { 182 struct v4l2_pix_format *f = &dev->tch_format; 183 184 if (i) 185 return -EINVAL; 186 187 f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; 188 f->width = VIVID_TCH_WIDTH; 189 f->height = VIVID_TCH_HEIGHT; 190 f->field = V4L2_FIELD_NONE; 191 f->colorspace = V4L2_COLORSPACE_RAW; 192 f->bytesperline = f->width * sizeof(s16); 193 f->sizeimage = f->width * f->height * sizeof(s16); 194 return 0; 195 } 196 197 int vivid_s_input_tch(struct file *file, void *priv, unsigned int i) 198 { 199 return vivid_set_touch(video_drvdata(file), i); 200 } 201 202 static void vivid_fill_buff_noise(__s16 *tch_buf, int size) 203 { 204 int i; 205 206 /* Fill 10% of the values within range -3 and 3, zero the others */ 207 for (i = 0; i < size; i++) { 208 unsigned int rand = get_random_u32(); 209 210 if (rand % 10) 211 tch_buf[i] = 0; 212 else 213 tch_buf[i] = (rand / 10) % 7 - 3; 214 } 215 } 216 217 static inline int get_random_pressure(void) 218 { 219 return get_random_u32_below(VIVID_PRESSURE_LIMIT); 220 } 221 222 static void vivid_tch_buf_set(struct v4l2_pix_format *f, 223 __s16 *tch_buf, 224 int index) 225 { 226 unsigned int x = index % f->width; 227 unsigned int y = index / f->width; 228 unsigned int offset = VIVID_MIN_PRESSURE; 229 230 tch_buf[index] = offset + get_random_pressure(); 231 offset /= 2; 232 if (x) 233 tch_buf[index - 1] = offset + get_random_pressure(); 234 if (x < f->width - 1) 235 tch_buf[index + 1] = offset + get_random_pressure(); 236 if (y) 237 tch_buf[index - f->width] = offset + get_random_pressure(); 238 if (y < f->height - 1) 239 tch_buf[index + f->width] = offset + get_random_pressure(); 240 offset /= 2; 241 if (x && y) 242 tch_buf[index - 1 - f->width] = offset + get_random_pressure(); 243 if (x < f->width - 1 && y) 244 tch_buf[index + 1 - f->width] = offset + get_random_pressure(); 245 if (x && y < f->height - 1) 246 tch_buf[index - 1 + f->width] = offset + get_random_pressure(); 247 if (x < f->width - 1 && y < f->height - 1) 248 tch_buf[index + 1 + f->width] = offset + get_random_pressure(); 249 } 250 251 void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf) 252 { 253 struct v4l2_pix_format *f = &dev->tch_format; 254 int size = f->width * f->height; 255 int x, y, xstart, ystart, offset_x, offset_y; 256 unsigned int test_pattern, test_pat_idx, rand; 257 258 __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 259 260 buf->vb.sequence = dev->touch_cap_with_seq_wrap_count; 261 test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX; 262 test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT; 263 264 vivid_fill_buff_noise(tch_buf, size); 265 266 if (test_pat_idx >= TCH_PATTERN_COUNT) 267 return; 268 269 if (test_pat_idx == 0) 270 dev->tch_pat_random = get_random_u32(); 271 rand = dev->tch_pat_random; 272 273 switch (test_pattern) { 274 case SINGLE_TAP: 275 if (test_pat_idx == 2) 276 vivid_tch_buf_set(f, tch_buf, rand % size); 277 break; 278 case DOUBLE_TAP: 279 if (test_pat_idx == 2 || test_pat_idx == 4) 280 vivid_tch_buf_set(f, tch_buf, rand % size); 281 break; 282 case TRIPLE_TAP: 283 if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6) 284 vivid_tch_buf_set(f, tch_buf, rand % size); 285 break; 286 case MOVE_LEFT_TO_RIGHT: 287 vivid_tch_buf_set(f, tch_buf, 288 (rand % f->height) * f->width + 289 test_pat_idx * 290 (f->width / TCH_PATTERN_COUNT)); 291 break; 292 case ZOOM_IN: 293 x = f->width / 2; 294 y = f->height / 2; 295 offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) / 296 TCH_PATTERN_COUNT; 297 offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) / 298 TCH_PATTERN_COUNT; 299 vivid_tch_buf_set(f, tch_buf, 300 (x - offset_x) + f->width * (y - offset_y)); 301 vivid_tch_buf_set(f, tch_buf, 302 (x + offset_x) + f->width * (y + offset_y)); 303 break; 304 case ZOOM_OUT: 305 x = f->width / 2; 306 y = f->height / 2; 307 offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT; 308 offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT; 309 vivid_tch_buf_set(f, tch_buf, 310 (x - offset_x) + f->width * (y - offset_y)); 311 vivid_tch_buf_set(f, tch_buf, 312 (x + offset_x) + f->width * (y + offset_y)); 313 break; 314 case PALM_PRESS: 315 for (x = 0; x < f->width; x++) 316 for (y = f->height / 2; y < f->height; y++) 317 tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE + 318 get_random_pressure(); 319 break; 320 case MULTIPLE_PRESS: 321 /* 16 pressure points */ 322 for (y = 0; y < 4; y++) { 323 for (x = 0; x < 4; x++) { 324 ystart = (y * f->height) / 4 + f->height / 8; 325 xstart = (x * f->width) / 4 + f->width / 8; 326 vivid_tch_buf_set(f, tch_buf, 327 ystart * f->width + xstart); 328 } 329 } 330 break; 331 } 332 #ifdef __BIG_ENDIAN__ 333 for (x = 0; x < size; x++) 334 tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]); 335 #endif 336 } 337