Commit 3d15c764 authored by Vandana BN's avatar Vandana BN Committed by Mauro Carvalho Chehab

media: vivid: Add touch support

Support to emulate touch devices in vivid driver.
It generates touch patterns simulating single tap, double tap, triple
tap, move from left to right, zoom in, zoom out, palm press simulating
large area being pressed on screen, and simulating 16 different
simultaneous touch points.The values generated are based on
behavior of the rmi_f54 driver.
Signed-off-by: default avatarVandana BN <bnvandana@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 8c956f3b
......@@ -3,7 +3,8 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
vivid-osd.o vivid-meta-cap.o vivid-meta-out.o
vivid-osd.o vivid-meta-cap.o vivid-meta-out.o \
vivid-kthread-touch.o vivid-touch-cap.o
ifeq ($(CONFIG_VIDEO_VIVID_CEC),y)
vivid-objs += vivid-cec.o
endif
......
This diff is collapsed.
......@@ -133,6 +133,7 @@ struct vivid_dev {
struct media_pad sdr_cap_pad;
struct media_pad meta_cap_pad;
struct media_pad meta_out_pad;
struct media_pad touch_cap_pad;
#endif
struct v4l2_ctrl_handler ctrl_hdl_user_gen;
struct v4l2_ctrl_handler ctrl_hdl_user_vid;
......@@ -159,6 +160,8 @@ struct vivid_dev {
struct v4l2_ctrl_handler ctrl_hdl_meta_cap;
struct video_device meta_out_dev;
struct v4l2_ctrl_handler ctrl_hdl_meta_out;
struct video_device touch_cap_dev;
struct v4l2_ctrl_handler ctrl_hdl_touch_cap;
spinlock_t slock;
struct mutex mutex;
......@@ -173,6 +176,7 @@ struct vivid_dev {
u32 radio_tx_caps;
u32 meta_cap_caps;
u32 meta_out_caps;
u32 touch_cap_caps;
/* supported features */
bool multiplanar;
......@@ -201,6 +205,7 @@ struct vivid_dev {
bool has_meta_cap;
bool has_meta_out;
bool has_tv_tuner;
bool has_touch_cap;
bool can_loop_video;
......@@ -404,6 +409,8 @@ struct vivid_dev {
struct list_head vbi_cap_active;
struct vb2_queue vb_meta_cap_q;
struct list_head meta_cap_active;
struct vb2_queue vb_touch_cap_q;
struct list_head touch_cap_active;
/* thread for generating video capture stream */
struct task_struct *kthread_vid_cap;
......@@ -425,6 +432,19 @@ struct vivid_dev {
u32 meta_cap_seq_count;
bool meta_cap_streaming;
/* Touch capture */
struct task_struct *kthread_touch_cap;
unsigned long jiffies_touch_cap;
u64 touch_cap_stream_start;
u32 touch_cap_seq_offset;
bool touch_cap_seq_resync;
u32 touch_cap_seq_start;
u32 touch_cap_seq_count;
bool touch_cap_streaming;
struct v4l2_fract timeperframe_tch_cap;
struct v4l2_pix_format tch_format;
int tch_pat_random;
/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
......
......@@ -1508,6 +1508,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap;
struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out;
struct v4l2_ctrl_handler *hdl_tch_cap = &dev->ctrl_hdl_touch_cap;
struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
.ops = &vivid_vid_cap_ctrl_ops,
......@@ -1551,6 +1552,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_meta_out, 2);
v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_tch_cap, 2);
v4l2_ctrl_new_custom(hdl_tch_cap, &vivid_ctrl_class, NULL);
/* User Controls */
dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
......@@ -1904,6 +1907,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
return hdl_meta_out->error;
dev->meta_out_dev.ctrl_handler = hdl_meta_out;
}
if (dev->has_touch_cap) {
v4l2_ctrl_add_handler(hdl_tch_cap, hdl_user_gen, NULL, false);
v4l2_ctrl_add_handler(hdl_tch_cap, hdl_streaming, NULL, false);
if (hdl_tch_cap->error)
return hdl_tch_cap->error;
dev->touch_cap_dev.ctrl_handler = hdl_tch_cap;
}
return 0;
}
......@@ -1925,4 +1935,5 @@ void vivid_free_controls(struct vivid_dev *dev)
v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_touch_cap);
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-kthread-touch.c - touch capture thread support functions.
*
*/
#include <linux/freezer.h>
#include "vivid-core.h"
#include "vivid-kthread-touch.h"
#include "vivid-touch-cap.h"
static noinline_for_stack void vivid_thread_tch_cap_tick(struct vivid_dev *dev,
int dropped_bufs)
{
struct vivid_buffer *tch_cap_buf = NULL;
spin_lock(&dev->slock);
if (!list_empty(&dev->touch_cap_active)) {
tch_cap_buf = list_entry(dev->touch_cap_active.next,
struct vivid_buffer, list);
list_del(&tch_cap_buf->list);
}
spin_unlock(&dev->slock);
if (tch_cap_buf) {
v4l2_ctrl_request_setup(tch_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_touch_cap);
vivid_fillbuff_tch(dev, tch_cap_buf);
v4l2_ctrl_request_complete(tch_cap_buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_touch_cap);
vb2_buffer_done(&tch_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "touch_cap buffer %d done\n",
tch_cap_buf->vb.vb2_buf.index);
tch_cap_buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
}
dev->dqbuf_error = false;
}
static int vivid_thread_touch_cap(void *data)
{
struct vivid_dev *dev = data;
u64 numerators_since_start;
u64 buffers_since_start;
u64 next_jiffies_since_start;
unsigned long jiffies_since_start;
unsigned long cur_jiffies;
unsigned int wait_jiffies;
unsigned int numerator;
unsigned int denominator;
int dropped_bufs;
dprintk(dev, 1, "Touch Capture Thread Start\n");
set_freezable();
/* Resets frame counters */
dev->touch_cap_seq_offset = 0;
dev->touch_cap_seq_count = 0;
dev->touch_cap_seq_resync = false;
dev->jiffies_touch_cap = jiffies;
for (;;) {
try_to_freeze();
if (kthread_should_stop())
break;
if (!mutex_trylock(&dev->mutex)) {
schedule_timeout_uninterruptible(1);
continue;
}
cur_jiffies = jiffies;
if (dev->touch_cap_seq_resync) {
dev->jiffies_touch_cap = cur_jiffies;
dev->touch_cap_seq_offset = dev->touch_cap_seq_count + 1;
dev->touch_cap_seq_count = 0;
dev->cap_seq_resync = false;
}
denominator = dev->timeperframe_tch_cap.denominator;
numerator = dev->timeperframe_tch_cap.numerator;
/* Calculate the number of jiffies since we started streaming */
jiffies_since_start = cur_jiffies - dev->jiffies_touch_cap;
/* Get the number of buffers streamed since the start */
buffers_since_start = (u64)jiffies_since_start * denominator +
(HZ * numerator) / 2;
do_div(buffers_since_start, HZ * numerator);
/*
* After more than 0xf0000000 (rounded down to a multiple of
* 'jiffies-per-day' to ease jiffies_to_msecs calculation)
* jiffies have passed since we started streaming reset the
* counters and keep track of the sequence offset.
*/
if (jiffies_since_start > JIFFIES_RESYNC) {
dev->jiffies_touch_cap = cur_jiffies;
dev->cap_seq_offset = buffers_since_start;
buffers_since_start = 0;
}
dropped_bufs = buffers_since_start + dev->touch_cap_seq_offset - dev->touch_cap_seq_count;
dev->touch_cap_seq_count = buffers_since_start + dev->touch_cap_seq_offset;
vivid_thread_tch_cap_tick(dev, dropped_bufs);
/*
* Calculate the number of 'numerators' streamed
* since we started, including the current buffer.
*/
numerators_since_start = ++buffers_since_start * numerator;
/* And the number of jiffies since we started */
jiffies_since_start = jiffies - dev->jiffies_touch_cap;
mutex_unlock(&dev->mutex);
/*
* Calculate when that next buffer is supposed to start
* in jiffies since we started streaming.
*/
next_jiffies_since_start = numerators_since_start * HZ +
denominator / 2;
do_div(next_jiffies_since_start, denominator);
/* If it is in the past, then just schedule asap */
if (next_jiffies_since_start < jiffies_since_start)
next_jiffies_since_start = jiffies_since_start;
wait_jiffies = next_jiffies_since_start - jiffies_since_start;
schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
}
dprintk(dev, 1, "Touch Capture Thread End\n");
return 0;
}
int vivid_start_generating_touch_cap(struct vivid_dev *dev)
{
if (dev->kthread_touch_cap) {
dev->touch_cap_streaming = true;
return 0;
}
dev->kthread_touch_cap = kthread_run(vivid_thread_touch_cap, dev,
"%s-tch-cap", dev->v4l2_dev.name);
if (IS_ERR(dev->kthread_touch_cap)) {
int err = PTR_ERR(dev->kthread_touch_cap);
dev->kthread_touch_cap = NULL;
v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
return err;
}
dev->touch_cap_streaming = true;
dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
}
void vivid_stop_generating_touch_cap(struct vivid_dev *dev)
{
if (!dev->kthread_touch_cap)
return;
dev->touch_cap_streaming = false;
while (!list_empty(&dev->touch_cap_active)) {
struct vivid_buffer *buf;
buf = list_entry(dev->touch_cap_active.next,
struct vivid_buffer, list);
list_del(&buf->list);
v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
&dev->ctrl_hdl_touch_cap);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
dprintk(dev, 2, "touch_cap buffer %d done\n",
buf->vb.vb2_buf.index);
}
kthread_stop(dev->kthread_touch_cap);
dev->kthread_touch_cap = NULL;
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-kthread-cap.h - video/vbi capture thread support functions.
*
*/
#ifndef _VIVID_KTHREAD_CAP_H_
#define _VIVID_KTHREAD_CAP_H_
int vivid_start_generating_touch_cap(struct vivid_dev *dev);
void vivid_stop_generating_touch_cap(struct vivid_dev *dev);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* vivid-touch-cap.c - touch support functions.
*/
#include "vivid-core.h"
#include "vivid-kthread-touch.h"
#include "vivid-touch-cap.h"
static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
struct device *alloc_devs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
struct v4l2_pix_format *f = &dev->tch_format;
unsigned int size = f->sizeimage;
if (*nplanes) {
if (sizes[0] < size)
return -EINVAL;
} else {
sizes[0] = size;
}
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
*nplanes = 1;
return 0;
}
static int touch_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct v4l2_pix_format *f = &dev->tch_format;
unsigned int size = f->sizeimage;
if (dev->buf_prepare_error) {
/*
* Error injection: test what happens if buf_prepare() returns
* an error.
*/
dev->buf_prepare_error = false;
return -EINVAL;
}
if (vb2_plane_size(vb, 0) < size) {
dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
__func__, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
vb2_set_plane_payload(vb, 0, size);
return 0;
}
static void touch_cap_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
spin_lock(&dev->slock);
list_add_tail(&buf->list, &dev->touch_cap_active);
spin_unlock(&dev->slock);
}
static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
int err;
dev->touch_cap_seq_count = 0;
if (dev->start_streaming_error) {
dev->start_streaming_error = false;
err = -EINVAL;
} else {
err = vivid_start_generating_touch_cap(dev);
}
if (err) {
struct vivid_buffer *buf, *tmp;
list_for_each_entry_safe(buf, tmp,
&dev->touch_cap_active, list) {
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
}
return err;
}
/* abort streaming and wait for last buffer */
static void touch_cap_stop_streaming(struct vb2_queue *vq)
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
vivid_stop_generating_touch_cap(dev);
}
static void touch_cap_buf_request_complete(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap);
}
const struct vb2_ops vivid_touch_cap_qops = {
.queue_setup = touch_cap_queue_setup,
.buf_prepare = touch_cap_buf_prepare,
.buf_queue = touch_cap_buf_queue,
.start_streaming = touch_cap_start_streaming,
.stop_streaming = touch_cap_stop_streaming,
.buf_request_complete = touch_cap_buf_request_complete,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f)
{
if (f->index)
return -EINVAL;
f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
return 0;
}
int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
{
struct vivid_dev *dev = video_drvdata(file);
f->fmt.pix = dev->tch_format;
return 0;
}
int vivid_g_parm_tch(struct file *file, void *priv,
struct v4l2_streamparm *parm)
{
struct vivid_dev *dev = video_drvdata(file);
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
parm->parm.capture.timeperframe = dev->timeperframe_tch_cap;
parm->parm.capture.readbuffers = 1;
return 0;
}
int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp)
{
if (inp->index)
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_TOUCH;
strscpy(inp->name, "Vivid Touch", sizeof(inp->name));
inp->capabilities = 0;
return 0;
}
int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i)
{
*i = 0;
return 0;
}
int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
{
struct v4l2_pix_format *f = &dev->tch_format;
if (i)
return -EINVAL;
f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
f->width = VIVID_TCH_WIDTH;
f->height = VIVID_TCH_HEIGHT;
f->field = V4L2_FIELD_NONE;
f->colorspace = V4L2_COLORSPACE_RAW;
f->bytesperline = f->width * sizeof(s16);
f->sizeimage = f->width * f->height * sizeof(s16);
return 0;
}
int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
{
return vivid_set_touch(video_drvdata(file), i);
}
static void vivid_fill_buff_noise(__s16 *tch_buf, int size)
{
int i;
/* Fill 10% of the values within range -3 and 3, zero the others */
for (i = 0; i < size; i++) {
unsigned int rand = get_random_int();
if (rand % 10)
tch_buf[i] = 0;
else
tch_buf[i] = (rand / 10) % 7 - 3;
}
}
static inline int get_random_pressure(void)
{
return get_random_int() % VIVID_PRESSURE_LIMIT;
}
static void vivid_tch_buf_set(struct v4l2_pix_format *f,
__s16 *tch_buf,
int index)
{
unsigned int x = index % f->width;
unsigned int y = index / f->width;
unsigned int offset = VIVID_MIN_PRESSURE;
tch_buf[index] = offset + get_random_pressure();
offset /= 2;
if (x)
tch_buf[index - 1] = offset + get_random_pressure();
if (x < f->width - 1)
tch_buf[index + 1] = offset + get_random_pressure();
if (y)
tch_buf[index - f->width] = offset + get_random_pressure();
if (y < f->height - 1)
tch_buf[index + f->width] = offset + get_random_pressure();
offset /= 2;
if (x && y)
tch_buf[index - 1 - f->width] = offset + get_random_pressure();
if (x < f->width - 1 && y)
tch_buf[index + 1 - f->width] = offset + get_random_pressure();
if (x && y < f->height - 1)
tch_buf[index - 1 + f->width] = offset + get_random_pressure();
if (x < f->width - 1 && y < f->height - 1)
tch_buf[index + 1 + f->width] = offset + get_random_pressure();
}
void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
{
struct v4l2_pix_format *f = &dev->tch_format;
int size = f->width * f->height;
int x, y, xstart, ystart, offset_x, offset_y;
unsigned int test_pattern, test_pat_idx, rand;
__s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
buf->vb.sequence = dev->touch_cap_seq_count;
test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX;
test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT;
vivid_fill_buff_noise(tch_buf, size);
if (test_pat_idx >= TCH_PATTERN_COUNT)
return;
if (test_pat_idx == 0)
dev->tch_pat_random = get_random_int();
rand = dev->tch_pat_random;
switch (test_pattern) {
case SINGLE_TAP:
if (test_pat_idx == 2)
vivid_tch_buf_set(f, tch_buf, rand % size);
break;
case DOUBLE_TAP:
if (test_pat_idx == 2 || test_pat_idx == 4)
vivid_tch_buf_set(f, tch_buf, rand % size);
break;
case TRIPLE_TAP:
if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6)
vivid_tch_buf_set(f, tch_buf, rand % size);
break;
case MOVE_LEFT_TO_RIGHT:
vivid_tch_buf_set(f, tch_buf,
(rand % f->height) * f->width +
test_pat_idx *
(f->width / TCH_PATTERN_COUNT));
break;
case ZOOM_IN:
x = f->width / 2;
y = f->height / 2;
offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) /
TCH_PATTERN_COUNT;
offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) /
TCH_PATTERN_COUNT;
vivid_tch_buf_set(f, tch_buf,
(x - offset_x) + f->width * (y - offset_y));
vivid_tch_buf_set(f, tch_buf,
(x + offset_x) + f->width * (y + offset_y));
break;
case ZOOM_OUT:
x = f->width / 2;
y = f->height / 2;
offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT;
offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT;
vivid_tch_buf_set(f, tch_buf,
(x - offset_x) + f->width * (y - offset_y));
vivid_tch_buf_set(f, tch_buf,
(x + offset_x) + f->width * (y + offset_y));
break;
case PALM_PRESS:
for (x = 0; x < f->width; x++)
for (y = f->height / 2; y < f->height; y++)
tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE +
get_random_pressure();
break;
case MULTIPLE_PRESS:
/* 16 pressure points */
for (y = 0; y < 4; y++) {
for (x = 0; x < 4; x++) {
ystart = (y * f->height) / 4 + f->height / 8;
xstart = (x * f->width) / 4 + f->width / 8;
vivid_tch_buf_set(f, tch_buf,
ystart * f->width + xstart);
}
}
break;
}
#ifdef __BIG_ENDIAN__
for (x = 0; x < size; x++)
tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]);
#endif
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* vivid-touch-cap.h - touch support functions.
*/
#ifndef _VIVID_TOUCH_CAP_H_
#define _VIVID_TOUCH_CAP_H_
#define VIVID_TCH_HEIGHT 12
#define VIVID_TCH_WIDTH 21
#define VIVID_MIN_PRESSURE 180
#define VIVID_PRESSURE_LIMIT 40
#define TCH_SEQ_COUNT 16
#define TCH_PATTERN_COUNT 12
enum vivid_tch_test {
SINGLE_TAP,
DOUBLE_TAP,
TRIPLE_TAP,
MOVE_LEFT_TO_RIGHT,
ZOOM_IN,
ZOOM_OUT,
PALM_PRESS,
MULTIPLE_PRESS,
TEST_CASE_MAX
};
extern const struct vb2_ops vivid_touch_cap_qops;
int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f);
int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f);
int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp);
int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i);
int vivid_s_input_tch(struct file *file, void *priv, unsigned int i);
void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf);
int vivid_set_touch(struct vivid_dev *dev, unsigned int i);
int vivid_g_parm_tch(struct file *file, void *priv,
struct v4l2_streamparm *parm);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment