[media] omap_vout: add missing OVERLAY_OUTPUT cap and set V4L2_FBUF_FLAG_OVERLAY
[pandora-kernel.git] / drivers / media / video / omap / omap_vout.c
index b3a5ecd..2c8048a 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/irq.h>
 #include <linux/videodev2.h>
 #include <linux/dma-mapping.h>
+#include <linux/slab.h>
 
 #include <media/videobuf-dma-contig.h>
 #include <media/v4l2-device.h>
@@ -205,19 +206,21 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp)
        struct vm_area_struct *vma;
        struct mm_struct *mm = current->mm;
 
-       vma = find_vma(mm, virtp);
        /* For kernel direct-mapped memory, take the easy way */
-       if (virtp >= PAGE_OFFSET) {
-               physp = virt_to_phys((void *) virtp);
-       } else if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
+       if (virtp >= PAGE_OFFSET)
+               return virt_to_phys((void *) virtp);
+
+       down_read(&current->mm->mmap_sem);
+       vma = find_vma(mm, virtp);
+       if (vma && (vma->vm_flags & VM_IO) && vma->vm_pgoff) {
                /* this will catch, kernel-allocated, mmaped-to-usermode
                   addresses */
                physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+               up_read(&current->mm->mmap_sem);
        } else {
                /* otherwise, use get_user_pages() for general userland pages */
                int res, nr_pages = 1;
                struct page *pages;
-               down_read(&current->mm->mmap_sem);
 
                res = get_user_pages(current, current->mm, virtp, nr_pages, 1,
                                0, &pages, NULL);
@@ -400,7 +403,6 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
 
        ovl->get_overlay_info(ovl, &info);
        info.paddr = addr;
-       info.vaddr = NULL;
        info.width = cropwidth;
        info.height = cropheight;
        info.color_mode = vout->dss_mode;
@@ -834,6 +836,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q,
 /*
  *  File operations
  */
+static unsigned int omap_vout_poll(struct file *file,
+                                  struct poll_table_struct *wait)
+{
+       struct omap_vout_device *vout = file->private_data;
+       struct videobuf_queue *q = &vout->vbq;
+
+       return videobuf_poll_stream(file, q, wait);
+}
+
 static void omap_vout_vm_open(struct vm_area_struct *vma)
 {
        struct omap_vout_device *vout = vma->vm_private_data;
@@ -1032,7 +1043,8 @@ static int vidioc_querycap(struct file *file, void *fh,
        strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
        strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
        cap->bus_info[0] = '\0';
-       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+       cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+               V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
 
        return 0;
 }
@@ -1165,12 +1177,17 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
 {
        int ret = 0;
        struct omap_vout_device *vout = fh;
+       struct omap_overlay *ovl;
+       struct omapvideo_info *ovid;
        struct v4l2_window *win = &f->fmt.win;
 
+       ovid = &vout->vid_info;
+       ovl = ovid->overlays[0];
+
        ret = omap_vout_try_window(&vout->fbuf, win);
 
        if (!ret) {
-               if (vout->vid == OMAP_VIDEO1)
+               if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
                        win->global_alpha = 255;
                else
                        win->global_alpha = f->fmt.win.global_alpha;
@@ -1194,8 +1211,8 @@ 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 */
-               if (ovl->id == OMAP_DSS_VIDEO1)
+               /* 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;
@@ -1788,7 +1805,9 @@ static int vidioc_s_fbuf(struct file *file, void *fh,
        if (ovl->manager && ovl->manager->get_manager_info &&
                        ovl->manager->set_manager_info) {
                ovl->manager->get_manager_info(ovl->manager, &info);
-               info.alpha_enabled = enable;
+               /* enable this only if there is no zorder cap */
+               if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+                       info.partial_alpha_enabled = enable;
                if (ovl->manager->set_manager_info(ovl->manager, &info))
                        return -EINVAL;
        }
@@ -1807,7 +1826,9 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
        ovid = &vout->vid_info;
        ovl = ovid->overlays[0];
 
-       a->flags = 0x0;
+       /* 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;
 
@@ -1820,7 +1841,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
        }
        if (ovl->manager && ovl->manager->get_manager_info) {
                ovl->manager->get_manager_info(ovl->manager, &info);
-               if (info.alpha_enabled)
+               if (info.partial_alpha_enabled)
                        a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
        }
 
@@ -1855,6 +1876,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = {
 
 static const struct v4l2_file_operations omap_vout_fops = {
        .owner          = THIS_MODULE,
+       .poll           = omap_vout_poll,
        .unlocked_ioctl = video_ioctl2,
        .mmap           = omap_vout_mmap,
        .open           = omap_vout_open,
@@ -2153,6 +2175,14 @@ static int __init omap_vout_probe(struct platform_device *pdev)
        vid_dev->num_displays = 0;
        for_each_dss_dev(dssdev) {
                omap_dss_get_device(dssdev);
+
+               if (!dssdev->driver) {
+                       dev_warn(&pdev->dev, "no driver for display: %s\n",
+                                       dssdev->name);
+                       omap_dss_put_device(dssdev);
+                       continue;
+               }
+
                vid_dev->displays[vid_dev->num_displays++] = dssdev;
        }