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 (sizes[0] < size) 21 return -EINVAL; 22 } else { 23 sizes[0] = size; 24 } 25 26 if (vq->num_buffers + *nbuffers < 2) 27 *nbuffers = 2 - vq->num_buffers; 28 29 *nplanes = 1; 30 return 0; 31 } 32 33 static int touch_cap_buf_prepare(struct vb2_buffer *vb) 34 { 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; 38 39 if (dev->buf_prepare_error) { 40 /* 41 * Error injection: test what happens if buf_prepare() returns 42 * an error. 43 */ 44 dev->buf_prepare_error = false; 45 return -EINVAL; 46 } 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); 50 return -EINVAL; 51 } 52 vb2_set_plane_payload(vb, 0, size); 53 54 return 0; 55 } 56 57 static void touch_cap_buf_queue(struct vb2_buffer *vb) 58 { 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); 62 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); 67 } 68 69 static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count) 70 { 71 struct vivid_dev *dev = vb2_get_drv_priv(vq); 72 int err; 73 74 dev->touch_cap_seq_count = 0; 75 if (dev->start_streaming_error) { 76 dev->start_streaming_error = false; 77 err = -EINVAL; 78 } else { 79 err = vivid_start_generating_touch_cap(dev); 80 } 81 if (err) { 82 struct vivid_buffer *buf, *tmp; 83 84 list_for_each_entry_safe(buf, tmp, 85 &dev->touch_cap_active, list) { 86 list_del(&buf->list); 87 vb2_buffer_done(&buf->vb.vb2_buf, 88 VB2_BUF_STATE_QUEUED); 89 } 90 } 91 return err; 92 } 93 94 /* abort streaming and wait for last buffer */ 95 static void touch_cap_stop_streaming(struct vb2_queue *vq) 96 { 97 struct vivid_dev *dev = vb2_get_drv_priv(vq); 98 99 vivid_stop_generating_touch_cap(dev); 100 } 101 102 static void touch_cap_buf_request_complete(struct vb2_buffer *vb) 103 { 104 struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); 105 106 v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap); 107 } 108 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, 118 }; 119 120 int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) 121 { 122 if (f->index) 123 return -EINVAL; 124 125 f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; 126 return 0; 127 } 128 129 int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f) 130 { 131 struct vivid_dev *dev = video_drvdata(file); 132 133 if (dev->multiplanar) 134 return -ENOTTY; 135 f->fmt.pix = dev->tch_format; 136 return 0; 137 } 138 139 int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f) 140 { 141 struct vivid_dev *dev = video_drvdata(file); 142 struct v4l2_format sp_fmt; 143 144 if (!dev->multiplanar) 145 return -ENOTTY; 146 sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 147 sp_fmt.fmt.pix = dev->tch_format; 148 fmt_sp2mp(&sp_fmt, f); 149 return 0; 150 } 151 152 int vivid_g_parm_tch(struct file *file, void *priv, 153 struct v4l2_streamparm *parm) 154 { 155 struct vivid_dev *dev = video_drvdata(file); 156 157 if (parm->type != (dev->multiplanar ? 158 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : 159 V4L2_BUF_TYPE_VIDEO_CAPTURE)) 160 return -EINVAL; 161 162 parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 163 parm->parm.capture.timeperframe = dev->timeperframe_tch_cap; 164 parm->parm.capture.readbuffers = 1; 165 return 0; 166 } 167 168 int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp) 169 { 170 if (inp->index) 171 return -EINVAL; 172 173 inp->type = V4L2_INPUT_TYPE_TOUCH; 174 strscpy(inp->name, "Vivid Touch", sizeof(inp->name)); 175 inp->capabilities = 0; 176 return 0; 177 } 178 179 int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i) 180 { 181 *i = 0; 182 return 0; 183 } 184 185 int vivid_set_touch(struct vivid_dev *dev, unsigned int i) 186 { 187 struct v4l2_pix_format *f = &dev->tch_format; 188 189 if (i) 190 return -EINVAL; 191 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); 199 return 0; 200 } 201 202 int vivid_s_input_tch(struct file *file, void *priv, unsigned int i) 203 { 204 return vivid_set_touch(video_drvdata(file), i); 205 } 206 207 static void vivid_fill_buff_noise(__s16 *tch_buf, int size) 208 { 209 int i; 210 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_u32(); 214 215 if (rand % 10) 216 tch_buf[i] = 0; 217 else 218 tch_buf[i] = (rand / 10) % 7 - 3; 219 } 220 } 221 222 static inline int get_random_pressure(void) 223 { 224 return prandom_u32_max(VIVID_PRESSURE_LIMIT); 225 } 226 227 static void vivid_tch_buf_set(struct v4l2_pix_format *f, 228 __s16 *tch_buf, 229 int index) 230 { 231 unsigned int x = index % f->width; 232 unsigned int y = index / f->width; 233 unsigned int offset = VIVID_MIN_PRESSURE; 234 235 tch_buf[index] = offset + get_random_pressure(); 236 offset /= 2; 237 if (x) 238 tch_buf[index - 1] = offset + get_random_pressure(); 239 if (x < f->width - 1) 240 tch_buf[index + 1] = offset + get_random_pressure(); 241 if (y) 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(); 245 offset /= 2; 246 if (x && y) 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(); 254 } 255 256 void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf) 257 { 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; 262 263 __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); 264 265 buf->vb.sequence = dev->touch_cap_with_seq_wrap_count; 266 test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX; 267 test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT; 268 269 vivid_fill_buff_noise(tch_buf, size); 270 271 if (test_pat_idx >= TCH_PATTERN_COUNT) 272 return; 273 274 if (test_pat_idx == 0) 275 dev->tch_pat_random = get_random_u32(); 276 rand = dev->tch_pat_random; 277 278 switch (test_pattern) { 279 case SINGLE_TAP: 280 if (test_pat_idx == 2) 281 vivid_tch_buf_set(f, tch_buf, rand % size); 282 break; 283 case DOUBLE_TAP: 284 if (test_pat_idx == 2 || test_pat_idx == 4) 285 vivid_tch_buf_set(f, tch_buf, rand % size); 286 break; 287 case TRIPLE_TAP: 288 if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6) 289 vivid_tch_buf_set(f, tch_buf, rand % size); 290 break; 291 case MOVE_LEFT_TO_RIGHT: 292 vivid_tch_buf_set(f, tch_buf, 293 (rand % f->height) * f->width + 294 test_pat_idx * 295 (f->width / TCH_PATTERN_COUNT)); 296 break; 297 case ZOOM_IN: 298 x = f->width / 2; 299 y = f->height / 2; 300 offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) / 301 TCH_PATTERN_COUNT; 302 offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) / 303 TCH_PATTERN_COUNT; 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)); 308 break; 309 case ZOOM_OUT: 310 x = f->width / 2; 311 y = f->height / 2; 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)); 318 break; 319 case PALM_PRESS: 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(); 324 break; 325 case MULTIPLE_PRESS: 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); 333 } 334 } 335 break; 336 } 337 #ifdef __BIG_ENDIAN__ 338 for (x = 0; x < size; x++) 339 tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]); 340 #endif 341 } 342