media: omap_vout: fix various v4l2-compliance failures

This patch fixes the following v4l2-compliance failures:

- FIELD_ANY could be returned, which is not allowed.
- JPEG colorspace was set instead of SRGB.
- No control events.
- Empty bus_info in QUERYCAP.
- Overlay format handling wasn't zeroing bitmap/clips and
  didn't return the chromakey correctly.
- G_FBUF didn't fill in many of the v4l2_framebuffer values.
  Now also return the base address of the corresponding
  framebuffer that this overlays.
- Missing ENUM/G/S_OUTPUT ioctls.
- ROTATE/VFLIP controls were added when the HW didn't support them.

With these changes 'v4l2-compliance' passes all non-streaming tests.

Tested on a Pandaboard and a Beagle XM board.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Hans Verkuil 2019-07-30 03:38:16 -03:00 committed by Mauro Carvalho Chehab
parent ae27c563a6
commit 839b9d2c59
2 changed files with 136 additions and 44 deletions

View File

@ -43,6 +43,7 @@
#include <media/videobuf-dma-contig.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <video/omapvrfb.h>
#include <video/omapfb_dss.h>
@ -159,13 +160,13 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix)
ifmt = 0;
pix->pixelformat = omap_formats[ifmt].pixelformat;
pix->field = V4L2_FIELD_ANY;
pix->field = V4L2_FIELD_NONE;
switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
default:
pix->colorspace = V4L2_COLORSPACE_JPEG;
pix->colorspace = V4L2_COLORSPACE_SRGB;
bpp = YUYV_BPP;
break;
case V4L2_PIX_FMT_RGB565:
@ -836,10 +837,16 @@ static void omap_vout_buffer_release(struct videobuf_queue *q,
static __poll_t omap_vout_poll(struct file *file,
struct poll_table_struct *wait)
{
__poll_t req_events = poll_requested_events(wait);
struct omap_vout_device *vout = video_drvdata(file);
struct videobuf_queue *q = &vout->vbq;
__poll_t res = 0;
return videobuf_poll_stream(file, q, wait);
if (req_events & EPOLLPRI)
res = v4l2_ctrl_poll(file, wait);
if (req_events & (EPOLLOUT | EPOLLWRNORM))
res |= videobuf_poll_stream(file, q, wait);
return res;
}
static void omap_vout_vm_open(struct vm_area_struct *vma)
@ -1039,7 +1046,8 @@ static int vidioc_querycap(struct file *file, void *fh,
strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
strscpy(cap->card, vout->vfd->name, sizeof(cap->card));
cap->bus_info[0] = '\0';
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s.%d", VOUT_NAME, vout->vid);
return 0;
}
@ -1176,12 +1184,8 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
ret = omap_vout_try_window(&vout->fbuf, win);
if (!ret) {
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
win->global_alpha = 255;
else
win->global_alpha = f->fmt.win.global_alpha;
}
if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA))
win->global_alpha = 0;
return ret;
}
@ -1201,13 +1205,35 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
if (!ret) {
/* Video1 plane does not support global alpha on OMAP3 */
if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
vout->win.global_alpha = 255;
else
vout->win.global_alpha = f->fmt.win.global_alpha;
enum omap_dss_trans_key_type key_type =
OMAP_DSS_COLOR_KEY_GFX_DST;
int enable;
vout->win.chromakey = f->fmt.win.chromakey;
/* Video1 plane does not support global alpha on OMAP3 */
if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)
vout->win.global_alpha = win->global_alpha;
else
win->global_alpha = 0;
if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY |
V4L2_FBUF_FLAG_SRC_CHROMAKEY))
enable = 1;
else
enable = 0;
if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
if (ovl->manager && ovl->manager->get_manager_info &&
ovl->manager->set_manager_info) {
struct omap_overlay_manager_info info;
ovl->manager->get_manager_info(ovl->manager, &info);
info.trans_enabled = enable;
info.trans_key_type = key_type;
info.trans_key = vout->win.chromakey;
if (ovl->manager->set_manager_info(ovl->manager, &info))
ret = -EINVAL;
}
}
mutex_unlock(&vout->lock);
return ret;
@ -1216,11 +1242,9 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
struct v4l2_format *f)
{
u32 key_value = 0;
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
struct omap_vout_device *vout = video_drvdata(file);
struct omap_overlay_manager_info info;
struct v4l2_window *win = &f->fmt.win;
ovid = &vout->vid_info;
@ -1228,13 +1252,14 @@ static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
win->w = vout->win.w;
win->field = vout->win.field;
win->global_alpha = vout->win.global_alpha;
if (ovl->manager && ovl->manager->get_manager_info) {
ovl->manager->get_manager_info(ovl->manager, &info);
key_value = info.trans_key;
}
win->chromakey = key_value;
win->chromakey = vout->win.chromakey;
if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)
win->global_alpha = vout->win.global_alpha;
else
win->global_alpha = 0;
win->clips = NULL;
win->clipcount = 0;
win->bitmap = NULL;
return 0;
}
@ -1733,15 +1758,34 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
struct omapvideo_info *ovid;
struct omap_vout_device *vout = video_drvdata(file);
struct omap_overlay_manager_info info;
struct omap_video_timings *timing;
struct omap_dss_device *dssdev;
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
/* get the display device attached to the overlay */
dssdev = ovl->get_device(ovl);
/* The video overlay must stay within the framebuffer and can't be
positioned independently. */
a->flags = V4L2_FBUF_FLAG_OVERLAY;
a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
| V4L2_FBUF_CAP_SRC_CHROMAKEY;
if (!dssdev)
return -EINVAL;
timing = &dssdev->panel.timings;
vout->fbuf.fmt.height = timing->y_res;
vout->fbuf.fmt.width = timing->x_res;
a->fmt.field = V4L2_FIELD_NONE;
a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32;
a->fmt.height = vout->fbuf.fmt.height;
a->fmt.width = vout->fbuf.fmt.width;
a->fmt.bytesperline = vout->fbuf.fmt.width * 4;
a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline;
a->base = vout->fbuf.base;
a->flags = vout->fbuf.flags;
a->capability = vout->fbuf.capability;
a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY |
V4L2_FBUF_FLAG_LOCAL_ALPHA);
if (ovl->manager && ovl->manager->get_manager_info) {
ovl->manager->get_manager_info(ovl->manager, &info);
@ -1749,9 +1793,6 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
}
if (ovl->manager && ovl->manager->get_manager_info) {
ovl->manager->get_manager_info(ovl->manager, &info);
if (info.partial_alpha_enabled)
a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
@ -1759,6 +1800,27 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
return 0;
}
static int vidioc_enum_output(struct file *file, void *priv_fh,
struct v4l2_output *out)
{
if (out->index)
return -EINVAL;
snprintf(out->name, sizeof(out->name), "Overlay");
out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
return 0;
}
static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i)
{
*i = 0;
return 0;
}
static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i)
{
return i ? -EINVAL : 0;
}
static const struct v4l2_ioctl_ops vout_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
@ -1772,12 +1834,17 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = {
.vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_g_selection = vidioc_g_selection,
.vidioc_s_selection = vidioc_s_selection,
.vidioc_enum_output = vidioc_enum_output,
.vidioc_g_output = vidioc_g_output,
.vidioc_s_output = vidioc_s_output,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct v4l2_file_operations omap_vout_fops = {
@ -1808,32 +1875,41 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
/* Default pixel format is RGB 5-6-5 */
pix->pixelformat = V4L2_PIX_FMT_RGB565;
pix->field = V4L2_FIELD_ANY;
pix->field = V4L2_FIELD_NONE;
pix->bytesperline = pix->width * 2;
pix->sizeimage = pix->bytesperline * pix->height;
pix->colorspace = V4L2_COLORSPACE_JPEG;
pix->colorspace = V4L2_COLORSPACE_SRGB;
vout->bpp = RGB565_BPP;
vout->fbuf.fmt.width = display->panel.timings.x_res;
vout->fbuf.fmt.height = display->panel.timings.y_res;
/* Set the data structures for the overlay parameters*/
vout->win.global_alpha = 255;
vout->fbuf.flags = 0;
vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY;
vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
vout->win.chromakey = 0;
V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_EXTERNOVERLAY;
if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) {
vout->win.global_alpha = 255;
vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA;
vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
} else {
vout->win.global_alpha = 0;
}
vout->win.field = V4L2_FIELD_NONE;
omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
hdl = &vout->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 3);
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_ROTATE, 0, 270, 90, 0);
if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) {
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_ROTATE, 0, 270, 90, 0);
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
}
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0);
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
if (hdl->error)
return hdl->error;
@ -1930,6 +2006,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct omap2video_device *vid_dev = container_of(v4l2_dev,
struct omap2video_device, v4l2_dev);
struct omap_overlay *ovl = vid_dev->overlays[0];
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
for (k = 0; k < pdev->num_resources; k++) {
@ -1950,6 +2030,14 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
vout->vid_info.num_overlays = 1;
vout->vid_info.id = k + 1;
/*
* Set the framebuffer base, this allows applications to find
* the fb corresponding to this overlay.
*
* To be precise: fbuf.base should match smem_start of
* struct fb_fix_screeninfo.
*/
vout->fbuf.base = (void *)info.paddr;
/* Set VRFB as rotation_type for omap2 and omap3 */
if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx())

View File

@ -95,7 +95,11 @@ int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
/* We now have a valid preview window, so go with it */
new_win->w = try_win;
new_win->field = V4L2_FIELD_ANY;
new_win->field = V4L2_FIELD_NONE;
new_win->clips = NULL;
new_win->clipcount = 0;
new_win->bitmap = NULL;
return 0;
}
EXPORT_SYMBOL_GPL(omap_vout_try_window);