brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 3600b08 Raw
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