Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2fe22d0 authored by Nick Dyer's avatar Nick Dyer Committed by Mauro Carvalho Chehab
Browse files

[media] v4l2-core: Add support for touch devices



Some touch controllers send out touch data in a similar way to a
greyscale frame grabber.

Add new device type VFL_TYPE_TOUCH:
- This uses a new device prefix v4l-touch for these devices, to stop
  generic capture software from treating them as webcams. Otherwise,
  touch is treated similarly to video capture.
- Add V4L2_INPUT_TYPE_TOUCH
- Add MEDIA_INTF_T_V4L_TOUCH
- Add V4L2_CAP_TOUCH to indicate device is a touch device

Add formats:
- V4L2_TCH_FMT_DELTA_TD16 for signed 16-bit touch deltas
- V4L2_TCH_FMT_DELTA_TD08 for signed 16-bit touch deltas
- V4L2_TCH_FMT_TU16 for unsigned 16-bit touch data
- V4L2_TCH_FMT_TU08 for unsigned 8-bit touch data

This support will be used by:
- Atmel maXTouch (atmel_mxt_ts)
- Synaptics RMI4.
- sur40

Signed-off-by: default avatarNick Dyer <nick@shmanahar.org>
Tested-by: default avatarChris Healy <cphealy@gmail.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
Acked-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent aaf578e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ types exist:
- ``VFL_TYPE_VBI``: ``/dev/vbiX`` for vertical blank data (i.e. closed captions, teletext)
- ``VFL_TYPE_RADIO``: ``/dev/radioX`` for radio tuners
- ``VFL_TYPE_SDR``: ``/dev/swradioX`` for Software Defined Radio tuners
- ``VFL_TYPE_TOUCH``: ``/dev/v4l-touchX`` for touch sensors

The last argument gives you a certain amount of control over the device
device node number used (i.e. the X in ``videoX``). Normally you will pass -1
+2 −0
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ static inline const char *intf_type(struct media_interface *intf)
		return "v4l-subdev";
	case MEDIA_INTF_T_V4L_SWRADIO:
		return "v4l-swradio";
	case MEDIA_INTF_T_V4L_TOUCH:
		return "v4l-touch";
	case MEDIA_INTF_T_ALSA_PCM_CAPTURE:
		return "alsa-pcm-capture";
	case MEDIA_INTF_T_ALSA_PCM_PLAYBACK:
+11 −3
Original line number Diff line number Diff line
@@ -527,6 +527,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
	bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI;
	bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO;
	bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
	bool is_tx = vdev->vfl_dir != VFL_DIR_RX;

@@ -573,7 +574,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
	if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
		set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);

	if (is_vid) {
	if (is_vid || is_tch) {
		/* video specific ioctls */
		if ((is_rx && (ops->vidioc_enum_fmt_vid_cap ||
			       ops->vidioc_enum_fmt_vid_cap_mplane ||
@@ -662,7 +663,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
			set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
	}

	if (is_vid || is_vbi || is_sdr) {
	if (is_vid || is_vbi || is_sdr || is_tch) {
		/* ioctls valid for video, vbi or sdr */
		SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
		SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
@@ -675,7 +676,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
		SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
	}

	if (is_vid || is_vbi) {
	if (is_vid || is_vbi || is_tch) {
		/* ioctls valid for video or vbi */
		if (ops->vidioc_s_std)
			set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
@@ -751,6 +752,10 @@ static int video_register_media_controller(struct video_device *vdev, int type)
		intf_type = MEDIA_INTF_T_V4L_SWRADIO;
		vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO;
		break;
	case VFL_TYPE_TOUCH:
		intf_type = MEDIA_INTF_T_V4L_TOUCH;
		vdev->entity.function = MEDIA_ENT_F_IO_V4L;
		break;
	case VFL_TYPE_RADIO:
		intf_type = MEDIA_INTF_T_V4L_RADIO;
		/*
@@ -854,6 +859,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
		/* Use device name 'swradio' because 'sdr' was already taken. */
		name_base = "swradio";
		break;
	case VFL_TYPE_TOUCH:
		name_base = "v4l-touch";
		break;
	default:
		printk(KERN_ERR "%s called with unknown type: %d\n",
		       __func__, type);
+31 −5
Original line number Diff line number Diff line
@@ -924,6 +924,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
	bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI;
	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;

@@ -932,7 +933,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)

	switch (type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (is_vid && is_rx &&
		if ((is_vid || is_tch) && is_rx &&
		    (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane))
			return 0;
		break;
@@ -1243,6 +1244,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
	case V4L2_SDR_FMT_CS8:		descr = "Complex S8"; break;
	case V4L2_SDR_FMT_CS14LE:	descr = "Complex S14LE"; break;
	case V4L2_SDR_FMT_RU12LE:	descr = "Real U12LE"; break;
	case V4L2_TCH_FMT_DELTA_TD16:	descr = "16-bit signed deltas"; break;
	case V4L2_TCH_FMT_DELTA_TD08:	descr = "8-bit signed deltas"; break;
	case V4L2_TCH_FMT_TU16:		descr = "16-bit unsigned touch data"; break;
	case V4L2_TCH_FMT_TU08:		descr = "8-bit unsigned touch data"; break;

	default:
		/* Compressed formats */
@@ -1309,13 +1314,14 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
	struct video_device *vfd = video_devdata(file);
	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
	int ret = -EINVAL;

	switch (p->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_vid_cap))
		if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_enum_fmt_vid_cap))
			break;
		ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg);
		break;
@@ -1362,6 +1368,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
	struct video_device *vfd = video_devdata(file);
	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
	int ret;
@@ -1392,7 +1399,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,

	switch (p->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_vid_cap))
		if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_g_fmt_vid_cap))
			break;
		p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
		ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg);
@@ -1451,6 +1458,21 @@ 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)
{
@@ -1458,6 +1480,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
	struct video_device *vfd = video_devdata(file);
	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
	int ret;
@@ -1469,12 +1492,14 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,

	switch (p->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap))
		if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_s_fmt_vid_cap))
			break;
		CLEAR_AFTER_FIELD(p, fmt.pix);
		ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg);
		/* just in case the driver zeroed it again */
		p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
		if (is_tch)
			v4l_pix_format_touch(&p->fmt.pix);
		return ret;
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
		if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_vid_cap_mplane))
@@ -1545,6 +1570,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
	struct video_device *vfd = video_devdata(file);
	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;
	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
	bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
	bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
	int ret;
@@ -1553,7 +1579,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,

	switch (p->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_vid_cap))
		if (unlikely(!is_rx || (!is_vid && !is_tch) || !ops->vidioc_try_fmt_vid_cap))
			break;
		CLEAR_AFTER_FIELD(p, fmt.pix);
		ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg);
+3 −1
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@
#define VFL_TYPE_RADIO		2
#define VFL_TYPE_SUBDEV		3
#define VFL_TYPE_SDR		4
#define VFL_TYPE_MAX		5
#define VFL_TYPE_TOUCH		5
#define VFL_TYPE_MAX		6

/* Is this a receiver, transmitter or mem-to-mem? */
/* Ignored for VFL_TYPE_SUBDEV. */
@@ -294,6 +295,7 @@ struct video_device
 *	- %VFL_TYPE_RADIO - A radio card
 *	- %VFL_TYPE_SUBDEV - A subdevice
 *	- %VFL_TYPE_SDR - Software Defined Radio
 *	- %VFL_TYPE_TOUCH - A touch sensor
 *
 * .. note::
 *
Loading