Add V4L2_CAP_IO_MC to be used in struct v4l2_capability to indicate that input and output are controlled by the Media Controller instead of V4L2 API. When this flag is set, ioctls for get, set and enum input and outputs are automatically enabled and programmed to call helper function. Signed-off-by: Helen Koike <helen.koike@xxxxxxxxxxxxx> --- Changes in v2:: - replace the type by capability - erase V4L2_INPUT_TYPE_DEFAULT - also consider output - plug helpers in the ops automatically so drivers doesn't need to set it by hand - update docs - commit message and title --- Documentation/media/uapi/v4l/vidioc-querycap.rst | 3 + Documentation/media/videodev2.h.rst.exceptions | 1 + drivers/media/v4l2-core/v4l2-dev.c | 35 +++++++-- drivers/media/v4l2-core/v4l2-ioctl.c | 91 ++++++++++++++++++++++-- include/uapi/linux/videodev2.h | 2 + 5 files changed, 120 insertions(+), 12 deletions(-) diff --git a/Documentation/media/uapi/v4l/vidioc-querycap.rst b/Documentation/media/uapi/v4l/vidioc-querycap.rst index 12e0d9a..2bd1223 100644 --- a/Documentation/media/uapi/v4l/vidioc-querycap.rst +++ b/Documentation/media/uapi/v4l/vidioc-querycap.rst @@ -252,6 +252,9 @@ specification the ioctl returns an ``EINVAL`` error code. * - ``V4L2_CAP_TOUCH`` - 0x10000000 - This is a touch device. + * - ``V4L2_CAP_IO_MC`` + - 0x20000000 + - This device has its inputs and outputs controller by the Media Controller * - ``V4L2_CAP_DEVICE_CAPS`` - 0x80000000 - The driver fills the ``device_caps`` field. This capability can diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions index a5cb0a8..0b48cd0 100644 --- a/Documentation/media/videodev2.h.rst.exceptions +++ b/Documentation/media/videodev2.h.rst.exceptions @@ -159,6 +159,7 @@ replace define V4L2_CAP_ASYNCIO device-capabilities replace define V4L2_CAP_STREAMING device-capabilities replace define V4L2_CAP_DEVICE_CAPS device-capabilities replace define V4L2_CAP_TOUCH device-capabilities +replace define V4L2_CAP_IO_MC device-capabilities # V4L2 pix flags replace define V4L2_PIX_FMT_PRIV_MAGIC :c:type:`v4l2_pix_format` diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index c647ba6..0f272fe 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -688,22 +688,34 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_STD, vidioc_g_std); if (is_rx) { SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd); - 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_ENUMAUDIO, vidioc_enumaudio); SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid); + if (vdev->device_caps & V4L2_CAP_IO_MC) { + set_bit(_IOC_NR(VIDIOC_ENUMINPUT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_G_INPUT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_S_INPUT), valid_ioctls); + } else { + 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); + } } if (is_tx) { - SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); - SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output); - SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output); SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout); SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout); SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout); + if (vdev->device_caps & V4L2_CAP_IO_MC) { + set_bit(_IOC_NR(VIDIOC_ENUMOUTPUT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_G_OUTPUT), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_S_OUTPUT), valid_ioctls); + } else { + SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); + SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output); + SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output); + } } if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER && ops->vidioc_g_std)) @@ -945,6 +957,17 @@ int __video_register_device(struct video_device *vdev, int type, int nr, video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->ioctl_ops + && !vdev->ioctl_ops->vidioc_enum_input + && !vdev->ioctl_ops->vidioc_s_input + && !vdev->ioctl_ops->vidioc_g_input + && !vdev->ioctl_ops->vidioc_enum_output + && !vdev->ioctl_ops->vidioc_s_output + && !vdev->ioctl_ops->vidioc_g_output) + vdev->device_caps |= V4L2_CAP_IO_MC; +#endif + if (vdev->ioctl_ops) determine_valid_ioctls(vdev); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index e5a2187..9d8c645 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1019,6 +1019,70 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, return ret; } +static int v4l2_ioctl_enum_input_mc(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct video_device *vfd = video_devdata(file); + + if (i->index > 0) + return -EINVAL; + + memset(i, 0, sizeof(*i)); + strlcpy(i->name, vfd->name, sizeof(i->name)); + + return 0; +} + +static int v4l2_ioctl_enum_output_mc(struct file *file, void *priv, + struct v4l2_output *o) +{ + struct video_device *vfd = video_devdata(file); + + if (o->index > 0) + return -EINVAL; + + memset(o, 0, sizeof(*o)); + strlcpy(o->name, vfd->name, sizeof(o->name)); + + return 0; +} + +static int v4l2_ioctl_g_input_mc(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} +#define v4l2_ioctl_g_output_mc v4l2_ioctl_g_input_mc + +static int v4l2_ioctl_s_input_mc(struct file *file, void *priv, unsigned int i) +{ + return i ? -EINVAL : 0; +} +#define v4l2_ioctl_s_output_mc v4l2_ioctl_s_input_mc + + +static int v4l_g_input(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_g_input_mc(file, fh, arg); + else + return ops->vidioc_g_input(file, fh, arg); +} + +static int v4l_g_output(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_g_output_mc(file, fh, arg); + else + return ops->vidioc_g_output(file, fh, arg); +} + static int v4l_s_input(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1028,13 +1092,22 @@ static int v4l_s_input(const struct v4l2_ioctl_ops *ops, ret = v4l_enable_media_source(vfd); if (ret) return ret; - return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_s_input_mc(file, fh, *(unsigned int *)arg); + else + return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); } static int v4l_s_output(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { - return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); + struct video_device *vfd = video_devdata(file); + + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_s_output_mc(file, fh, *(unsigned int *)arg); + else + return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); } static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, @@ -1077,7 +1150,10 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_IN_CAP_STD; - return ops->vidioc_enum_input(file, fh, p); + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_enum_input_mc(file, fh, p); + else + return ops->vidioc_enum_input(file, fh, p); } static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, @@ -1095,7 +1171,10 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_OUT_CAP_STD; - return ops->vidioc_enum_output(file, fh, p); + if (vfd->device_caps & V4L2_CAP_IO_MC) + return v4l2_ioctl_enum_output_mc(file, fh, p); + else + return ops->vidioc_enum_output(file, fh, p); } static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) @@ -2534,11 +2613,11 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_S_AUDIO, vidioc_s_audio, v4l_print_audio, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_QUERYCTRL, v4l_queryctrl, v4l_print_queryctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_queryctrl, id)), IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)), - IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0), + IOCTL_INFO_FNC(VIDIOC_G_INPUT, v4l_g_input, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, 0), IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO), - IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0), + IOCTL_INFO_FNC(VIDIOC_G_OUTPUT, v4l_g_output, v4l_print_u32, 0), IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0), diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 2b8feb8..94cb196 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -460,6 +460,8 @@ struct v4l2_capability { #define V4L2_CAP_TOUCH 0x10000000 /* Is a touch device */ +#define V4L2_CAP_IO_MC 0x20000000 /* Is input/output controlled by the media controler */ + #define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ /* -- 2.7.4