* [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device
@ 2019-10-22 7:51 bnvandana
2019-10-22 7:51 ` Vandana BN
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: bnvandana @ 2019-10-22 7:51 UTC (permalink / raw)
This patch adds support for touch devices in the vivid driver.
Current code provides a framework for touch support and passes
compliance tests.
TODO: Add touch emulation.
Thank you.
Regards,
Vandana.
Vandana BN (2):
v4l2-core: fix touch support in v4l_g_fmt
vivid: Add touch support
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 134 ++++++++++-
drivers/media/platform/vivid/vivid-core.h | 18 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../media/platform/vivid/vivid-kthread-cap.c | 1 -
.../platform/vivid/vivid-kthread-touch.c | 211 ++++++++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 ++
.../media/platform/vivid/vivid-touch-cap.c | 160 +++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 18 ++
drivers/media/v4l2-core/v4l2-ioctl.c | 33 +--
10 files changed, 578 insertions(+), 24 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
--
2.17.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device
2019-10-22 7:51 [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device bnvandana
@ 2019-10-22 7:51 ` Vandana BN
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt bnvandana
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support bnvandana
2 siblings, 0 replies; 9+ messages in thread
From: Vandana BN @ 2019-10-22 7:51 UTC (permalink / raw)
This patch adds support for touch devices in the vivid driver.
Current code provides a framework for touch support and passes
compliance tests.
TODO: Add touch emulation.
Thank you.
Regards,
Vandana.
Vandana BN (2):
v4l2-core: fix touch support in v4l_g_fmt
vivid: Add touch support
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 134 ++++++++++-
drivers/media/platform/vivid/vivid-core.h | 18 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../media/platform/vivid/vivid-kthread-cap.c | 1 -
.../platform/vivid/vivid-kthread-touch.c | 211 ++++++++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 ++
.../media/platform/vivid/vivid-touch-cap.c | 160 +++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 18 ++
drivers/media/v4l2-core/v4l2-ioctl.c | 33 +--
10 files changed, 578 insertions(+), 24 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
--
2.17.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt
2019-10-22 7:51 [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device bnvandana
2019-10-22 7:51 ` Vandana BN
@ 2019-10-22 7:51 ` bnvandana
2019-10-22 7:51 ` Vandana BN
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support bnvandana
2 siblings, 1 reply; 9+ messages in thread
From: bnvandana @ 2019-10-22 7:51 UTC (permalink / raw)
v4l_s_fmt, for VFL_TYPE_TOUCH, sets unneeded members of
the v4l2_pix_format structure to default values.This was
missing in v4l_g_fmt, which would lead to failures in
v4l2-compliance tests.
Signed-off-by: Vandana BN <bnvandana at gmail.com>
---
drivers/media/v4l2-core/v4l2-ioctl.c | 33 +++++++++++++++-------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 2753073cf340..0ade0540ee5b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1477,10 +1477,26 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
return ret;
}
+static void v4l_pix_format_touch(struct v4l2_pix_format *p)
+{
+ /*
+ * The v4l2_pix_format structure contains fields that make no sense for
+ * touch. Set them to default values in this case.
+ */
+
+ p->field = V4L2_FIELD_NONE;
+ p->colorspace = V4L2_COLORSPACE_RAW;
+ p->flags = 0;
+ p->ycbcr_enc = 0;
+ p->quantization = 0;
+ p->xfer_func = 0;
+}
+
static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct v4l2_format *p = arg;
+ struct video_device *vfd = video_devdata(file);
int ret = check_fmt(file, p->type);
if (ret)
@@ -1518,6 +1534,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ if (vfd->vfl_type == VFL_TYPE_TOUCH)
+ v4l_pix_format_touch(&p->fmt.pix);
return ret;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
@@ -1555,21 +1573,6 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
return -EINVAL;
}
-static void v4l_pix_format_touch(struct v4l2_pix_format *p)
-{
- /*
- * The v4l2_pix_format structure contains fields that make no sense for
- * touch. Set them to default values in this case.
- */
-
- p->field = V4L2_FIELD_NONE;
- p->colorspace = V4L2_COLORSPACE_RAW;
- p->flags = 0;
- p->ycbcr_enc = 0;
- p->quantization = 0;
- p->xfer_func = 0;
-}
-
static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt bnvandana
@ 2019-10-22 7:51 ` Vandana BN
0 siblings, 0 replies; 9+ messages in thread
From: Vandana BN @ 2019-10-22 7:51 UTC (permalink / raw)
v4l_s_fmt, for VFL_TYPE_TOUCH, sets unneeded members of
the v4l2_pix_format structure to default values.This was
missing in v4l_g_fmt, which would lead to failures in
v4l2-compliance tests.
Signed-off-by: Vandana BN <bnvandana at gmail.com>
---
drivers/media/v4l2-core/v4l2-ioctl.c | 33 +++++++++++++++-------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 2753073cf340..0ade0540ee5b 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1477,10 +1477,26 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
return ret;
}
+static void v4l_pix_format_touch(struct v4l2_pix_format *p)
+{
+ /*
+ * The v4l2_pix_format structure contains fields that make no sense for
+ * touch. Set them to default values in this case.
+ */
+
+ p->field = V4L2_FIELD_NONE;
+ p->colorspace = V4L2_COLORSPACE_RAW;
+ p->flags = 0;
+ p->ycbcr_enc = 0;
+ p->quantization = 0;
+ p->xfer_func = 0;
+}
+
static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct v4l2_format *p = arg;
+ struct video_device *vfd = video_devdata(file);
int ret = check_fmt(file, p->type);
if (ret)
@@ -1518,6 +1534,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
/* just in case the driver zeroed it again */
p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ if (vfd->vfl_type == VFL_TYPE_TOUCH)
+ v4l_pix_format_touch(&p->fmt.pix);
return ret;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg);
@@ -1555,21 +1573,6 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
return -EINVAL;
}
-static void v4l_pix_format_touch(struct v4l2_pix_format *p)
-{
- /*
- * The v4l2_pix_format structure contains fields that make no sense for
- * touch. Set them to default values in this case.
- */
-
- p->field = V4L2_FIELD_NONE;
- p->colorspace = V4L2_COLORSPACE_RAW;
- p->flags = 0;
- p->ycbcr_enc = 0;
- p->quantization = 0;
- p->xfer_func = 0;
-}
-
static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support
2019-10-22 7:51 [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device bnvandana
2019-10-22 7:51 ` Vandana BN
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt bnvandana
@ 2019-10-22 7:51 ` bnvandana
2019-10-22 7:51 ` Vandana BN
2019-11-04 12:45 ` [Linux-kernel-mentees] [PATCH v2] " Vandana BN
2 siblings, 2 replies; 9+ messages in thread
From: bnvandana @ 2019-10-22 7:51 UTC (permalink / raw)
Support to emulate touch devices in vivid driver.
Signed-off-by: Vandana BN <bnvandana at gmail.com>
---
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 134 ++++++++++-
drivers/media/platform/vivid/vivid-core.h | 18 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../media/platform/vivid/vivid-kthread-cap.c | 1 -
.../platform/vivid/vivid-kthread-touch.c | 211 ++++++++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 ++
.../media/platform/vivid/vivid-touch-cap.c | 160 +++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 18 ++
9 files changed, 560 insertions(+), 9 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index e8a50c506dc9..b12ad0152a3e 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -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
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index bd91916980b9..ab1598c606d2 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -39,6 +39,7 @@
#include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#include "vivid-meta-out.h"
+#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
@@ -89,6 +90,10 @@ static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_out_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
+static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(touch_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
+
static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -110,10 +115,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
* vbi-out + vid-out + meta-cap
*/
static unsigned int node_types[VIVID_MAX_DEVS] = {
- [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
+ [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
};
module_param_array(node_types, uint, NULL, 0444);
-MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
+MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
"\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n"
@@ -123,7 +128,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the
"\t\t bit 12: Radio Transmitter node\n"
"\t\t bit 16: Framebuffer for testing overlays\n"
"\t\t bit 17: Metadata Capture node\n"
- "\t\t bit 18: Metadata Output node\n");
+ "\t\t bit 18: Metadata Output node\n"
+ "\t\t bit 19: Touch Capture node\n");
/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -223,7 +229,8 @@ static int vidioc_querycap(struct file *file, void *priv,
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
dev->sdr_cap_caps | dev->meta_cap_caps |
- dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->meta_out_caps | dev->touch_cap_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -255,6 +262,8 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
return vivid_radio_rx_g_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_tuner(file, fh, vt);
}
@@ -266,6 +275,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
return vivid_radio_rx_s_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_tuner(file, fh, vt);
}
@@ -280,6 +291,8 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_frequency(file, fh, vf);
}
@@ -294,6 +307,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_frequency(file, fh, vf);
}
@@ -377,6 +392,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_cap_g_parm(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_g_parm(file, fh, parm);
return vivid_vid_out_g_parm(file, fh, parm);
@@ -387,6 +404,8 @@ static int vidioc_s_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_cap_g_parm(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_s_parm(file, fh, parm);
return -ENOTTY;
@@ -432,6 +451,29 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}
+int vivid_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_enum_input(file, priv, inp);
+ else
+ return vidioc_enum_input(file, priv, inp);
+}
+
+int vivid_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (i >= dev->num_inputs)
+ return -EINVAL;
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return 0;
+ else
+ return vidioc_s_input(file, priv, i);
+}
+
static bool vivid_is_in_use(struct video_device *vdev)
{
unsigned long flags;
@@ -453,7 +495,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev) +
vivid_is_in_use(&dev->meta_cap_dev) +
- vivid_is_in_use(&dev->meta_out_dev);
+ vivid_is_in_use(&dev->meta_out_dev) +
+ vivid_is_in_use(&dev->touch_cap_dev);
return uses == 1;
}
@@ -481,6 +524,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
}
mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner)
@@ -590,9 +634,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enum_input = vivid_enum_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
@@ -856,6 +900,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a metadata output device */
dev->has_meta_out = node_type & 0x40000;
+ /* do we create a touch capture device */
+ dev->has_touch_cap = node_type & 0x80000;
+
/* end detecting feature set */
if (dev->has_vid_cap) {
@@ -929,6 +976,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_audio_outputs)
dev->meta_out_caps |= V4L2_CAP_AUDIO;
}
+ /* set up the capabilities of the touch capture device */
+ if (dev->has_touch_cap) {
+ dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ }
ret = -ENOMEM;
/* initialize the test pattern generator */
@@ -992,6 +1044,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUMAUDIO);
}
if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
@@ -1022,6 +1077,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_FREQUENCY);
}
if (!has_tuner) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
@@ -1030,6 +1087,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_TUNER);
}
if (in_type_counter[HDMI] == 0) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
@@ -1056,6 +1115,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
@@ -1136,6 +1196,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 1;
+ dev->timeperframe_tch_cap.denominator = 10;
+
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
@@ -1148,6 +1212,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->meta_cap_active);
INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
@@ -1336,6 +1401,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
}
+ if (dev->has_touch_cap) {
+ /* initialize touch_cap queue */
+ q = &dev->vb_touch_cap_q;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ if (!allocator)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = &vivid_touch_cap_qops;
+ q->mem_ops = vivid_mem_ops[allocator];
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto unreg_dev;
+ }
#ifdef CONFIG_VIDEO_VIVID_CEC
if (dev->has_vid_cap && in_type_counter[HDMI]) {
@@ -1379,6 +1465,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
@@ -1665,6 +1752,33 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_touch_cap) {
+ vfd = &dev->touch_cap_dev;
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->touch_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_touch_cap_q;
+ vfd->tvnorms = tvnorms_cap;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->touch_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_TOUCH,
+ touch_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 touch capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */
ret = media_device_register(&dev->mdev);
@@ -1681,6 +1795,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0;
unreg_dev:
+ video_unregister_device(&dev->touch_cap_dev);
video_unregister_device(&dev->meta_out_dev);
video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
@@ -1809,6 +1924,11 @@ static int vivid_remove(struct platform_device *pdev)
video_device_node_name(&dev->meta_out_dev));
video_unregister_device(&dev->meta_out_dev);
}
+ if (dev->has_touch_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->touch_cap_dev));
+ video_unregister_device(&dev->touch_cap_dev);
+ }
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index d57066ed31f0..f065f7557f8f 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -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;
@@ -200,6 +204,7 @@ struct vivid_dev {
bool has_fb;
bool has_meta_cap;
bool has_meta_out;
+ bool has_touch_cap;
bool can_loop_video;
@@ -403,10 +408,13 @@ 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;
unsigned long jiffies_vid_cap;
+ struct v4l2_fract timeperframe_tch_cap;
u64 cap_stream_start;
u64 cap_frame_period;
u64 cap_frame_eof_offset;
@@ -424,6 +432,16 @@ 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;
+
/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index b250fc3764e2..c2a5597a6480 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1495,6 +1495,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,
@@ -1538,6 +1539,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,
@@ -1890,6 +1893,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;
}
@@ -1911,4 +1921,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);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 9f981e8bae6e..84deafac0d26 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -779,7 +779,6 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
meta_cap_buf->vb.vb2_buf.index);
meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
}
-
dev->dqbuf_error = false;
update_mv:
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
new file mode 100644
index 000000000000..15406df628f7
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-kthread-touch.h - touch capture thread support functions.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-rect.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.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;
+
+ dprintk(dev, 1, "Touch Capture Thread Tick\n");
+
+ 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);
+ /* Add touch caputre*/
+
+ 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;
+
+ mutex_lock(&dev->mutex);
+ 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_vid_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, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->kthread_touch_cap) {
+ *pstreaming = 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;
+ }
+ *pstreaming = true;
+ dprintk(dev, 1, "returning from %s\n", __func__);
+ return 0;
+}
+
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (!dev->kthread_touch_cap)
+ return;
+
+ *pstreaming = 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);
+ }
+
+ if (dev->touch_cap_streaming)
+ return;
+
+ mutex_unlock(&dev->mutex);
+ kthread_stop(dev->kthread_touch_cap);
+ dev->kthread_touch_cap = NULL;
+ mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
new file mode 100644
index 000000000000..db9cfa1b473c
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
@@ -0,0 +1,13 @@
+/* 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, bool *pstreaming);
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
new file mode 100644
index 000000000000..d791018f1cb6
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-touch-cap.c - touch support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ 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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ 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,
+ &dev->touch_cap_streaming);
+ }
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ vivid_stop_generating_touch_cap(dev, &dev->touch_cap_streaming);
+}
+
+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_tch_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (inp->index >= dev->num_inputs)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_TOUCH;
+ snprintf(inp->name, sizeof(inp->name), "Touch %u",
+ dev->input_name_counter[inp->index]);
+ inp->capabilities = 0;
+ return 0;
+}
+
+int vivid_tch_cap_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+}
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
new file mode 100644
index 000000000000..782a9b84fcac
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-touch-cap.h - touch support functions.
+ */
+#ifndef _VIVID_TOUCH_CAP_H_
+#define _VIVID_TOUCH_CAP_H_
+
+struct vivid_touch_buf {
+ int tmp;
+} __packed;
+
+extern const struct vb2_ops vivid_touch_cap_qops;
+
+int vivid_tch_cap_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm);
+int vivid_tch_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp);
+#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support bnvandana
@ 2019-10-22 7:51 ` Vandana BN
2019-11-04 12:45 ` [Linux-kernel-mentees] [PATCH v2] " Vandana BN
1 sibling, 0 replies; 9+ messages in thread
From: Vandana BN @ 2019-10-22 7:51 UTC (permalink / raw)
Support to emulate touch devices in vivid driver.
Signed-off-by: Vandana BN <bnvandana at gmail.com>
---
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 134 ++++++++++-
drivers/media/platform/vivid/vivid-core.h | 18 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../media/platform/vivid/vivid-kthread-cap.c | 1 -
.../platform/vivid/vivid-kthread-touch.c | 211 ++++++++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 ++
.../media/platform/vivid/vivid-touch-cap.c | 160 +++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 18 ++
9 files changed, 560 insertions(+), 9 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index e8a50c506dc9..b12ad0152a3e 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -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
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index bd91916980b9..ab1598c606d2 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -39,6 +39,7 @@
#include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#include "vivid-meta-out.h"
+#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
@@ -89,6 +90,10 @@ static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_out_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
+static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(touch_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
+
static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -110,10 +115,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
* vbi-out + vid-out + meta-cap
*/
static unsigned int node_types[VIVID_MAX_DEVS] = {
- [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
+ [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
};
module_param_array(node_types, uint, NULL, 0444);
-MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
+MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
"\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n"
@@ -123,7 +128,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the
"\t\t bit 12: Radio Transmitter node\n"
"\t\t bit 16: Framebuffer for testing overlays\n"
"\t\t bit 17: Metadata Capture node\n"
- "\t\t bit 18: Metadata Output node\n");
+ "\t\t bit 18: Metadata Output node\n"
+ "\t\t bit 19: Touch Capture node\n");
/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -223,7 +229,8 @@ static int vidioc_querycap(struct file *file, void *priv,
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
dev->sdr_cap_caps | dev->meta_cap_caps |
- dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->meta_out_caps | dev->touch_cap_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -255,6 +262,8 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
return vivid_radio_rx_g_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_tuner(file, fh, vt);
}
@@ -266,6 +275,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
return vivid_radio_rx_s_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_tuner(file, fh, vt);
}
@@ -280,6 +291,8 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_frequency(file, fh, vf);
}
@@ -294,6 +307,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_frequency(file, fh, vf);
}
@@ -377,6 +392,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_cap_g_parm(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_g_parm(file, fh, parm);
return vivid_vid_out_g_parm(file, fh, parm);
@@ -387,6 +404,8 @@ static int vidioc_s_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_cap_g_parm(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_s_parm(file, fh, parm);
return -ENOTTY;
@@ -432,6 +451,29 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}
+int vivid_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_tch_enum_input(file, priv, inp);
+ else
+ return vidioc_enum_input(file, priv, inp);
+}
+
+int vivid_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (i >= dev->num_inputs)
+ return -EINVAL;
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return 0;
+ else
+ return vidioc_s_input(file, priv, i);
+}
+
static bool vivid_is_in_use(struct video_device *vdev)
{
unsigned long flags;
@@ -453,7 +495,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev) +
vivid_is_in_use(&dev->meta_cap_dev) +
- vivid_is_in_use(&dev->meta_out_dev);
+ vivid_is_in_use(&dev->meta_out_dev) +
+ vivid_is_in_use(&dev->touch_cap_dev);
return uses == 1;
}
@@ -481,6 +524,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
}
mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner)
@@ -590,9 +634,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enum_input = vivid_enum_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
@@ -856,6 +900,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a metadata output device */
dev->has_meta_out = node_type & 0x40000;
+ /* do we create a touch capture device */
+ dev->has_touch_cap = node_type & 0x80000;
+
/* end detecting feature set */
if (dev->has_vid_cap) {
@@ -929,6 +976,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_audio_outputs)
dev->meta_out_caps |= V4L2_CAP_AUDIO;
}
+ /* set up the capabilities of the touch capture device */
+ if (dev->has_touch_cap) {
+ dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ }
ret = -ENOMEM;
/* initialize the test pattern generator */
@@ -992,6 +1044,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUMAUDIO);
}
if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
@@ -1022,6 +1077,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_FREQUENCY);
}
if (!has_tuner) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
@@ -1030,6 +1087,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_TUNER);
}
if (in_type_counter[HDMI] == 0) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
@@ -1056,6 +1115,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
@@ -1136,6 +1196,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 1;
+ dev->timeperframe_tch_cap.denominator = 10;
+
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
@@ -1148,6 +1212,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->meta_cap_active);
INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
@@ -1336,6 +1401,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
}
+ if (dev->has_touch_cap) {
+ /* initialize touch_cap queue */
+ q = &dev->vb_touch_cap_q;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ if (!allocator)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = &vivid_touch_cap_qops;
+ q->mem_ops = vivid_mem_ops[allocator];
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto unreg_dev;
+ }
#ifdef CONFIG_VIDEO_VIVID_CEC
if (dev->has_vid_cap && in_type_counter[HDMI]) {
@@ -1379,6 +1465,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
@@ -1665,6 +1752,33 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_touch_cap) {
+ vfd = &dev->touch_cap_dev;
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->touch_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_touch_cap_q;
+ vfd->tvnorms = tvnorms_cap;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->touch_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_TOUCH,
+ touch_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 touch capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */
ret = media_device_register(&dev->mdev);
@@ -1681,6 +1795,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0;
unreg_dev:
+ video_unregister_device(&dev->touch_cap_dev);
video_unregister_device(&dev->meta_out_dev);
video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
@@ -1809,6 +1924,11 @@ static int vivid_remove(struct platform_device *pdev)
video_device_node_name(&dev->meta_out_dev));
video_unregister_device(&dev->meta_out_dev);
}
+ if (dev->has_touch_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->touch_cap_dev));
+ video_unregister_device(&dev->touch_cap_dev);
+ }
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index d57066ed31f0..f065f7557f8f 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -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;
@@ -200,6 +204,7 @@ struct vivid_dev {
bool has_fb;
bool has_meta_cap;
bool has_meta_out;
+ bool has_touch_cap;
bool can_loop_video;
@@ -403,10 +408,13 @@ 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;
unsigned long jiffies_vid_cap;
+ struct v4l2_fract timeperframe_tch_cap;
u64 cap_stream_start;
u64 cap_frame_period;
u64 cap_frame_eof_offset;
@@ -424,6 +432,16 @@ 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;
+
/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index b250fc3764e2..c2a5597a6480 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1495,6 +1495,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,
@@ -1538,6 +1539,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,
@@ -1890,6 +1893,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;
}
@@ -1911,4 +1921,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);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 9f981e8bae6e..84deafac0d26 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -779,7 +779,6 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
meta_cap_buf->vb.vb2_buf.index);
meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
}
-
dev->dqbuf_error = false;
update_mv:
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
new file mode 100644
index 000000000000..15406df628f7
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-kthread-touch.h - touch capture thread support functions.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-rect.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.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;
+
+ dprintk(dev, 1, "Touch Capture Thread Tick\n");
+
+ 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);
+ /* Add touch caputre*/
+
+ 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;
+
+ mutex_lock(&dev->mutex);
+ 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_vid_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, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->kthread_touch_cap) {
+ *pstreaming = 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;
+ }
+ *pstreaming = true;
+ dprintk(dev, 1, "returning from %s\n", __func__);
+ return 0;
+}
+
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (!dev->kthread_touch_cap)
+ return;
+
+ *pstreaming = 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);
+ }
+
+ if (dev->touch_cap_streaming)
+ return;
+
+ mutex_unlock(&dev->mutex);
+ kthread_stop(dev->kthread_touch_cap);
+ dev->kthread_touch_cap = NULL;
+ mutex_lock(&dev->mutex);
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
new file mode 100644
index 000000000000..db9cfa1b473c
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
@@ -0,0 +1,13 @@
+/* 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, bool *pstreaming);
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
new file mode 100644
index 000000000000..d791018f1cb6
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-touch-cap.c - touch support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ 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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ 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,
+ &dev->touch_cap_streaming);
+ }
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ vivid_stop_generating_touch_cap(dev, &dev->touch_cap_streaming);
+}
+
+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_tch_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (inp->index >= dev->num_inputs)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_TOUCH;
+ snprintf(inp->name, sizeof(inp->name), "Touch %u",
+ dev->input_name_counter[inp->index]);
+ inp->capabilities = 0;
+ return 0;
+}
+
+int vivid_tch_cap_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+}
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
new file mode 100644
index 000000000000..782a9b84fcac
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-touch-cap.h - touch support functions.
+ */
+#ifndef _VIVID_TOUCH_CAP_H_
+#define _VIVID_TOUCH_CAP_H_
+
+struct vivid_touch_buf {
+ int tmp;
+} __packed;
+
+extern const struct vb2_ops vivid_touch_cap_qops;
+
+int vivid_tch_cap_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm);
+int vivid_tch_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp);
+#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH v2] vivid: Add touch support
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support bnvandana
2019-10-22 7:51 ` Vandana BN
@ 2019-11-04 12:45 ` Vandana BN
2019-11-04 16:00 ` Hans Verkuil
1 sibling, 1 reply; 9+ messages in thread
From: Vandana BN @ 2019-11-04 12:45 UTC (permalink / raw)
To: linux-media, linux-kernel-mentees
Support to emulate touch devices in vivid driver.
Incorporate changes from https://patchwork.linuxtv.org/patch/59782/,
to avoid the mutex unlocking/relocking around the kthread_stop.
Signed-off-by: Vandana BN <bnvandana@gmail.com>
---
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 180 +++++++++++++-
drivers/media/platform/vivid/vivid-core.h | 19 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../media/platform/vivid/vivid-kthread-cap.c | 1 -
.../platform/vivid/vivid-kthread-touch.c | 212 +++++++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 ++
.../media/platform/vivid/vivid-touch-cap.c | 221 ++++++++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 25 ++
9 files changed, 672 insertions(+), 13 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index e8a50c506dc9..b12ad0152a3e 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -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
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index bd91916980b9..f6f58d7daa71 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -39,6 +39,7 @@
#include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#include "vivid-meta-out.h"
+#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
@@ -89,6 +90,10 @@ static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_out_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
+static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(touch_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
+
static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -110,10 +115,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
* vbi-out + vid-out + meta-cap
*/
static unsigned int node_types[VIVID_MAX_DEVS] = {
- [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
+ [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
};
module_param_array(node_types, uint, NULL, 0444);
-MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
+MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
"\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n"
@@ -123,7 +128,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the
"\t\t bit 12: Radio Transmitter node\n"
"\t\t bit 16: Framebuffer for testing overlays\n"
"\t\t bit 17: Metadata Capture node\n"
- "\t\t bit 18: Metadata Output node\n");
+ "\t\t bit 18: Metadata Output node\n"
+ "\t\t bit 19: Touch Capture node\n");
/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -223,7 +229,8 @@ static int vidioc_querycap(struct file *file, void *priv,
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
dev->sdr_cap_caps | dev->meta_cap_caps |
- dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->meta_out_caps | dev->touch_cap_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -255,6 +262,8 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
return vivid_radio_rx_g_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_tuner(file, fh, vt);
}
@@ -266,6 +275,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
return vivid_radio_rx_s_tuner(file, fh, vt);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_tuner(file, fh, vt);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_tuner(file, fh, vt);
}
@@ -280,6 +291,8 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_g_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_g_frequency(file, fh, vf);
}
@@ -294,6 +307,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
return vivid_sdr_s_frequency(file, fh, vf);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return -EINVAL;
return vivid_video_s_frequency(file, fh, vf);
}
@@ -377,6 +392,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_parm_tch(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_g_parm(file, fh, parm);
return vivid_vid_out_g_parm(file, fh, parm);
@@ -387,6 +404,8 @@ static int vidioc_s_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_parm_tch(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_s_parm(file, fh, parm);
return -ENOTTY;
@@ -432,6 +451,66 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}
+int vivid_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_input_tch(file, priv, inp);
+ else
+ return vidioc_enum_input(file, priv, inp);
+}
+
+int vivid_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_s_input_tch(file, priv, i);
+ else
+ return vidioc_s_input(file, priv, i);
+}
+
+int vivid_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_fmt_tch(file, priv, f);
+ else
+ return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vivid_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ else
+ return vidioc_g_fmt_vid_cap(file, priv, f);
+}
+
+int vivid_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ else
+ return vidioc_try_fmt_vid_cap(file, priv, f);
+}
+
+int vivid_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ else
+ return vidioc_s_fmt_vid_cap(file, priv, f);
+}
+
static bool vivid_is_in_use(struct video_device *vdev)
{
unsigned long flags;
@@ -453,7 +532,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev) +
vivid_is_in_use(&dev->meta_cap_dev) +
- vivid_is_in_use(&dev->meta_out_dev);
+ vivid_is_in_use(&dev->meta_out_dev) +
+ vivid_is_in_use(&dev->touch_cap_dev);
return uses == 1;
}
@@ -481,6 +561,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
}
mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner)
@@ -522,10 +603,10 @@ static const struct v4l2_file_operations vivid_radio_fops = {
static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap,
+ .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
@@ -590,9 +671,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enum_input = vivid_enum_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
@@ -856,6 +937,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a metadata output device */
dev->has_meta_out = node_type & 0x40000;
+ /* do we create a touch capture device */
+ dev->has_touch_cap = node_type & 0x80000;
+
/* end detecting feature set */
if (dev->has_vid_cap) {
@@ -929,6 +1013,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_audio_outputs)
dev->meta_out_caps |= V4L2_CAP_AUDIO;
}
+ /* set up the capabilities of the touch capture device */
+ if (dev->has_touch_cap) {
+ dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ }
ret = -ENOMEM;
/* initialize the test pattern generator */
@@ -992,6 +1081,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUMAUDIO);
}
if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
@@ -1022,6 +1114,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_FREQUENCY);
}
if (!has_tuner) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
@@ -1030,6 +1124,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_TUNER);
}
if (in_type_counter[HDMI] == 0) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
@@ -1056,6 +1152,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
@@ -1136,6 +1233,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 1;
+ dev->timeperframe_tch_cap.denominator = 10;
+ vivid_set_touch(dev, 0);
+
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
@@ -1148,6 +1250,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->meta_cap_active);
INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
@@ -1336,6 +1439,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
}
+ if (dev->has_touch_cap) {
+ /* initialize touch_cap queue */
+ q = &dev->vb_touch_cap_q;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ if (!allocator)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = &vivid_touch_cap_qops;
+ q->mem_ops = vivid_mem_ops[allocator];
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto unreg_dev;
+ }
#ifdef CONFIG_VIDEO_VIVID_CEC
if (dev->has_vid_cap && in_type_counter[HDMI]) {
@@ -1379,6 +1503,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
@@ -1665,6 +1790,33 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_touch_cap) {
+ vfd = &dev->touch_cap_dev;
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->touch_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_touch_cap_q;
+ vfd->tvnorms = tvnorms_cap;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->touch_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_TOUCH,
+ touch_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 touch capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */
ret = media_device_register(&dev->mdev);
@@ -1681,6 +1833,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0;
unreg_dev:
+ video_unregister_device(&dev->touch_cap_dev);
video_unregister_device(&dev->meta_out_dev);
video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
@@ -1809,6 +1962,11 @@ static int vivid_remove(struct platform_device *pdev)
video_device_node_name(&dev->meta_out_dev));
video_unregister_device(&dev->meta_out_dev);
}
+ if (dev->has_touch_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->touch_cap_dev));
+ video_unregister_device(&dev->touch_cap_dev);
+ }
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index d57066ed31f0..0827f6cf7d54 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -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;
@@ -200,6 +204,7 @@ struct vivid_dev {
bool has_fb;
bool has_meta_cap;
bool has_meta_out;
+ bool has_touch_cap;
bool can_loop_video;
@@ -403,6 +408,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;
@@ -424,6 +431,18 @@ 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;
+
/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index b250fc3764e2..c2a5597a6480 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1495,6 +1495,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,
@@ -1538,6 +1539,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,
@@ -1890,6 +1893,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;
}
@@ -1911,4 +1921,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);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 9f981e8bae6e..84deafac0d26 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -779,7 +779,6 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
meta_cap_buf->vb.vb2_buf.index);
meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
}
-
dev->dqbuf_error = false;
update_mv:
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
new file mode 100644
index 000000000000..f39f10749a29
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-kthread-touch.h - touch capture thread support functions.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <linux/v4l2-dv-timings.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-rect.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.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;
+
+ dprintk(dev, 1, "Touch Capture Thread Tick\n");
+
+ 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_vid_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, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->kthread_touch_cap) {
+ *pstreaming = 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;
+ }
+ *pstreaming = true;
+ dprintk(dev, 1, "returning from %s\n", __func__);
+ return 0;
+}
+
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (!dev->kthread_touch_cap)
+ return;
+
+ *pstreaming = 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);
+ }
+
+ if (dev->touch_cap_streaming)
+ return;
+
+ kthread_stop(dev->kthread_touch_cap);
+ dev->kthread_touch_cap = NULL;
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
new file mode 100644
index 000000000000..db9cfa1b473c
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
@@ -0,0 +1,13 @@
+/* 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, bool *pstreaming);
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
new file mode 100644
index 000000000000..480846afc311
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-touch-cap.c - touch support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#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[])
+{
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ 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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ 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,
+ &dev->touch_cap_streaming);
+ }
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ vivid_stop_generating_touch_cap(dev, &dev->touch_cap_streaming);
+}
+
+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)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (f->index)
+ return -EINVAL;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ f->pixelformat = V4L2_TCH_FMT_TU16;
+ return 0;
+}
+
+int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (inp->index >= dev->num_inputs)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_TOUCH;
+ snprintf(inp->name, sizeof(inp->name), "Vivid Touch %u",
+ dev->input_name_counter[inp->index]);
+ inp->capabilities = 0;
+ return 0;
+}
+
+int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
+{
+ struct v4l2_pix_format *f = &dev->tch_format;
+
+ if (i >= dev->num_inputs)
+ return -EINVAL;
+
+ dev->input = i;
+ f->pixelformat = V4L2_TCH_FMT_TU16;
+ 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(u16);
+ f->sizeimage = f->width * f->height * sizeof(u16);
+ return 0;
+}
+
+int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
+{
+ return vivid_set_touch(video_drvdata(file), i);
+}
+
+void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+ int size = VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT;
+ int touch_width = VIVID_TCH_WIDTH / 4;
+ int i = 0, j = 0;
+ struct vivid_touch_buf *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+
+ buf->vb.sequence = dev->touch_cap_seq_count;
+
+ memset(tch_buf, 1, vb2_plane_size(&buf->vb.vb2_buf, 0));
+
+ for (i = 0; i < (size / 4 + touch_width) ; i = i + VIVID_TCH_WIDTH)
+ for (j = i ; j < i + touch_width; j++)
+ tch_buf->buf[j] = buf->vb.sequence;
+}
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
new file mode 100644
index 000000000000..9286afab5425
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.h
@@ -0,0 +1,25 @@
+/* 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 24
+#define VIVID_TCH_WIDTH 14
+
+struct vivid_touch_buf {
+ u16 buf[VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT];
+};
+
+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_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
--
2.17.1
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Linux-kernel-mentees] [PATCH v2] vivid: Add touch support
2019-11-04 12:45 ` [Linux-kernel-mentees] [PATCH v2] " Vandana BN
@ 2019-11-04 16:00 ` Hans Verkuil
2019-11-08 7:08 ` [Linux-kernel-mentees] [PATCH v3] " Vandana BN
0 siblings, 1 reply; 9+ messages in thread
From: Hans Verkuil @ 2019-11-04 16:00 UTC (permalink / raw)
To: Vandana BN, linux-media, linux-kernel-mentees
Hi Vandana,
Here is a quick review:
On 11/4/19 1:45 PM, Vandana BN wrote:
> Support to emulate touch devices in vivid driver.
>
> Incorporate changes from https://patchwork.linuxtv.org/patch/59782/,
> to avoid the mutex unlocking/relocking around the kthread_stop.
You wouldn't put this here...
>
> Signed-off-by: Vandana BN <bnvandana@gmail.com>
> ---
...but you might want to add that here, followed by ---
Anything between the first and second --- line is ignored by git, so that's
a good place to add comments that you don't want to see in the commit log.
> drivers/media/platform/vivid/Makefile | 3 +-
> drivers/media/platform/vivid/vivid-core.c | 180 +++++++++++++-
> drivers/media/platform/vivid/vivid-core.h | 19 ++
> drivers/media/platform/vivid/vivid-ctrls.c | 11 +
> .../media/platform/vivid/vivid-kthread-cap.c | 1 -
> .../platform/vivid/vivid-kthread-touch.c | 212 +++++++++++++++++
> .../platform/vivid/vivid-kthread-touch.h | 13 ++
> .../media/platform/vivid/vivid-touch-cap.c | 221 ++++++++++++++++++
> .../media/platform/vivid/vivid-touch-cap.h | 25 ++
> 9 files changed, 672 insertions(+), 13 deletions(-)
> create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
> create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
> create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
> create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
>
> diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
> index e8a50c506dc9..b12ad0152a3e 100644
> --- a/drivers/media/platform/vivid/Makefile
> +++ b/drivers/media/platform/vivid/Makefile
> @@ -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
> diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
> index bd91916980b9..f6f58d7daa71 100644
> --- a/drivers/media/platform/vivid/vivid-core.c
> +++ b/drivers/media/platform/vivid/vivid-core.c
> @@ -39,6 +39,7 @@
> #include "vivid-ctrls.h"
> #include "vivid-meta-cap.h"
> #include "vivid-meta-out.h"
> +#include "vivid-touch-cap.h"
>
> #define VIVID_MODULE_NAME "vivid"
>
> @@ -89,6 +90,10 @@ static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
> module_param_array(meta_out_nr, int, NULL, 0444);
> MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
>
> +static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
> +module_param_array(touch_cap_nr, int, NULL, 0444);
> +MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
> +
> static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
> module_param_array(ccs_cap_mode, int, NULL, 0444);
> MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
> @@ -110,10 +115,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
> * vbi-out + vid-out + meta-cap
> */
> static unsigned int node_types[VIVID_MAX_DEVS] = {
> - [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
> + [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
> };
> module_param_array(node_types, uint, NULL, 0444);
> -MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
> +MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
> "\t\t bit 0: Video Capture node\n"
> "\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
> "\t\t bit 4: Radio Receiver node\n"
> @@ -123,7 +128,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the
> "\t\t bit 12: Radio Transmitter node\n"
> "\t\t bit 16: Framebuffer for testing overlays\n"
> "\t\t bit 17: Metadata Capture node\n"
> - "\t\t bit 18: Metadata Output node\n");
> + "\t\t bit 18: Metadata Output node\n"
> + "\t\t bit 19: Touch Capture node\n");
>
> /* Default: 4 inputs */
> static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
> @@ -223,7 +229,8 @@ static int vidioc_querycap(struct file *file, void *priv,
> dev->vbi_cap_caps | dev->vbi_out_caps |
> dev->radio_rx_caps | dev->radio_tx_caps |
> dev->sdr_cap_caps | dev->meta_cap_caps |
> - dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
> + dev->meta_out_caps | dev->touch_cap_caps |
> + V4L2_CAP_DEVICE_CAPS;
> return 0;
> }
>
> @@ -255,6 +262,8 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
> return vivid_radio_rx_g_tuner(file, fh, vt);
> if (vdev->vfl_type == VFL_TYPE_SDR)
> return vivid_sdr_g_tuner(file, fh, vt);
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return -EINVAL;
The v4l2 core should disable all these ioctls automatically. So is this really needed?
(See the "v4l2-dev: disable frequency and tuner ioctls for touch" patch)
Looks like a left-over to me.
> return vivid_video_g_tuner(file, fh, vt);
> }
>
> @@ -266,6 +275,8 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
> return vivid_radio_rx_s_tuner(file, fh, vt);
> if (vdev->vfl_type == VFL_TYPE_SDR)
> return vivid_sdr_s_tuner(file, fh, vt);
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return -EINVAL;
> return vivid_video_s_tuner(file, fh, vt);
> }
>
> @@ -280,6 +291,8 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
> &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
> if (vdev->vfl_type == VFL_TYPE_SDR)
> return vivid_sdr_g_frequency(file, fh, vf);
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return -EINVAL;
> return vivid_video_g_frequency(file, fh, vf);
> }
>
> @@ -294,6 +307,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
> &dev->radio_rx_freq : &dev->radio_tx_freq, vf);
> if (vdev->vfl_type == VFL_TYPE_SDR)
> return vivid_sdr_s_frequency(file, fh, vf);
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return -EINVAL;
> return vivid_video_s_frequency(file, fh, vf);
> }
>
> @@ -377,6 +392,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
> {
> struct video_device *vdev = video_devdata(file);
>
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_g_parm_tch(file, fh, parm);
> if (vdev->vfl_dir == VFL_DIR_RX)
> return vivid_vid_cap_g_parm(file, fh, parm);
> return vivid_vid_out_g_parm(file, fh, parm);
> @@ -387,6 +404,8 @@ static int vidioc_s_parm(struct file *file, void *fh,
> {
> struct video_device *vdev = video_devdata(file);
>
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_g_parm_tch(file, fh, parm);
> if (vdev->vfl_dir == VFL_DIR_RX)
> return vivid_vid_cap_s_parm(file, fh, parm);
> return -ENOTTY;
> @@ -432,6 +451,66 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
> return vivid_radio_tx_poll(file, wait);
> }
>
> +int vivid_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_enum_input_tch(file, priv, inp);
> + else
You can drop the 'else' statement here.
> + return vidioc_enum_input(file, priv, inp);
> +}
> +
> +int vivid_s_input(struct file *file, void *priv, unsigned int i)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_s_input_tch(file, priv, i);
> + else
Ditto here and various places below.
> + return vidioc_s_input(file, priv, i);
> +}
> +
> +int vivid_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_enum_fmt_tch(file, priv, f);
> + else
> + return vivid_enum_fmt_vid(file, priv, f);
> +}
> +
> +int vivid_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_g_fmt_tch(file, priv, f);
> + else
> + return vidioc_g_fmt_vid_cap(file, priv, f);
> +}
> +
> +int vivid_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_g_fmt_tch(file, priv, f);
> + else
> + return vidioc_try_fmt_vid_cap(file, priv, f);
> +}
> +
> +int vivid_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
> +{
> + struct video_device *vdev = video_devdata(file);
> +
> + if (vdev->vfl_type == VFL_TYPE_TOUCH)
> + return vivid_g_fmt_tch(file, priv, f);
> + else
> + return vidioc_s_fmt_vid_cap(file, priv, f);
> +}
> +
> static bool vivid_is_in_use(struct video_device *vdev)
> {
> unsigned long flags;
> @@ -453,7 +532,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
> vivid_is_in_use(&dev->radio_rx_dev) +
> vivid_is_in_use(&dev->radio_tx_dev) +
> vivid_is_in_use(&dev->meta_cap_dev) +
> - vivid_is_in_use(&dev->meta_out_dev);
> + vivid_is_in_use(&dev->meta_out_dev) +
> + vivid_is_in_use(&dev->touch_cap_dev);
>
> return uses == 1;
> }
> @@ -481,6 +561,7 @@ static int vivid_fop_release(struct file *file)
> set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
> set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
> set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
> + set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
> }
> mutex_unlock(&dev->mutex);
> if (file->private_data == dev->overlay_cap_owner)
> @@ -522,10 +603,10 @@ static const struct v4l2_file_operations vivid_radio_fops = {
> static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
> .vidioc_querycap = vidioc_querycap,
>
> - .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid,
> - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
> - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
> - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
> + .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap,
> + .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap,
> + .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap,
> + .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap,
> .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
> .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
> .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
> @@ -590,9 +671,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
> .vidioc_streamon = vb2_ioctl_streamon,
> .vidioc_streamoff = vb2_ioctl_streamoff,
>
> - .vidioc_enum_input = vidioc_enum_input,
> + .vidioc_enum_input = vivid_enum_input,
> .vidioc_g_input = vidioc_g_input,
> - .vidioc_s_input = vidioc_s_input,
> + .vidioc_s_input = vivid_s_input,
> .vidioc_s_audio = vidioc_s_audio,
> .vidioc_g_audio = vidioc_g_audio,
> .vidioc_enumaudio = vidioc_enumaudio,
> @@ -856,6 +937,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> /* do we create a metadata output device */
> dev->has_meta_out = node_type & 0x40000;
>
> + /* do we create a touch capture device */
> + dev->has_touch_cap = node_type & 0x80000;
> +
> /* end detecting feature set */
>
> if (dev->has_vid_cap) {
> @@ -929,6 +1013,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> if (dev->has_audio_outputs)
> dev->meta_out_caps |= V4L2_CAP_AUDIO;
> }
> + /* set up the capabilities of the touch capture device */
> + if (dev->has_touch_cap) {
> + dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_VIDEO_CAPTURE |
> + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
> + }
No need for {} since this is a single statement.
>
> ret = -ENOMEM;
> /* initialize the test pattern generator */
> @@ -992,6 +1081,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_AUDIO);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_AUDIO);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUMAUDIO);
> }
> if (!dev->has_audio_outputs) {
> v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
> @@ -1022,6 +1114,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_FREQUENCY);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_FREQUENCY);
> }
> if (!has_tuner) {
> v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
> @@ -1030,6 +1124,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_TUNER);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_TUNER);
It shouldn't be needed to disable this since the v4l2 core should do that already
for touch devices. Left-over code?
> }
> if (in_type_counter[HDMI] == 0) {
> v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
> @@ -1056,6 +1152,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
> v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
> v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
> + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
Same here.
> v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
> v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
> v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
> @@ -1136,6 +1233,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
> dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
>
> + /* update touch configuration */
> + dev->timeperframe_tch_cap.numerator = 1;
> + dev->timeperframe_tch_cap.denominator = 10;
> + vivid_set_touch(dev, 0);
> +
> /* initialize locks */
> spin_lock_init(&dev->slock);
> mutex_init(&dev->mutex);
> @@ -1148,6 +1250,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> INIT_LIST_HEAD(&dev->sdr_cap_active);
> INIT_LIST_HEAD(&dev->meta_cap_active);
> INIT_LIST_HEAD(&dev->meta_out_active);
> + INIT_LIST_HEAD(&dev->touch_cap_active);
>
> INIT_LIST_HEAD(&dev->cec_work_list);
> spin_lock_init(&dev->cec_slock);
> @@ -1336,6 +1439,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> if (ret)
> goto unreg_dev;
> }
> + if (dev->has_touch_cap) {
> + /* initialize touch_cap queue */
> + q = &dev->vb_touch_cap_q;
> + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
> + if (!allocator)
> + q->io_modes |= VB2_USERPTR;
> + q->drv_priv = dev;
> + q->buf_struct_size = sizeof(struct vivid_buffer);
> + q->ops = &vivid_touch_cap_qops;
> + q->mem_ops = vivid_mem_ops[allocator];
> + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> + q->min_buffers_needed = 1;
> + q->lock = &dev->mutex;
> + q->dev = dev->v4l2_dev.dev;
> + q->supports_requests = true;
> +
> + ret = vb2_queue_init(q);
> + if (ret)
> + goto unreg_dev;
> + }
>
> #ifdef CONFIG_VIDEO_VIVID_CEC
> if (dev->has_vid_cap && in_type_counter[HDMI]) {
> @@ -1379,6 +1503,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
> v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
> v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
> + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
>
> /* finally start creating the device nodes */
> if (dev->has_vid_cap) {
> @@ -1665,6 +1790,33 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> video_device_node_name(vfd));
> }
>
> + if (dev->has_touch_cap) {
> + vfd = &dev->touch_cap_dev;
I expect vfd->name to be set here.
> + vfd->fops = &vivid_fops;
> + vfd->ioctl_ops = &vivid_ioctl_ops;
> + vfd->device_caps = dev->touch_cap_caps;
> + vfd->release = video_device_release_empty;
> + vfd->v4l2_dev = &dev->v4l2_dev;
> + vfd->queue = &dev->vb_touch_cap_q;
> + vfd->tvnorms = tvnorms_cap;
> + vfd->lock = &dev->mutex;
> + video_set_drvdata(vfd, dev);
> +#ifdef CONFIG_MEDIA_CONTROLLER
> + dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
> + ret = media_entity_pads_init(&vfd->entity, 1,
> + &dev->touch_cap_pad);
> + if (ret)
> + goto unreg_dev;
> +#endif
> + ret = video_register_device(vfd, VFL_TYPE_TOUCH,
> + touch_cap_nr[inst]);
> + if (ret < 0)
> + goto unreg_dev;
> + v4l2_info(&dev->v4l2_dev,
> + "V4L2 touch capture device registered as %s\n",
> + video_device_node_name(vfd));
> + }
> +
> #ifdef CONFIG_MEDIA_CONTROLLER
> /* Register the media device */
> ret = media_device_register(&dev->mdev);
> @@ -1681,6 +1833,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
> return 0;
>
> unreg_dev:
> + video_unregister_device(&dev->touch_cap_dev);
> video_unregister_device(&dev->meta_out_dev);
> video_unregister_device(&dev->meta_cap_dev);
> video_unregister_device(&dev->radio_tx_dev);
> @@ -1809,6 +1962,11 @@ static int vivid_remove(struct platform_device *pdev)
> video_device_node_name(&dev->meta_out_dev));
> video_unregister_device(&dev->meta_out_dev);
> }
> + if (dev->has_touch_cap) {
> + v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
> + video_device_node_name(&dev->touch_cap_dev));
> + video_unregister_device(&dev->touch_cap_dev);
> + }
> cec_unregister_adapter(dev->cec_rx_adap);
> for (j = 0; j < MAX_OUTPUTS; j++)
> cec_unregister_adapter(dev->cec_tx_adap[j]);
> diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
> index d57066ed31f0..0827f6cf7d54 100644
> --- a/drivers/media/platform/vivid/vivid-core.h
> +++ b/drivers/media/platform/vivid/vivid-core.h
> @@ -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;
> @@ -200,6 +204,7 @@ struct vivid_dev {
> bool has_fb;
> bool has_meta_cap;
> bool has_meta_out;
> + bool has_touch_cap;
>
> bool can_loop_video;
>
> @@ -403,6 +408,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;
> @@ -424,6 +431,18 @@ 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;
> +
> /* video output */
> const struct vivid_fmt *fmt_out;
> struct v4l2_fract timeperframe_vid_out;
> diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
> index b250fc3764e2..c2a5597a6480 100644
> --- a/drivers/media/platform/vivid/vivid-ctrls.c
> +++ b/drivers/media/platform/vivid/vivid-ctrls.c
> @@ -1495,6 +1495,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,
> @@ -1538,6 +1539,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,
> @@ -1890,6 +1893,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;
> }
>
> @@ -1911,4 +1921,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);
> }
> diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
> index 9f981e8bae6e..84deafac0d26 100644
> --- a/drivers/media/platform/vivid/vivid-kthread-cap.c
> +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
> @@ -779,7 +779,6 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
> meta_cap_buf->vb.vb2_buf.index);
> meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
> }
> -
> dev->dqbuf_error = false;
>
> update_mv:
Spurious change.
> diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
> new file mode 100644
> index 000000000000..f39f10749a29
> --- /dev/null
> +++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
> @@ -0,0 +1,212 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * vivid-kthread-touch.h - touch capture thread support functions.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/font.h>
> +#include <linux/mutex.h>
> +#include <linux/videodev2.h>
> +#include <linux/kthread.h>
> +#include <linux/freezer.h>
> +#include <linux/random.h>
> +#include <linux/v4l2-dv-timings.h>
I don't think you need this header.
> +#include <asm/div64.h>
> +#include <media/videobuf2-vmalloc.h>
> +#include <media/v4l2-dv-timings.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-fh.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-rect.h>
> +
> +#include "vivid-core.h"
> +#include "vivid-osd.h"
> +#include "vivid-ctrls.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;
> +
> + dprintk(dev, 1, "Touch Capture Thread Tick\n");
> +
> + 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_vid_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, bool *pstreaming)
You don't need the pstreaming argument. You can just refer to dev->touch_cap_streaming
directly. It is needed for video/vbi/metadata devices since they get their data from
the same 'source', but for touch only one device can be streaming.
> +{
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + if (dev->kthread_touch_cap) {
> + *pstreaming = 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;
> + }
> + *pstreaming = true;
> + dprintk(dev, 1, "returning from %s\n", __func__);
> + return 0;
> +}
> +
> +void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming)
> +{
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + if (!dev->kthread_touch_cap)
> + return;
> +
> + *pstreaming = 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);
> + }
> +
> + if (dev->touch_cap_streaming)
> + return;
This can be dropped since dev->touch_cap_streaming is set to false by the
*pstreaming = false; line above. Just drop the pstreaming argument for touch
devices, it makes the code easier to follow.
> +
> + kthread_stop(dev->kthread_touch_cap);
> + dev->kthread_touch_cap = NULL;
> +}
> diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
> new file mode 100644
> index 000000000000..db9cfa1b473c
> --- /dev/null
> +++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
> @@ -0,0 +1,13 @@
> +/* 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, bool *pstreaming);
> +void vivid_stop_generating_touch_cap(struct vivid_dev *dev, bool *pstreaming);
> +
> +#endif
> diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
> new file mode 100644
> index 000000000000..480846afc311
> --- /dev/null
> +++ b/drivers/media/platform/vivid/vivid-touch-cap.c
> @@ -0,0 +1,221 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * vivid-touch-cap.c - touch support functions.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/videodev2.h>
> +#include <media/v4l2-common.h>
> +#include <linux/usb/video.h>
> +
> +#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[])
> +{
> + unsigned int size = sizeof(struct vivid_touch_buf);
> +
> + 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);
> + unsigned int size = sizeof(struct vivid_touch_buf);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + 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);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + 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;
> +
> + dprintk(dev, 1, "%s\n", __func__);
> + 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,
> + &dev->touch_cap_streaming);
> + }
> + 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);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> + vivid_stop_generating_touch_cap(dev, &dev->touch_cap_streaming);
> +}
> +
> +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)
> +{
> + struct vivid_dev *dev = video_drvdata(file);
> +
> + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> + return -EINVAL;
Is this check needed?
> + if (f->index)
> + return -EINVAL;
> +
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + f->pixelformat = V4L2_TCH_FMT_TU16;
> + return 0;
> +}
> +
> +int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
> +{
> + struct vivid_dev *dev = video_drvdata(file);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->type should be set by the core already.
> + 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);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + 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)
> +{
> + struct vivid_dev *dev = video_drvdata(file);
> +
> + dprintk(dev, 1, "%s\n", __func__);
> +
> + if (inp->index >= dev->num_inputs)
> + return -EINVAL;
> +
> + inp->type = V4L2_INPUT_TYPE_TOUCH;
> + snprintf(inp->name, sizeof(inp->name), "Vivid Touch %u",
> + dev->input_name_counter[inp->index]);
> + inp->capabilities = 0;
> + return 0;
> +}
> +
> +int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
> +{
> + struct v4l2_pix_format *f = &dev->tch_format;
> +
> + if (i >= dev->num_inputs)
> + return -EINVAL;
> +
> + dev->input = i;
> + f->pixelformat = V4L2_TCH_FMT_TU16;
> + 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(u16);
> + f->sizeimage = f->width * f->height * sizeof(u16);
> + return 0;
> +}
> +
> +int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
> +{
> + return vivid_set_touch(video_drvdata(file), i);
> +}
> +
> +void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
> +{
> + int size = VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT;
> + int touch_width = VIVID_TCH_WIDTH / 4;
> + int i = 0, j = 0;
> + struct vivid_touch_buf *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
> +
> + buf->vb.sequence = dev->touch_cap_seq_count;
> +
> + memset(tch_buf, 1, vb2_plane_size(&buf->vb.vb2_buf, 0));
> +
> + for (i = 0; i < (size / 4 + touch_width) ; i = i + VIVID_TCH_WIDTH)
> + for (j = i ; j < i + touch_width; j++)
> + tch_buf->buf[j] = buf->vb.sequence;
I was considering using Test Patterns, but perhaps running through some
sequence of touch interactions might be simpler:
single tap
double tap
triple tap
move single finger from left to right
move two fingers diagonally from center to two opposite corners (i.e. zoom-out)
and back to center (zoom-in)
palm press (i.e. the lower half shows pressure)
16 pressure points (i.e. testing an almost impossible situation).
And then back to the beginning. Each scenario takes perhaps 2 seconds.
> +}
> diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
> new file mode 100644
> index 000000000000..9286afab5425
> --- /dev/null
> +++ b/drivers/media/platform/vivid/vivid-touch-cap.h
> @@ -0,0 +1,25 @@
> +/* 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 24
> +#define VIVID_TCH_WIDTH 14
> +
> +struct vivid_touch_buf {
> + u16 buf[VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT];
> +};
> +
> +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_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
>
Regards,
Hans
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Linux-kernel-mentees] [PATCH v3] vivid: Add touch support
2019-11-04 16:00 ` Hans Verkuil
@ 2019-11-08 7:08 ` Vandana BN
0 siblings, 0 replies; 9+ messages in thread
From: Vandana BN @ 2019-11-08 7:08 UTC (permalink / raw)
To: linux-media, linux-kernel-mentees
Support to emulate touch devices in vivid driver.
Signed-off-by: Vandana BN <bnvandana@gmail.com>
---
Incorporate changes from https://patchwork.linuxtv.org/patch/59782/,
to avoid the mutex unlocking/relocking around the kthread_stop.
---
drivers/media/platform/vivid/Makefile | 3 +-
drivers/media/platform/vivid/vivid-core.c | 162 +++++++++-
drivers/media/platform/vivid/vivid-core.h | 23 ++
drivers/media/platform/vivid/vivid-ctrls.c | 11 +
.../platform/vivid/vivid-kthread-touch.c | 207 +++++++++++++
.../platform/vivid/vivid-kthread-touch.h | 13 +
.../media/platform/vivid/vivid-touch-cap.c | 286 ++++++++++++++++++
.../media/platform/vivid/vivid-touch-cap.h | 38 +++
8 files changed, 731 insertions(+), 12 deletions(-)
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c
create mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c
create mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index e8a50c506dc9..b12ad0152a3e 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -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
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index dadfc59c92c5..cc7807dd0a36 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -39,6 +39,7 @@
#include "vivid-ctrls.h"
#include "vivid-meta-cap.h"
#include "vivid-meta-out.h"
+#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
@@ -89,6 +90,10 @@ static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(meta_out_nr, int, NULL, 0444);
MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
+static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(touch_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
+
static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -110,10 +115,10 @@ MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 cr
* vbi-out + vid-out + meta-cap
*/
static unsigned int node_types[VIVID_MAX_DEVS] = {
- [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d
+ [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
};
module_param_array(node_types, uint, NULL, 0444);
-MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n"
+MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
"\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n"
@@ -123,7 +128,8 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the
"\t\t bit 12: Radio Transmitter node\n"
"\t\t bit 16: Framebuffer for testing overlays\n"
"\t\t bit 17: Metadata Capture node\n"
- "\t\t bit 18: Metadata Output node\n");
+ "\t\t bit 18: Metadata Output node\n"
+ "\t\t bit 19: Touch Capture node\n");
/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -223,7 +229,8 @@ static int vidioc_querycap(struct file *file, void *priv,
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
dev->sdr_cap_caps | dev->meta_cap_caps |
- dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->meta_out_caps | dev->touch_cap_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -377,6 +384,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_parm_tch(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_g_parm(file, fh, parm);
return vivid_vid_out_g_parm(file, fh, parm);
@@ -387,6 +396,8 @@ static int vidioc_s_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_parm_tch(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_s_parm(file, fh, parm);
return -ENOTTY;
@@ -432,6 +443,60 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}
+int vivid_enum_input(struct file *file, void *priv, struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_input_tch(file, priv, inp);
+ return vidioc_enum_input(file, priv, inp);
+}
+
+int vivid_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_s_input_tch(file, priv, i);
+ return vidioc_s_input(file, priv, i);
+}
+
+int vivid_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_fmt_tch(file, priv, f);
+ return vivid_enum_fmt_vid(file, priv, f);
+}
+
+int vivid_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_g_fmt_vid_cap(file, priv, f);
+}
+
+int vivid_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_try_fmt_vid_cap(file, priv, f);
+}
+
+int vivid_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_s_fmt_vid_cap(file, priv, f);
+}
+
static bool vivid_is_in_use(struct video_device *vdev)
{
unsigned long flags;
@@ -453,7 +518,8 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev) +
vivid_is_in_use(&dev->meta_cap_dev) +
- vivid_is_in_use(&dev->meta_out_dev);
+ vivid_is_in_use(&dev->meta_out_dev) +
+ vivid_is_in_use(&dev->touch_cap_dev);
return uses == 1;
}
@@ -481,6 +547,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
}
mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner)
@@ -522,10 +589,10 @@ static const struct v4l2_file_operations vivid_radio_fops = {
static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap,
+ .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
@@ -590,9 +657,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enum_input = vivid_enum_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
@@ -856,6 +923,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a metadata output device */
dev->has_meta_out = node_type & 0x40000;
+ /* do we create a touch capture device */
+ dev->has_touch_cap = node_type & 0x80000;
+
/* end detecting feature set */
if (dev->has_vid_cap) {
@@ -929,6 +999,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_audio_outputs)
dev->meta_out_caps |= V4L2_CAP_AUDIO;
}
+ /* set up the capabilities of the touch capture device */
+ if (dev->has_touch_cap)
+ dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
ret = -ENOMEM;
/* initialize the test pattern generator */
@@ -992,6 +1066,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUMAUDIO);
}
if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
@@ -1136,6 +1213,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 20;
+ dev->timeperframe_tch_cap.denominator = 10;
+ vivid_set_touch(dev, 0);
+
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
@@ -1148,6 +1230,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->meta_cap_active);
INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
@@ -1336,6 +1419,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
}
+ if (dev->has_touch_cap) {
+ /* initialize touch_cap queue */
+ q = &dev->vb_touch_cap_q;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ if (!allocator)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = &vivid_touch_cap_qops;
+ q->mem_ops = vivid_mem_ops[allocator];
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto unreg_dev;
+ }
#ifdef CONFIG_VIDEO_VIVID_CEC
if (dev->has_vid_cap && in_type_counter[HDMI]) {
@@ -1379,6 +1483,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
@@ -1665,6 +1770,35 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_touch_cap) {
+ vfd = &dev->touch_cap_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-touch-cap", inst);
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->touch_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_touch_cap_q;
+ vfd->tvnorms = tvnorms_cap;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->touch_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_TOUCH,
+ touch_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 touch capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */
ret = media_device_register(&dev->mdev);
@@ -1681,6 +1815,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0;
unreg_dev:
+ video_unregister_device(&dev->touch_cap_dev);
video_unregister_device(&dev->meta_out_dev);
video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
@@ -1809,6 +1944,11 @@ static int vivid_remove(struct platform_device *pdev)
video_device_node_name(&dev->meta_out_dev));
video_unregister_device(&dev->meta_out_dev);
}
+ if (dev->has_touch_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->touch_cap_dev));
+ video_unregister_device(&dev->touch_cap_dev);
+ }
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index d57066ed31f0..077f2b3eeed9 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -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;
@@ -200,6 +204,7 @@ struct vivid_dev {
bool has_fb;
bool has_meta_cap;
bool has_meta_out;
+ bool has_touch_cap;
bool can_loop_video;
@@ -403,6 +408,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;
@@ -424,6 +431,22 @@ 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_test_pattern;
+ int tch_index;
+ int tch_val;
+ int tch_cnt;
+
/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index b250fc3764e2..c2a5597a6480 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1495,6 +1495,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,
@@ -1538,6 +1539,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,
@@ -1890,6 +1893,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;
}
@@ -1911,4 +1921,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);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
new file mode 100644
index 000000000000..7ef7230c9a27
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-kthread-touch.c - touch capture thread support functions.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/random.h>
+#include <asm/div64.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-rect.h>
+
+#include "vivid-core.h"
+#include "vivid-osd.h"
+#include "vivid-ctrls.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;
+
+ dprintk(dev, 1, "Touch Capture Thread Tick\n");
+
+ 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)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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)
+{
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
new file mode 100644
index 000000000000..ecf79b46209e
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
@@ -0,0 +1,13 @@
+/* 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
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
new file mode 100644
index 000000000000..56af43a09a7f
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-touch-cap.c - touch support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#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[])
+{
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ 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);
+ unsigned int size = sizeof(struct vivid_touch_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ dev->touch_cap_seq_count = 0;
+ dev->tch_test_pattern = 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ 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)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (f->index)
+ return -EINVAL;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ f->pixelformat = V4L2_TCH_FMT_TU16;
+ return 0;
+}
+
+int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ 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);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ 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)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (inp->index >= dev->num_inputs)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_TOUCH;
+ snprintf(inp->name, sizeof(inp->name), "Vivid Touch %u",
+ dev->input_name_counter[inp->index]);
+ inp->capabilities = 0;
+ return 0;
+}
+
+int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
+{
+ struct v4l2_pix_format *f = &dev->tch_format;
+
+ if (i >= dev->num_inputs)
+ return -EINVAL;
+
+ dev->input = i;
+ f->pixelformat = V4L2_TCH_FMT_TU16;
+ 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(u16);
+ f->sizeimage = f->width * f->height * sizeof(u16);
+ return 0;
+}
+
+int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
+{
+ return vivid_set_touch(video_drvdata(file), i);
+}
+
+void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+ int size = VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT;
+ int index = 0, x, y, xstart, ystart;
+ struct vivid_touch_buf *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+
+ buf->vb.sequence = dev->touch_cap_seq_count;
+
+ memset(tch_buf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0));
+
+ tch_buf->test_pattern = dev->tch_test_pattern;
+
+ switch (dev->tch_test_pattern) {
+ case SINGLE_TAP:
+ case DOUBLE_TAP:
+ case TRIPLE_TAP:
+ if (!dev->tch_cnt) {
+ dev->tch_index = get_random_int() % size;
+ dev->tch_val = buf->vb.sequence + dev->tch_index;
+ }
+ tch_buf->buf[dev->tch_index] = dev->tch_val;
+ dev->tch_cnt++;
+ if (dev->tch_cnt > dev->tch_test_pattern) {
+ dev->tch_test_pattern++;
+ dev->tch_cnt = 0;
+ }
+ break;
+ case SWAP_LEFT_RIGHT:
+ x = get_random_int() % VIVID_TCH_WIDTH;
+ for (index = x; index < VIVID_TCH_WIDTH ; index++)
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ dev->tch_test_pattern++;
+ dev->tch_index = 0;
+ break;
+ case ZOOM_IN:
+ case ZOOM_OUT:
+ x = VIVID_TCH_WIDTH / 2;
+ y = VIVID_TCH_HEIGHT / 2;
+ if (!dev->tch_index) {
+ index = x + VIVID_TCH_WIDTH * y;
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ if (dev->tch_test_pattern == ZOOM_OUT)
+ dev->tch_test_pattern++;
+ } else {
+ index = (x - dev->tch_index) + VIVID_TCH_WIDTH * (y - dev->tch_index);
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ index = (x + dev->tch_index) + VIVID_TCH_WIDTH * (y + dev->tch_index);
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ }
+ if (dev->tch_test_pattern == ZOOM_IN) {
+ dev->tch_index++;
+ if (x + dev->tch_index >= VIVID_TCH_WIDTH ||
+ y + dev->tch_index >= VIVID_TCH_HEIGHT)
+ dev->tch_test_pattern++;
+ }
+ if (dev->tch_test_pattern == ZOOM_OUT)
+ dev->tch_index--;
+ break;
+ case PALM_PRESS:
+ xstart = VIVID_TCH_WIDTH - VIVID_TCH_WIDTH / 4;
+ ystart = VIVID_TCH_HEIGHT - VIVID_TCH_HEIGHT / 4;
+ for (x = xstart; x < VIVID_TCH_WIDTH; x++) {
+ for (y = ystart; y < VIVID_TCH_HEIGHT; y++) {
+ index = x + VIVID_TCH_WIDTH * y;
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ }
+ }
+ dev->tch_test_pattern++;
+ break;
+ case MULTIPLE_PRESS:
+ /*16 pressure points*/
+ for (x = 0; x < 16; x++) {
+ index = get_random_int() % size;
+ tch_buf->buf[index] = buf->vb.sequence + index;
+ }
+ dev->tch_test_pattern++;
+ break;
+ }
+
+ if (dev->tch_test_pattern == TEST_CASE_MAX)
+ dev->tch_test_pattern = SINGLE_TAP;
+}
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
new file mode 100644
index 000000000000..6a159c91af87
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.h
@@ -0,0 +1,38 @@
+/* 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 24
+#define VIVID_TCH_WIDTH 14
+
+enum vivid_tch_test {
+ SINGLE_TAP,
+ DOUBLE_TAP,
+ TRIPLE_TAP,
+ SWAP_LEFT_RIGHT,
+ ZOOM_IN,
+ ZOOM_OUT,
+ PALM_PRESS,
+ MULTIPLE_PRESS,
+ TEST_CASE_MAX
+};
+
+struct vivid_touch_buf {
+ u16 buf[VIVID_TCH_WIDTH * VIVID_TCH_HEIGHT];
+ int test_pattern;
+};
+
+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_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
--
2.17.1
_______________________________________________
Linux-kernel-mentees mailing list
Linux-kernel-mentees@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/linux-kernel-mentees
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2019-11-08 7:09 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-22 7:51 [Linux-kernel-mentees] [PATCH 0/2] vivid: Support for touch device bnvandana
2019-10-22 7:51 ` Vandana BN
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 1/2] v4l2-core: fix touch support in v4l_g_fmt bnvandana
2019-10-22 7:51 ` Vandana BN
2019-10-22 7:51 ` [Linux-kernel-mentees] [PATCH 2/2] vivid: Add touch support bnvandana
2019-10-22 7:51 ` Vandana BN
2019-11-04 12:45 ` [Linux-kernel-mentees] [PATCH v2] " Vandana BN
2019-11-04 16:00 ` Hans Verkuil
2019-11-08 7:08 ` [Linux-kernel-mentees] [PATCH v3] " Vandana BN
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).