Skip to content

Commit

Permalink
media: vivid: Add touch support
Browse files Browse the repository at this point in the history
Support to emulate touch devices in vivid driver.
It generates touch patterns simulating single tap, double tap, triple
tap, move from left to right, zoom in, zoom out, palm press simulating
large area being pressed on screen, and simulating 16 different
simultaneous touch points.The values generated are based on
behavior of the rmi_f54 driver.

Signed-off-by: Vandana BN <[email protected]>
Signed-off-by: Hans Verkuil <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
  • Loading branch information
vandanabn authored and mchehab committed Dec 13, 2019
1 parent 8c956f3 commit 3d15c76
Show file tree
Hide file tree
Showing 8 changed files with 739 additions and 13 deletions.
3 changes: 2 additions & 1 deletion drivers/media/platform/vivid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
164 changes: 152 additions & 12 deletions drivers/media/platform/vivid/vivid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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 };
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -432,6 +441,74 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}

static 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);
}

static int vivid_g_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_g_input_tch(file, priv, i);
return vidioc_g_input(file, priv, i);
}

static 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);
}

static 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);
}

static 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);
}

static 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);
}

static 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;
Expand All @@ -453,7 +530,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;
}
Expand Down Expand Up @@ -481,6 +559,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)
Expand Down Expand Up @@ -522,10 +601,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,
Expand Down Expand Up @@ -590,9 +669,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_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_enum_input = vivid_enum_input,
.vidioc_g_input = vivid_g_input,
.vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
Expand Down Expand Up @@ -921,6 +1000,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_scaler_out ? 'Y' : 'N');
}

/* do we create a touch capture device */
dev->has_touch_cap = node_type & 0x80000;

/* end detecting feature set */

if (dev->has_vid_cap) {
Expand Down Expand Up @@ -994,6 +1076,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 */
Expand Down Expand Up @@ -1129,6 +1215,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM);
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES);
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS);

/* configure internal data */
dev->fmt_cap = &vivid_formats[0];
Expand Down Expand Up @@ -1201,6 +1290,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);
Expand All @@ -1213,6 +1307,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);
Expand Down Expand Up @@ -1294,6 +1389,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
goto unreg_dev;
}

if (dev->has_touch_cap) {
/* initialize touch_cap queue */
ret = vivid_create_queue(dev, &dev->vb_touch_cap_q,
V4L2_BUF_TYPE_VIDEO_CAPTURE, 1,
&vivid_touch_cap_qops);
if (ret)
goto unreg_dev;
}

if (dev->has_fb) {
/* Create framebuffer for testing capture/output overlay */
ret = vivid_fb_init(dev);
Expand Down Expand Up @@ -1345,6 +1449,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) {
Expand Down Expand Up @@ -1635,6 +1740,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);
Expand All @@ -1651,6 +1785,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);
Expand Down Expand Up @@ -1778,6 +1913,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]);
Expand Down
20 changes: 20 additions & 0 deletions drivers/media/platform/vivid/vivid-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -201,6 +205,7 @@ struct vivid_dev {
bool has_meta_cap;
bool has_meta_out;
bool has_tv_tuner;
bool has_touch_cap;

bool can_loop_video;

Expand Down Expand Up @@ -404,6 +409,8 @@ struct vivid_dev {
struct list_head vbi_cap_active;
struct vb2_queue vb_meta_cap_q;
struct list_head meta_cap_active;
struct vb2_queue vb_touch_cap_q;
struct list_head touch_cap_active;

/* thread for generating video capture stream */
struct task_struct *kthread_vid_cap;
Expand All @@ -425,6 +432,19 @@ struct vivid_dev {
u32 meta_cap_seq_count;
bool meta_cap_streaming;

/* Touch capture */
struct task_struct *kthread_touch_cap;
unsigned long jiffies_touch_cap;
u64 touch_cap_stream_start;
u32 touch_cap_seq_offset;
bool touch_cap_seq_resync;
u32 touch_cap_seq_start;
u32 touch_cap_seq_count;
bool touch_cap_streaming;
struct v4l2_fract timeperframe_tch_cap;
struct v4l2_pix_format tch_format;
int tch_pat_random;

/* video output */
const struct vivid_fmt *fmt_out;
struct v4l2_fract timeperframe_vid_out;
Expand Down
Loading

0 comments on commit 3d15c76

Please sign in to comment.