From 96f49c1ac370c23ae55c63c67a0b40d83928bfbd Mon Sep 17 00:00:00 2001 From: Vandana BN Date: Mon, 14 Oct 2019 05:40:19 -0300 Subject: media: v4l2-core: correctly validate video and metadata ioctls If the type is VFL_TYPE_GRABBER, then also check device_caps to see if the video device supports video and/or metadata and disable unneeded ioctls. Without this change, format ioctls for both video and metadata devices could be called on both device nodes. This is true for other ioctls as well, even if the device supports only video or metadata. Metadata devices act similar to VBI devices w.r.t. which ioctls should be enabled. This makes sense since VBI *is* metadata. Signed-off-by: Vandana BN Co-developed-by: Hans Verkuil Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 62 ++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 23 deletions(-) (limited to 'drivers/media/v4l2-core/v4l2-dev.c') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 4037689a945a..1bf543932e4f 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -533,13 +533,23 @@ static int get_index(struct video_device *vdev) */ static void determine_valid_ioctls(struct video_device *vdev) { + const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE; + const u32 meta_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; - bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER; + bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER && + (vdev->device_caps & vid_caps); 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_meta = vdev->vfl_type == VFL_TYPE_GRABBER && + (vdev->device_caps & meta_caps); bool is_rx = vdev->vfl_dir != VFL_DIR_TX; bool is_tx = vdev->vfl_dir != VFL_DIR_RX; @@ -587,39 +597,31 @@ static void determine_valid_ioctls(struct video_device *vdev) set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); if (is_vid || is_tch) { - /* video and metadata specific ioctls */ + /* video and touch specific ioctls */ if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || - ops->vidioc_enum_fmt_vid_overlay || - ops->vidioc_enum_fmt_meta_cap)) || - (is_tx && (ops->vidioc_enum_fmt_vid_out || - ops->vidioc_enum_fmt_meta_out))) + ops->vidioc_enum_fmt_vid_overlay)) || + (is_tx && ops->vidioc_enum_fmt_vid_out)) set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane || - ops->vidioc_g_fmt_vid_overlay || - ops->vidioc_g_fmt_meta_cap)) || + ops->vidioc_g_fmt_vid_overlay)) || (is_tx && (ops->vidioc_g_fmt_vid_out || ops->vidioc_g_fmt_vid_out_mplane || - ops->vidioc_g_fmt_vid_out_overlay || - ops->vidioc_g_fmt_meta_out))) + ops->vidioc_g_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_s_fmt_vid_cap || ops->vidioc_s_fmt_vid_cap_mplane || - ops->vidioc_s_fmt_vid_overlay || - ops->vidioc_s_fmt_meta_cap)) || + ops->vidioc_s_fmt_vid_overlay)) || (is_tx && (ops->vidioc_s_fmt_vid_out || ops->vidioc_s_fmt_vid_out_mplane || - ops->vidioc_s_fmt_vid_out_overlay || - ops->vidioc_s_fmt_meta_out))) + ops->vidioc_s_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_try_fmt_vid_cap || ops->vidioc_try_fmt_vid_cap_mplane || - ops->vidioc_try_fmt_vid_overlay || - ops->vidioc_try_fmt_meta_cap)) || + ops->vidioc_try_fmt_vid_overlay)) || (is_tx && (ops->vidioc_try_fmt_vid_out || ops->vidioc_try_fmt_vid_out_mplane || - ops->vidioc_try_fmt_vid_out_overlay || - ops->vidioc_try_fmt_meta_out))) + ops->vidioc_try_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay); SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf); @@ -641,7 +643,21 @@ static void determine_valid_ioctls(struct video_device *vdev) set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); - } else if (is_vbi) { + } + if (is_meta && is_rx) { + /* metadata capture specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_cap); + } else if (is_meta && is_tx) { + /* metadata output specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_out); + } + if (is_vbi) { /* vbi specific ioctls */ if ((is_rx && (ops->vidioc_g_fmt_vbi_cap || ops->vidioc_g_fmt_sliced_vbi_cap)) || @@ -681,8 +697,8 @@ 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 || is_tch) { - /* ioctls valid for video, metadata, vbi or sdr */ + if (is_vid || is_vbi || is_sdr || is_tch || is_meta) { + /* ioctls valid for video, vbi, sdr, touch and metadata */ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); @@ -694,8 +710,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); } - if (is_vid || is_vbi || is_tch) { - /* ioctls valid for video or vbi */ + if (is_vid || is_vbi || is_tch || is_meta) { + /* ioctls valid for video, vbi, touch and metadata */ if (ops->vidioc_s_std) set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std); -- cgit v1.2.3 From 8e72244b4e8f1a163d358c271f39c737b5b8106a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Oct 2019 05:40:20 -0300 Subject: media: v4l2-dev: simplify the SDR checks In determine_valid_ioctls() we can use SET_VALID_IOCTL to enable ioctls for SDR, simplifying the code. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/media/v4l2-core/v4l2-dev.c') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1bf543932e4f..27fb96a6c2a8 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -677,24 +677,16 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap); } else if (is_sdr && is_rx) { /* SDR receiver specific ioctls */ - if (ops->vidioc_enum_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); - if (ops->vidioc_g_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); - if (ops->vidioc_s_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); - if (ops->vidioc_try_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_cap); } else if (is_sdr && is_tx) { /* SDR transmitter specific ioctls */ - if (ops->vidioc_enum_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); - if (ops->vidioc_g_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); - if (ops->vidioc_s_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); - if (ops->vidioc_try_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_out); } if (is_vid || is_vbi || is_sdr || is_tch || is_meta) { -- cgit v1.2.3 From 4fbd54bbd24360c28ceec2ae9ee2c950b743aee1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Oct 2019 05:40:21 -0300 Subject: media: v4l2-dev: fix is_tch checks Touch devices mark too many ioctls as valid. Restrict the list of valid ioctls for touch devices. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/media/v4l2-core/v4l2-dev.c') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 27fb96a6c2a8..cec588b04711 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -596,8 +596,8 @@ 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 || is_tch) { - /* video and touch specific ioctls */ + if (is_vid) { + /* video specific ioctls */ if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || ops->vidioc_enum_fmt_vid_overlay)) || (is_tx && ops->vidioc_enum_fmt_vid_out)) @@ -675,6 +675,19 @@ static void determine_valid_ioctls(struct video_device *vdev) ops->vidioc_try_fmt_sliced_vbi_out))) set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap); + } else if (is_tch) { + /* touch specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); + SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input); + SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input); + SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input); + SET_VALID_IOCTL(ops, VIDIOC_G_PARM, vidioc_g_parm); + SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); } else if (is_sdr && is_rx) { /* SDR receiver specific ioctls */ SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_cap); @@ -702,8 +715,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); } - if (is_vid || is_vbi || is_tch || is_meta) { - /* ioctls valid for video, vbi, touch and metadata */ + if (is_vid || is_vbi || is_meta) { + /* ioctls valid for video, vbi and metadata */ if (ops->vidioc_s_std) set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std); @@ -727,8 +740,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout); SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout); } - if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER && - ops->vidioc_g_std)) + if (ops->vidioc_g_parm || ops->vidioc_g_std) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings); -- cgit v1.2.3 From 8669d8474a58268295414b9f78a41659698bdb87 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Oct 2019 09:01:05 -0300 Subject: media: v4l2-dev: disable frequency and tuner ioctls for touch Touch devices have obviously no tuner, so don't attempt to enable those ioctls for such devices. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media/v4l2-core/v4l2-dev.c') diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index cec588b04711..da42d172714a 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -581,8 +581,10 @@ static void determine_valid_ioctls(struct video_device *vdev) set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls); if (vdev->ctrl_handler || ops->vidioc_querymenu) set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls); - SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); - SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); + if (!is_tch) { + SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); + SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); + } SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); #ifdef CONFIG_VIDEO_ADV_DEBUG set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls); @@ -754,7 +756,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator); SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator); } - if (is_rx) { + if (is_rx && !is_tch) { /* receiver only ioctls */ SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner); SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner); -- cgit v1.2.3