diff options
author | Olof Johansson <olof@lixom.net> | 2019-12-05 13:16:58 -0800 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2019-12-05 13:18:54 -0800 |
commit | 942e6f8a8314e5550e254519dfba4ccd5170421d (patch) | |
tree | 75ec655b440fbc1c454247af38b5596dd8c78de9 /drivers/media/platform/vivid | |
parent | ARM: pxa: Fix resource properties (diff) | |
parent | Merge tag 'armsoc-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc (diff) | |
download | linux-dev-942e6f8a8314e5550e254519dfba4ccd5170421d.tar.xz linux-dev-942e6f8a8314e5550e254519dfba4ccd5170421d.zip |
Merge mainline/master into arm/fixes
This brings in the mainline tree right after armsoc contents was merged
this release cycle, so that we can re-run savedefconfig, etc.
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/media/platform/vivid')
-rw-r--r-- | drivers/media/platform/vivid/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-cec.c | 7 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-core.c | 368 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-core.h | 25 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-ctrls.c | 89 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-kthread-cap.c | 62 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-kthread-out.c | 57 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-meta-cap.c | 201 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-meta-cap.h | 29 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-meta-out.c | 174 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-meta-out.h | 25 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-sdr-cap.c | 8 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-vid-cap.c | 8 | ||||
-rw-r--r-- | drivers/media/platform/vivid/vivid-vid-out.c | 8 |
14 files changed, 925 insertions, 138 deletions
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile index 2f5762e3309a..e8a50c506dc9 100644 --- a/drivers/media/platform/vivid/Makefile +++ b/drivers/media/platform/vivid/Makefile @@ -3,7 +3,7 @@ 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-osd.o vivid-meta-cap.o vivid-meta-out.o ifeq ($(CONFIG_VIDEO_VIVID_CEC),y) vivid-objs += vivid-cec.o endif diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index 4d822dbed972..4d2413e87730 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -276,12 +276,11 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, unsigned int idx, bool is_source) { - char name[sizeof(dev->vid_out_dev.name) + 2]; u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; + char name[32]; - snprintf(name, sizeof(name), "%s%d", - is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name, - idx); + snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", + dev->inst, is_source ? "out" : "cap", idx); return cec_allocate_adapter(&vivid_cec_adap_ops, dev, name, caps, 1); } diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 53315c8dd2bb..c184f9b0be69 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -37,6 +37,8 @@ #include "vivid-osd.h" #include "vivid-cec.h" #include "vivid-ctrls.h" +#include "vivid-meta-cap.h" +#include "vivid-meta-out.h" #define VIVID_MODULE_NAME "vivid" @@ -79,6 +81,14 @@ static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; module_param_array(radio_tx_nr, int, NULL, 0444); MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); +static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(meta_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect"); + +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 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" @@ -95,10 +105,15 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1 module_param_array(multiplanar, uint, NULL, 0444); MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device."); -/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */ -static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d }; +/* + * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + + * vbi-out + vid-out + meta-cap + */ +static unsigned int node_types[VIVID_MAX_DEVS] = { + [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d +}; module_param_array(node_types, uint, NULL, 0444); -MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n" +MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. 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" @@ -106,7 +121,9 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f "\t\t bit 8: Video Output node\n" "\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" "\t\t bit 12: Radio Transmitter node\n" - "\t\t bit 16: Framebuffer for testing overlays"); + "\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"); /* Default: 4 inputs */ static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; @@ -205,7 +222,8 @@ static int vidioc_querycap(struct file *file, void *priv, cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | dev->vbi_cap_caps | dev->vbi_out_caps | dev->radio_rx_caps | dev->radio_tx_caps | - dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS; + dev->sdr_cap_caps | dev->meta_cap_caps | + dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -433,7 +451,9 @@ static bool vivid_is_last_user(struct vivid_dev *dev) vivid_is_in_use(&dev->vbi_out_dev) + vivid_is_in_use(&dev->sdr_cap_dev) + vivid_is_in_use(&dev->radio_rx_dev) + - vivid_is_in_use(&dev->radio_tx_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); return uses == 1; } @@ -459,6 +479,8 @@ static int vivid_fop_release(struct file *file) set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); 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); } mutex_unlock(&dev->mutex); if (file->private_data == dev->overlay_cap_owner) @@ -604,6 +626,16 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = vidioc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = vidioc_g_fmt_meta_cap, + + .vidioc_enum_fmt_meta_out = vidioc_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = vidioc_g_fmt_meta_out, }; /* ----------------------------------------------------------------- @@ -616,6 +648,9 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev) vivid_free_controls(dev); v4l2_device_unregister(&dev->v4l2_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif vfree(dev->scaled_line); vfree(dev->blended_line); vfree(dev->edid); @@ -645,14 +680,44 @@ static const struct media_device_ops vivid_media_ops = { }; #endif +static int vivid_create_queue(struct vivid_dev *dev, + struct vb2_queue *q, + u32 buf_type, + unsigned int min_buffers_needed, + const struct vb2_ops *ops) +{ + if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE && !dev->has_raw_vbi_cap) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + else if (buf_type == V4L2_BUF_TYPE_VBI_OUTPUT && !dev->has_raw_vbi_out) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + + q->type = buf_type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ; + if (allocators[dev->inst] != 1) + q->io_modes |= VB2_USERPTR; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = ops; + q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : + &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = min_buffers_needed; + q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; + q->supports_requests = true; + + return vb2_queue_init(q); +} + static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = V4L2_DV_BT_CEA_1280X720P60; - static const struct vb2_mem_ops * const vivid_mem_ops[2] = { - &vb2_vmalloc_memops, - &vb2_dma_contig_memops, - }; unsigned in_type_counter[4] = { 0, 0, 0, 0 }; unsigned out_type_counter[4] = { 0, 0, 0, 0 }; int ccs_cap = ccs_cap_mode[inst]; @@ -661,9 +726,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) bool has_modulator; struct vivid_dev *dev; struct video_device *vfd; - struct vb2_queue *q; unsigned node_type = node_types[inst]; - unsigned int allocator = allocators[inst]; v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; int ret; int i; @@ -758,6 +821,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap; } + /* do we create a meta capture device */ + dev->has_meta_cap = node_type & 0x20000; + + /* sanity checks */ + if ((in_type_counter[WEBCAM] || in_type_counter[HDMI]) && + !dev->has_vid_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "Webcam or HDMI input without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if ((in_type_counter[TV] || in_type_counter[SVID]) && + !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "TV or S-Video input without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + /* do we create a video output device? */ dev->has_vid_out = node_type & 0x0100; @@ -768,6 +850,24 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out; } + /* do we create a metadata output device */ + dev->has_meta_out = node_type & 0x40000; + + /* sanity checks */ + if (out_type_counter[SVID] && + !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "S-Video output without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "HDMI output without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + /* do we create a radio receiver device? */ dev->has_radio_rx = node_type & 0x0010; @@ -777,6 +877,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* do we create a software defined radio capture device? */ dev->has_sdr_cap = node_type & 0x0020; + /* do we have a TV tuner? */ + dev->has_tv_tuner = in_type_counter[TV]; + /* do we have a tuner? */ has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) || dev->has_radio_rx || dev->has_sdr_cap; @@ -828,7 +931,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; if (dev->has_audio_inputs) dev->vid_cap_caps |= V4L2_CAP_AUDIO; - if (in_type_counter[TV]) + if (dev->has_tv_tuner) dev->vid_cap_caps |= V4L2_CAP_TUNER; } if (dev->has_vid_out) { @@ -849,7 +952,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; if (dev->has_audio_inputs) dev->vbi_cap_caps |= V4L2_CAP_AUDIO; - if (in_type_counter[TV]) + if (dev->has_tv_tuner) dev->vbi_cap_caps |= V4L2_CAP_TUNER; } if (dev->has_vbi_out) { @@ -875,6 +978,23 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | V4L2_CAP_READWRITE; + /* set up the capabilities of meta capture device */ + if (dev->has_meta_cap) { + dev->meta_cap_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->meta_cap_caps |= V4L2_CAP_AUDIO; + if (dev->has_tv_tuner) + dev->meta_cap_caps |= V4L2_CAP_TUNER; + } + /* set up the capabilities of meta output device */ + if (dev->has_meta_out) { + dev->meta_out_caps = V4L2_CAP_META_OUTPUT | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->meta_out_caps |= V4L2_CAP_AUDIO; + } + ret = -ENOMEM; /* initialize the test pattern generator */ tpg_init(&dev->tpg, 640, 360); @@ -934,6 +1054,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); + 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); } if (!dev->has_audio_outputs) { v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); @@ -942,6 +1065,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT); } if (!in_type_counter[TV] && !in_type_counter[SVID]) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD); @@ -959,12 +1085,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); 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); } if (!has_tuner) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); 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); } if (in_type_counter[HDMI] == 0) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); @@ -990,12 +1120,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); 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->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); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY); 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); /* configure internal data */ dev->fmt_cap = &vivid_formats[0]; @@ -1078,6 +1211,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) INIT_LIST_HEAD(&dev->vbi_cap_active); INIT_LIST_HEAD(&dev->vbi_out_active); 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->cec_work_list); spin_lock_init(&dev->cec_slock); @@ -1092,126 +1227,69 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) goto unreg_dev; } - if (allocator == 1) + if (allocators[inst] == 1) dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - else if (allocator >= ARRAY_SIZE(vivid_mem_ops)) - allocator = 0; /* start creating the vb2 queues */ if (dev->has_vid_cap) { - snprintf(dev->vid_cap_dev.name, sizeof(dev->vid_cap_dev.name), - "vivid-%03d-vid-cap", inst); /* initialize vid_cap queue */ - q = &dev->vb_vid_cap_q; - q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - 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_vid_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vid_cap_q, + V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + &vivid_vid_cap_qops); if (ret) goto unreg_dev; } if (dev->has_vid_out) { - snprintf(dev->vid_out_dev.name, sizeof(dev->vid_out_dev.name), - "vivid-%03d-vid-out", inst); /* initialize vid_out queue */ - q = &dev->vb_vid_out_q; - q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : - V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vid_out_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vid_out_q, + V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + &vivid_vid_out_qops); if (ret) goto unreg_dev; } if (dev->has_vbi_cap) { /* initialize vbi_cap queue */ - q = &dev->vb_vbi_cap_q; - q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE : - V4L2_BUF_TYPE_SLICED_VBI_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_vbi_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vbi_cap_q, + V4L2_BUF_TYPE_VBI_CAPTURE, 2, + &vivid_vbi_cap_qops); if (ret) goto unreg_dev; } if (dev->has_vbi_out) { /* initialize vbi_out queue */ - q = &dev->vb_vbi_out_q; - q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT : - V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vbi_out_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vbi_out_q, + V4L2_BUF_TYPE_VBI_OUTPUT, 2, + &vivid_vbi_out_qops); if (ret) goto unreg_dev; } if (dev->has_sdr_cap) { /* initialize sdr_cap queue */ - q = &dev->vb_sdr_cap_q; - q->type = V4L2_BUF_TYPE_SDR_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_sdr_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 8; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_sdr_cap_q, + V4L2_BUF_TYPE_SDR_CAPTURE, 8, + &vivid_sdr_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_cap) { + /* initialize meta_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_cap_q, + V4L2_BUF_TYPE_META_CAPTURE, 2, + &vivid_meta_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_out) { + /* initialize meta_out queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_out_q, + V4L2_BUF_TYPE_META_OUTPUT, 1, + &vivid_meta_out_qops); if (ret) goto unreg_dev; } @@ -1222,7 +1300,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret) goto unreg_dev; v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", - dev->fb_info.node); + dev->fb_info.node); } #ifdef CONFIG_VIDEO_VIVID_CEC @@ -1265,10 +1343,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); 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); /* finally start creating the device nodes */ if (dev->has_vid_cap) { vfd = &dev->vid_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-cap", inst); vfd->fops = &vivid_fops; vfd->ioctl_ops = &vivid_ioctl_ops; vfd->device_caps = dev->vid_cap_caps; @@ -1314,6 +1396,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (dev->has_vid_out) { vfd = &dev->vid_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-out", inst); vfd->vfl_dir = VFL_DIR_TX; vfd->fops = &vivid_fops; vfd->ioctl_ops = &vivid_ioctl_ops; @@ -1492,6 +1576,65 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) video_device_node_name(vfd)); } + if (dev->has_meta_cap) { + vfd = &dev->meta_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_cap_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_cap; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_cap_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_GRABBER, + meta_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_meta_out) { + vfd = &dev->meta_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-out", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_out_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_out_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_out; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_out_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_GRABBER, + meta_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata output device registered as %s\n", + video_device_node_name(vfd)); + } + #ifdef CONFIG_MEDIA_CONTROLLER /* Register the media device */ ret = media_device_register(&dev->mdev); @@ -1508,6 +1651,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) return 0; unreg_dev: + video_unregister_device(&dev->meta_out_dev); + video_unregister_device(&dev->meta_cap_dev); video_unregister_device(&dev->radio_tx_dev); video_unregister_device(&dev->radio_rx_dev); video_unregister_device(&dev->sdr_cap_dev); @@ -1580,7 +1725,6 @@ static int vivid_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); - media_device_cleanup(&dev->mdev); #endif if (dev->has_vid_cap) { @@ -1624,6 +1768,16 @@ static int vivid_remove(struct platform_device *pdev) unregister_framebuffer(&dev->fb_info); vivid_fb_release_buffers(dev); } + if (dev->has_meta_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_cap_dev)); + video_unregister_device(&dev->meta_cap_dev); + } + if (dev->has_meta_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_out_dev)); + video_unregister_device(&dev->meta_out_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 7ebb14673c75..59192b67231c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -131,6 +131,8 @@ struct vivid_dev { struct media_pad vbi_cap_pad; struct media_pad vbi_out_pad; struct media_pad sdr_cap_pad; + struct media_pad meta_cap_pad; + struct media_pad meta_out_pad; #endif struct v4l2_ctrl_handler ctrl_hdl_user_gen; struct v4l2_ctrl_handler ctrl_hdl_user_vid; @@ -153,6 +155,11 @@ struct vivid_dev { struct v4l2_ctrl_handler ctrl_hdl_radio_tx; struct video_device sdr_cap_dev; struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; + struct video_device meta_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_cap; + struct video_device meta_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_out; + spinlock_t slock; struct mutex mutex; @@ -164,6 +171,8 @@ struct vivid_dev { u32 sdr_cap_caps; u32 radio_rx_caps; u32 radio_tx_caps; + u32 meta_cap_caps; + u32 meta_out_caps; /* supported features */ bool multiplanar; @@ -189,6 +198,9 @@ struct vivid_dev { bool has_radio_tx; bool has_sdr_cap; bool has_fb; + bool has_meta_cap; + bool has_meta_out; + bool has_tv_tuner; bool can_loop_video; @@ -390,6 +402,8 @@ struct vivid_dev { struct list_head vid_cap_active; struct vb2_queue vb_vbi_cap_q; struct list_head vbi_cap_active; + struct vb2_queue vb_meta_cap_q; + struct list_head meta_cap_active; /* thread for generating video capture stream */ struct task_struct *kthread_vid_cap; @@ -407,6 +421,9 @@ struct vivid_dev { u32 vbi_cap_seq_count; bool vbi_cap_streaming; bool stream_sliced_vbi_cap; + u32 meta_cap_seq_start; + u32 meta_cap_seq_count; + bool meta_cap_streaming; /* video output */ const struct vivid_fmt *fmt_out; @@ -421,6 +438,8 @@ struct vivid_dev { struct list_head vid_out_active; struct vb2_queue vb_vbi_out_q; struct list_head vbi_out_active; + struct vb2_queue vb_meta_out_q; + struct list_head meta_out_active; /* video loop precalculated rectangles */ @@ -461,6 +480,9 @@ struct vivid_dev { u32 vbi_out_seq_count; bool vbi_out_streaming; bool stream_sliced_vbi_out; + u32 meta_out_seq_start; + u32 meta_out_seq_count; + bool meta_out_streaming; /* SDR capture */ struct vb2_queue vb_sdr_cap_q; @@ -527,6 +549,9 @@ struct vivid_dev { /* CEC OSD String */ char osd[14]; unsigned long osd_jiffies; + + bool meta_pts; + bool meta_scr; }; static inline bool vivid_is_webcam(const struct vivid_dev *dev) diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index cb19a9a73092..68e8124c7973 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -32,6 +32,7 @@ #define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8) #define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9) #define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) +#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) #define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) #define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) @@ -94,6 +95,9 @@ #define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110) +#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111) +#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112) + /* General User Controls */ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) @@ -110,6 +114,7 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); break; case VIVID_CID_BUTTON: dev->button_pressed = 30; @@ -262,6 +267,18 @@ static const struct v4l2_ctrl_config vivid_ctrl_disconnect = { .type = V4L2_CTRL_TYPE_BUTTON, }; +static const struct v4l2_area area = { + .width = 1000, + .height = 2000, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_area = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_AREA, + .name = "Area", + .type = V4L2_CTRL_TYPE_AREA, + .p_def.p_const = &area, +}; /* Framebuffer Controls */ @@ -1421,6 +1438,47 @@ static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = { .step = 1, }; +/* Metadata Capture Control */ + +static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, + ctrl_hdl_meta_cap); + + switch (ctrl->id) { + case VIVID_CID_META_CAP_GENERATE_PTS: + dev->meta_pts = ctrl->val; + break; + case VIVID_CID_META_CAP_GENERATE_SCR: + dev->meta_scr = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = { + .s_ctrl = vivid_meta_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_PTS, + .name = "Generate PTS", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_SCR, + .name = "Generate SCR", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; static const struct v4l2_ctrl_config vivid_ctrl_class = { .ops = &vivid_user_gen_ctrl_ops, @@ -1448,6 +1506,9 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; 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_config vivid_ctrl_dv_timings = { .ops = &vivid_vid_cap_ctrl_ops, .id = VIVID_CID_DV_TIMINGS, @@ -1486,6 +1547,10 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_sdr_cap, 19); v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_meta_cap, 2); + 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); /* User Controls */ dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, @@ -1522,6 +1587,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); @@ -1743,6 +1809,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_sdr_cap_fm_deviation, NULL); } + if (dev->has_meta_cap) { + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_pts, NULL); + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_src_clk, NULL); + } + if (hdl_user_gen->error) return hdl_user_gen->error; if (hdl_user_vid->error) @@ -1817,6 +1890,20 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, return hdl_sdr_cap->error; dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; } + if (dev->has_meta_cap) { + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false); + if (hdl_meta_cap->error) + return hdl_meta_cap->error; + dev->meta_cap_dev.ctrl_handler = hdl_meta_cap; + } + if (dev->has_meta_out) { + v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false); + if (hdl_meta_out->error) + return hdl_meta_out->error; + dev->meta_out_dev.ctrl_handler = hdl_meta_out; + } return 0; } @@ -1836,4 +1923,6 @@ void vivid_free_controls(struct vivid_dev *dev) v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); 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); } diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 003319d7816d..01a9d671b947 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -39,6 +39,7 @@ #include "vivid-osd.h" #include "vivid-ctrls.h" #include "vivid-kthread-cap.h" +#include "vivid-meta-cap.h" static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) { @@ -677,6 +678,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, { struct vivid_buffer *vid_cap_buf = NULL; struct vivid_buffer *vbi_cap_buf = NULL; + struct vivid_buffer *meta_cap_buf = NULL; u64 f_time = 0; dprintk(dev, 1, "Video Capture Thread Tick\n"); @@ -704,15 +706,19 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, list_del(&vbi_cap_buf->list); } } + if (!list_empty(&dev->meta_cap_active)) { + meta_cap_buf = list_entry(dev->meta_cap_active.next, + struct vivid_buffer, list); + list_del(&meta_cap_buf->list); + } + spin_unlock(&dev->slock); - if (!vid_cap_buf && !vbi_cap_buf) + if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf) goto update_mv; f_time = dev->cap_frame_period * dev->vid_cap_seq_count + dev->cap_stream_start + dev->time_wrap_offset; - if (!dev->tstamp_src_is_soe) - f_time += dev->cap_frame_eof_offset; if (vid_cap_buf) { v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, @@ -735,6 +741,8 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, vid_cap_buf->vb.vb2_buf.index); vid_cap_buf->vb.vb2_buf.timestamp = f_time; + if (!dev->tstamp_src_is_soe) + vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset; } if (vbi_cap_buf) { @@ -756,8 +764,22 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, /* If capturing a VBI, offset by 0.05 */ vbi_period = dev->cap_frame_period * 5; do_div(vbi_period, 100); - vbi_cap_buf->vb.vb2_buf.timestamp = f_time + vbi_period; + vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period; + } + + if (meta_cap_buf) { + v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time); + v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_cap %d done\n", + 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: @@ -796,7 +818,11 @@ static int vivid_thread_vid_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->cap_seq_resync) { dev->jiffies_vid_cap = cur_jiffies; @@ -835,6 +861,7 @@ static int vivid_thread_vid_cap(void *data) dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; + dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start; vivid_thread_vid_cap_tick(dev, dropped_bufs); @@ -883,8 +910,10 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) if (pstreaming == &dev->vid_cap_streaming) dev->vid_cap_seq_start = seq_count; - else + else if (pstreaming == &dev->vbi_cap_streaming) dev->vbi_cap_seq_start = seq_count; + else + dev->meta_cap_seq_start = seq_count; *pstreaming = true; return 0; } @@ -894,6 +923,7 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) dev->vid_cap_seq_start = dev->seq_wrap * 128; dev->vbi_cap_seq_start = dev->seq_wrap * 128; + dev->meta_cap_seq_start = dev->seq_wrap * 128; dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, "%s-vid-cap", dev->v4l2_dev.name); @@ -951,13 +981,27 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) } } - if (dev->vid_cap_streaming || dev->vbi_cap_streaming) + if (pstreaming == &dev->meta_cap_streaming) { + while (!list_empty(&dev->meta_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_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_meta_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_cap_streaming || dev->vbi_cap_streaming || + dev->meta_cap_streaming) return; /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_cap); dev->kthread_vid_cap = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index ce5bcda2348c..6780687978f9 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -38,11 +38,13 @@ #include "vivid-osd.h" #include "vivid-ctrls.h" #include "vivid-kthread-out.h" +#include "vivid-meta-out.h" static void vivid_thread_vid_out_tick(struct vivid_dev *dev) { struct vivid_buffer *vid_out_buf = NULL; struct vivid_buffer *vbi_out_buf = NULL; + struct vivid_buffer *meta_out_buf = NULL; dprintk(dev, 1, "Video Output Thread Tick\n"); @@ -69,9 +71,14 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) struct vivid_buffer, list); list_del(&vbi_out_buf->list); } + if (!list_empty(&dev->meta_out_active)) { + meta_out_buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&meta_out_buf->list); + } spin_unlock(&dev->slock); - if (!vid_out_buf && !vbi_out_buf) + if (!vid_out_buf && !vbi_out_buf && !meta_out_buf) return; if (vid_out_buf) { @@ -111,6 +118,21 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) dprintk(dev, 2, "vbi_out buffer %d done\n", vbi_out_buf->vb.vb2_buf.index); } + if (meta_out_buf) { + v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vivid_meta_out_process(dev, meta_out_buf); + meta_out_buf->vb.sequence = dev->meta_out_seq_count; + meta_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_out buffer %d done\n", + meta_out_buf->vb.vb2_buf.index); + } + dev->dqbuf_error = false; } @@ -136,6 +158,7 @@ static int vivid_thread_vid_out(void *data) dev->out_seq_count = 0xffffff80U; dev->jiffies_vid_out = jiffies; dev->vid_out_seq_start = dev->vbi_out_seq_start = 0; + dev->meta_out_seq_start = 0; dev->out_seq_resync = false; for (;;) { @@ -143,7 +166,11 @@ static int vivid_thread_vid_out(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->out_seq_resync) { dev->jiffies_vid_out = cur_jiffies; @@ -178,6 +205,7 @@ static int vivid_thread_vid_out(void *data) dev->out_seq_count = buffers_since_start + dev->out_seq_offset; dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; + dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start; vivid_thread_vid_out_tick(dev); mutex_unlock(&dev->mutex); @@ -229,8 +257,10 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) if (pstreaming == &dev->vid_out_streaming) dev->vid_out_seq_start = seq_count; - else + else if (pstreaming == &dev->vbi_out_streaming) dev->vbi_out_seq_start = seq_count; + else + dev->meta_out_seq_start = seq_count; *pstreaming = true; return 0; } @@ -239,6 +269,7 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) dev->jiffies_vid_out = jiffies; dev->vid_out_seq_start = dev->seq_wrap * 128; dev->vbi_out_seq_start = dev->seq_wrap * 128; + dev->meta_out_seq_start = dev->seq_wrap * 128; dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, "%s-vid-out", dev->v4l2_dev.name); @@ -296,13 +327,27 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) } } - if (dev->vid_out_streaming || dev->vbi_out_streaming) + if (pstreaming == &dev->meta_out_streaming) { + while (!list_empty(&dev->meta_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_out buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_out_streaming || dev->vbi_out_streaming || + dev->meta_out_streaming) return; /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_out); dev->kthread_vid_out = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-meta-cap.c b/drivers/media/platform/vivid/vivid-meta-cap.c new file mode 100644 index 000000000000..780f96860a6d --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-cap.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-cap.c - meta capture 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-cap.h" +#include "vivid-meta-cap.h" + +static int meta_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_uvc_meta_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + 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 meta_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_uvc_meta_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 meta_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->meta_cap_active); + spin_unlock(&dev->slock); +} + +static int meta_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->meta_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, + &dev->meta_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_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 meta_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_vid_cap(dev, &dev->meta_cap_streaming); +} + +static void meta_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_meta_cap); +} + +const struct vb2_ops vivid_meta_cap_qops = { + .queue_setup = meta_cap_queue_setup, + .buf_prepare = meta_cap_buf_prepare, + .buf_queue = meta_cap_buf_queue, + .start_streaming = meta_cap_start_streaming, + .stop_streaming = meta_cap_stop_streaming, + .buf_request_complete = meta_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_CAPTURE; + f->pixelformat = V4L2_META_FMT_UVC; + return 0; +} + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_cap) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_UVC; + meta->buffersize = sizeof(struct vivid_uvc_meta_buf); + return 0; +} + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe) +{ + struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + int buf_off = 0; + + buf->vb.sequence = dev->meta_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.sequence /= 2; + memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0)); + + meta->ns = ktime_get_ns(); + meta->sof = buf->vb.sequence * 30; + meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length); + meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF; + + if ((buf->vb.sequence % 2) == 0) + meta->flags |= UVC_STREAM_FID; + + dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x", + __func__, meta->ns, meta->sof, meta->length, meta->flags); + if (dev->meta_pts) { + meta->flags |= UVC_STREAM_PTS; + meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT); + buf_off = 4; + dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf)); + } + + if (dev->meta_scr) { + meta->flags |= UVC_STREAM_SCR; + meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset), + VIVID_META_CLOCK_UNIT); + + meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000; + dprintk(dev, 2, " stc: %u, sof counter: %u\n", + *(__u32 *)(meta->buf + buf_off), + *(__u16 *)(meta->buf + buf_off + 4)); + } + dprintk(dev, 2, "\n"); +} diff --git a/drivers/media/platform/vivid/vivid-meta-cap.h b/drivers/media/platform/vivid/vivid-meta-cap.h new file mode 100644 index 000000000000..4670d00d1576 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-cap.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-cap.h - meta capture support functions. + */ +#ifndef _VIVID_META_CAP_H_ +#define _VIVID_META_CAP_H_ + +#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */ + +struct vivid_uvc_meta_buf { + __u64 ns; + __u16 sof; + __u8 length; + __u8 flags; + __u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */ +} __packed; + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe); + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f); + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_cap_qops; + +#endif diff --git a/drivers/media/platform/vivid/vivid-meta-out.c b/drivers/media/platform/vivid/vivid-meta-out.c new file mode 100644 index 000000000000..ff8a039aba72 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-out.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-out.c - meta output 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-out.h" +#include "vivid-meta-out.h" + +static int meta_out_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_meta_out_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + 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 meta_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_meta_out_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 meta_out_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->meta_out_active); + spin_unlock(&dev->slock); +} + +static int meta_out_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->meta_out_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, + &dev->meta_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_out_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 meta_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->meta_out_streaming); +} + +static void meta_out_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_meta_out); +} + +const struct vb2_ops vivid_meta_out_qops = { + .queue_setup = meta_out_queue_setup, + .buf_prepare = meta_out_buf_prepare, + .buf_queue = meta_out_buf_queue, + .start_streaming = meta_out_start_streaming, + .stop_streaming = meta_out_stop_streaming, + .buf_request_complete = meta_out_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_OUTPUT; + f->pixelformat = V4L2_META_FMT_VIVID; + return 0; +} + +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_out) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_VIVID; + meta->buffersize = sizeof(struct vivid_meta_out_buf); + return 0; +} + +void vivid_meta_out_process(struct vivid_dev *dev, + struct vivid_buffer *buf) +{ + struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + tpg_s_brightness(&dev->tpg, meta->brightness); + tpg_s_contrast(&dev->tpg, meta->contrast); + tpg_s_saturation(&dev->tpg, meta->saturation); + tpg_s_hue(&dev->tpg, meta->hue); + dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", + __func__, meta->brightness, meta->contrast, + meta->saturation, meta->hue); +} diff --git a/drivers/media/platform/vivid/vivid-meta-out.h b/drivers/media/platform/vivid/vivid-meta-out.h new file mode 100644 index 000000000000..0c639b7c2842 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-out.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-out.h - meta output support functions. + */ +#ifndef _VIVID_META_OUT_H_ +#define _VIVID_META_OUT_H_ + +struct vivid_meta_out_buf { + u16 brightness; + u16 contrast; + u16 saturation; + s16 hue; +}; + +void vivid_meta_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_out_qops; + +#endif diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 9acc709b0740..2b7522e16efc 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -141,7 +141,11 @@ static int vivid_thread_sdr_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->sdr_cap_seq_resync) { dev->jiffies_sdr_cap = cur_jiffies; @@ -303,10 +307,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq) } /* shutdown control thread */ - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_sdr_cap); dev->kthread_sdr_cap = NULL; - mutex_lock(&dev->mutex); } static void sdr_cap_buf_request_complete(struct vb2_buffer *vb) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 8cbaa0c998ed..e94beef008c8 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -223,9 +223,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_out_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_cap) - return 0; - dev->vid_cap_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); for (i = 0; i < VIDEO_MAX_FRAME; i++) @@ -1359,7 +1356,9 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) if (i == dev->input) return 0; - if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) + if (vb2_is_busy(&dev->vb_vid_cap_q) || + vb2_is_busy(&dev->vb_vbi_cap_q) || + vb2_is_busy(&dev->vb_meta_cap_q)) return -EBUSY; dev->input = i; @@ -1369,6 +1368,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; } dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; + dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; vivid_update_format_cap(dev, false); if (dev->colorspace) { diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 148b663a6075..ee3446e3217c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -161,9 +161,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_cap_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_out) - return 0; - dev->vid_out_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); if (dev->start_streaming_error) { @@ -1082,7 +1079,9 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) if (o == dev->output) return 0; - if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) + if (vb2_is_busy(&dev->vb_vid_out_q) || + vb2_is_busy(&dev->vb_vbi_out_q) || + vb2_is_busy(&dev->vb_meta_out_q)) return -EBUSY; dev->output = o; @@ -1093,6 +1092,7 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) dev->vid_out_dev.tvnorms = 0; dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; + dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms; vivid_update_format_out(dev); v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); |