Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6.git] / drivers / media / video / omap / omap_vout.c
index b3a5ecd..a277f95 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>
@@ -69,9 +70,9 @@ static u32 video1_numbuffers = 3;
 static u32 video2_numbuffers = 3;
 static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
 static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
-static u32 vid1_static_vrfb_alloc;
-static u32 vid2_static_vrfb_alloc;
-static int debug;
+static bool vid1_static_vrfb_alloc;
+static bool vid2_static_vrfb_alloc;
+static bool debug;
 
 /* Module parameters */
 module_param(video1_numbuffers, uint, S_IRUGO);
@@ -400,7 +401,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;
@@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
                "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
                "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
                "out_height=%d rotation_type=%d screen_width=%d\n",
-               __func__, info.enabled, info.paddr, info.width, info.height,
+               __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
                info.color_mode, info.rotation, info.mirror, info.pos_x,
                info.pos_y, info.out_width, info.out_height, info.rotation_type,
                info.screen_width);
@@ -524,10 +524,50 @@ static int omapvid_apply_changes(struct omap_vout_device *vout)
        return 0;
 }
 
+static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
+               unsigned int irqstatus, struct timeval timevalue)
+{
+       u32 fid;
+
+       if (vout->first_int) {
+               vout->first_int = 0;
+               goto err;
+       }
+
+       if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
+               fid = 1;
+       else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
+               fid = 0;
+       else
+               goto err;
+
+       vout->field_id ^= 1;
+       if (fid != vout->field_id) {
+               if (fid == 0)
+                       vout->field_id = fid;
+       } else if (0 == fid) {
+               if (vout->cur_frm == vout->next_frm)
+                       goto err;
+
+               vout->cur_frm->ts = timevalue;
+               vout->cur_frm->state = VIDEOBUF_DONE;
+               wake_up_interruptible(&vout->cur_frm->done);
+               vout->cur_frm = vout->next_frm;
+       } else {
+               if (list_empty(&vout->dma_queue) ||
+                               (vout->cur_frm != vout->next_frm))
+                       goto err;
+       }
+
+       return vout->field_id;
+err:
+       return 0;
+}
+
 static void omap_vout_isr(void *arg, unsigned int irqstatus)
 {
-       int ret;
-       u32 addr, fid;
+       int ret, fid, mgr_id;
+       u32 addr, irq;
        struct omap_overlay *ovl;
        struct timeval timevalue;
        struct omapvideo_info *ovid;
@@ -543,112 +583,73 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
        if (!ovl->manager || !ovl->manager->device)
                return;
 
+       mgr_id = ovl->manager->id;
        cur_display = ovl->manager->device;
 
        spin_lock(&vout->vbq_lock);
        do_gettimeofday(&timevalue);
 
-       if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) {
-               switch (cur_display->type) {
-               case OMAP_DISPLAY_TYPE_DPI:
-                       if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2)))
-                               goto vout_isr_err;
-                       break;
-               case OMAP_DISPLAY_TYPE_HDMI:
-                       if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
-                               goto vout_isr_err;
-                       break;
-               default:
-                       goto vout_isr_err;
-               }
-               if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
-                       vout->cur_frm->ts = timevalue;
-                       vout->cur_frm->state = VIDEOBUF_DONE;
-                       wake_up_interruptible(&vout->cur_frm->done);
-                       vout->cur_frm = vout->next_frm;
-               }
-               vout->first_int = 0;
-               if (list_empty(&vout->dma_queue))
+       switch (cur_display->type) {
+       case OMAP_DISPLAY_TYPE_DSI:
+       case OMAP_DISPLAY_TYPE_DPI:
+               if (mgr_id == OMAP_DSS_CHANNEL_LCD)
+                       irq = DISPC_IRQ_VSYNC;
+               else if (mgr_id == OMAP_DSS_CHANNEL_LCD2)
+                       irq = DISPC_IRQ_VSYNC2;
+               else
                        goto vout_isr_err;
 
-               vout->next_frm = list_entry(vout->dma_queue.next,
-                               struct videobuf_buffer, queue);
-               list_del(&vout->next_frm->queue);
-
-               vout->next_frm->state = VIDEOBUF_ACTIVE;
+               if (!(irqstatus & irq))
+                       goto vout_isr_err;
+               break;
+       case OMAP_DISPLAY_TYPE_VENC:
+               fid = omapvid_handle_interlace_display(vout, irqstatus,
+                               timevalue);
+               if (!fid)
+                       goto vout_isr_err;
+               break;
+       case OMAP_DISPLAY_TYPE_HDMI:
+               if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+                       goto vout_isr_err;
+               break;
+       default:
+               goto vout_isr_err;
+       }
 
-               addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
-                       + vout->cropped_offset;
+       if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+               vout->cur_frm->ts = timevalue;
+               vout->cur_frm->state = VIDEOBUF_DONE;
+               wake_up_interruptible(&vout->cur_frm->done);
+               vout->cur_frm = vout->next_frm;
+       }
 
-               /* First save the configuration in ovelray structure */
-               ret = omapvid_init(vout, addr);
-               if (ret)
-                       printk(KERN_ERR VOUT_NAME
-                               "failed to set overlay info\n");
-               /* Enable the pipeline and set the Go bit */
-               ret = omapvid_apply_changes(vout);
-               if (ret)
-                       printk(KERN_ERR VOUT_NAME "failed to change mode\n");
-       } else {
+       vout->first_int = 0;
+       if (list_empty(&vout->dma_queue))
+               goto vout_isr_err;
 
-               if (vout->first_int) {
-                       vout->first_int = 0;
-                       goto vout_isr_err;
-               }
-               if (irqstatus & DISPC_IRQ_EVSYNC_ODD)
-                       fid = 1;
-               else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN)
-                       fid = 0;
-               else
-                       goto vout_isr_err;
+       vout->next_frm = list_entry(vout->dma_queue.next,
+                       struct videobuf_buffer, queue);
+       list_del(&vout->next_frm->queue);
 
