Commit 839b9d2c authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

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: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent ae27c563
Loading
Loading
Loading
Loading
+129 −41
Original line number Diff line number Diff line
@@ -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) {
		enum omap_dss_trans_key_type key_type =
			OMAP_DSS_COLOR_KEY_GFX_DST;
		int enable;

		/* Video1 plane does not support global alpha on OMAP3 */
		if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
			vout->win.global_alpha = 255;
		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
			vout->win.global_alpha = f->fmt.win.global_alpha;
			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;

		vout->win.chromakey = f->fmt.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->chromakey = vout->win.chromakey;
	if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)
		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;
	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);
	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_BG_COLOR, 0, 0xffffff, 1, 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);
	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())
+5 −1
Original line number Diff line number Diff line
@@ -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);