-               vout->field_id ^= 1;
-               if (fid != vout->field_id) {
-                       if (0 == fid)
-                               vout->field_id = fid;
+       vout->next_frm->state = VIDEOBUF_ACTIVE;
 
-                       goto vout_isr_err;
-               }
-               if (0 == fid) {
-                       if (vout->cur_frm == vout->next_frm)
-                               goto vout_isr_err;
-
-                       vout->cur_frm->ts = timevalue;
-                       vout->cur_frm->state = VIDEOBUF_DONE;
-                       wake_up_interruptible(&vout->cur_frm->done);
-                       vout->cur_frm = vout->next_frm;
-               } else if (1 == fid) {
-                       if (list_empty(&vout->dma_queue) ||
-                                       (vout->cur_frm != vout->next_frm))
-                               goto vout_isr_err;
-
-                       vout->next_frm = list_entry(vout->dma_queue.next,
-                                       struct videobuf_buffer, queue);
-                       list_del(&vout->next_frm->queue);
-
-                       vout->next_frm->state = VIDEOBUF_ACTIVE;
-                       addr = (unsigned long)
-                               vout->queued_buf_addr[vout->next_frm->i] +
-                               vout->cropped_offset;
-                       /* First save the configuration in ovelray structure */
-                       ret = omapvid_init(vout, addr);
-                       if (ret)
-                               printk(KERN_ERR VOUT_NAME
-                                               "failed to set overlay info\n");
-                       /* Enable the pipeline and set the Go bit */
-                       ret = omapvid_apply_changes(vout);
-                       if (ret)
-                               printk(KERN_ERR VOUT_NAME
-                                               "failed to change mode\n");
-               }
+       addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+               + vout->cropped_offset;
 
-       }
+       /* First save the configuration in ovelray structure */
+       ret = omapvid_init(vout, addr);
+       if (ret)
+               printk(KERN_ERR VOUT_NAME
+                       "failed to set overlay info\n");
+       /* Enable the pipeline and set the Go bit */
+       ret = omapvid_apply_changes(vout);
+       if (ret)
+               printk(KERN_ERR VOUT_NAME "failed to change mode\n");
 
 vout_isr_err:
        spin_unlock(&vout->vbq_lock);
 }
 
-
 /* Video buffer call backs */
 
 /*
@@ -664,10 +665,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        u32 phy_addr = 0, virt_addr = 0;
        struct omap_vout_device *vout = q->priv_data;
        struct omapvideo_info *ovid = &vout->vid_info;
+       int vid_max_buf_size;
 
        if (!vout)
                return -EINVAL;
 
+       vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
+               video2_bufsize;
+
        if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
                return -EINVAL;
 
@@ -690,7 +695,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                video1_numbuffers : video2_numbuffers;
 
        /* Check the size of the buffer */
-       if (*size > vout->buffer_size) {
+       if (*size > vid_max_buf_size) {
                v4l2_err(&vout->vid_dev->v4l2_dev,
                                "buffer allocation mismatch [%u] [%u]\n",
                                *size, vout->buffer_size);
@@ -834,6 +839,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;
@@ -934,12 +948,8 @@ static int omap_vout_release(struct file *file)
        /* Disable all the overlay managers connected with this interface */
        for (i = 0; i < ovid->num_overlays; i++) {
                struct omap_overlay *ovl = ovid->overlays[i];
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ovl->set_overlay_info(ovl, &info);
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
        /* Turn off the pipeline */
        ret = omapvid_apply_changes(vout);
@@ -1165,12 +1175,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 +1209,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;
@@ -1654,7 +1669,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
                if (ovl->manager && ovl->manager->device) {
                        struct omap_overlay_info info;
                        ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 1;
                        info.paddr = addr;
                        if (ovl->set_overlay_info(ovl, &info)) {
                                ret = -EINVAL;
@@ -1673,6 +1687,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        if (ret)
                v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n");
 
+       for (j = 0; j < ovid->num_overlays; j++) {
+               struct omap_overlay *ovl = ovid->overlays[j];
+
+               if (ovl->manager && ovl->manager->device) {
+                       ret = ovl->enable(ovl);
+                       if (ret)
+                               goto streamon_err1;
+               }
+       }
+
        ret = 0;
 
 streamon_err1:
@@ -1702,16 +1726,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
        for (j = 0; j < ovid->num_overlays; j++) {
                struct omap_overlay *ovl = ovid->overlays[j];
 
-               if (ovl->manager && ovl->manager->device) {
-                       struct omap_overlay_info info;
-
-                       ovl->get_overlay_info(ovl, &info);
-                       info.enabled = 0;
-                       ret = ovl->set_overlay_info(ovl, &info);
-                       if (ret)
-                               v4l2_err(&vout->vid_dev->v4l2_dev,
-                               "failed to update overlay info in streamoff\n");
-               }
+               if (ovl->manager && ovl->manager->device)
+                       ovl->disable(ovl);
        }
 
        /* Turn of the pipeline */
@@ -1788,7 +1804,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;
        }
@@ -1820,7 +1838,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 +1873,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 +2172,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;
        }