]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/media/video/au0828/au0828-video.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / media / video / au0828 / au0828-video.c
index 162fd5f9d4482538244885a92c78820b68a0f71c..9c475c600fc9c9a0d8a5f7a568dae7a88579ee4d 100644 (file)
@@ -122,6 +122,7 @@ static void au0828_irq_callback(struct urb *urb)
 {
        struct au0828_dmaqueue  *dma_q = urb->context;
        struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+       unsigned long flags = 0;
        int rc, i;
 
        switch (urb->status) {
@@ -139,9 +140,9 @@ static void au0828_irq_callback(struct urb *urb)
        }
 
        /* Copy data from URB */
-       spin_lock(&dev->slock);
+       spin_lock_irqsave(&dev->slock, flags);
        rc = dev->isoc_ctl.isoc_copy(dev, urb);
-       spin_unlock(&dev->slock);
+       spin_unlock_irqrestore(&dev->slock, flags);
 
        /* Reset urb buffers */
        for (i = 0; i < urb->number_of_packets; i++) {
@@ -576,7 +577,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                        p += 4;
                        au0828_isocdbg("Video frame %s\n",
                                       (fbyte & 0x40) ? "odd" : "even");
-                       if (!(fbyte & 0x40)) {
+                       if (fbyte & 0x40) {
                                /* VBI */
                                if (vbi_buf != NULL)
                                        vbi_buffer_filled(dev,
@@ -597,6 +598,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
                                        outp = NULL;
                                else
                                        outp = videobuf_to_vmalloc(&buf->vb);
+
+                               /* As long as isoc traffic is arriving, keep
+                                  resetting the timer */
+                               if (dev->vid_timeout_running)
+                                       mod_timer(&dev->vid_timeout,
+                                                 jiffies + (HZ / 10));
+                               if (dev->vbi_timeout_running)
+                                       mod_timer(&dev->vbi_timeout,
+                                                 jiffies + (HZ / 10));
                        }
 
                        if (buf != NULL) {
@@ -907,6 +917,57 @@ static int get_ressource(struct au0828_fh *fh)
        }
 }
 
+/* This function ensures that video frames continue to be delivered even if
+   the ITU-656 input isn't receiving any data (thereby preventing applications
+   such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+       struct au0828_dev *dev = (struct au0828_dev *) data;
+       struct au0828_dmaqueue *dma_q = &dev->vidq;
+       struct au0828_buffer *buf;
+       unsigned char *vid_data;
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       buf = dev->isoc_ctl.buf;
+       if (buf != NULL) {
+               vid_data = videobuf_to_vmalloc(&buf->vb);
+               memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+               buffer_filled(dev, dma_q, buf);
+       }
+       get_next_buf(dma_q, &buf);
+
+       if (dev->vid_timeout_running == 1)
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+       struct au0828_dev *dev = (struct au0828_dev *) data;
+       struct au0828_dmaqueue *dma_q = &dev->vbiq;
+       struct au0828_buffer *buf;
+       unsigned char *vbi_data;
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&dev->slock, flags);
+
+       buf = dev->isoc_ctl.vbi_buf;
+       if (buf != NULL) {
+               vbi_data = videobuf_to_vmalloc(&buf->vb);
+               memset(vbi_data, 0x00, buf->vb.size);
+               vbi_buffer_filled(dev, dma_q, buf);
+       }
+       vbi_get_next_buf(dma_q, &buf);
+
+       if (dev->vbi_timeout_running == 1)
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
 static int au0828_v4l2_open(struct file *filp)
 {
        int ret = 0;
@@ -976,7 +1037,6 @@ static int au0828_v4l2_open(struct file *filp)
                                    V4L2_FIELD_SEQ_TB,
                                    sizeof(struct au0828_buffer), fh, NULL);
 
-
        return ret;
 }
 
@@ -987,11 +1047,19 @@ static int au0828_v4l2_close(struct file *filp)
        struct au0828_dev *dev = fh->dev;
 
        if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+               /* Cancel timeout thread in case they didn't call streamoff */
+               dev->vid_timeout_running = 0;
+               del_timer_sync(&dev->vid_timeout);
+
                videobuf_stop(&fh->vb_vidq);
                res_free(fh, AU0828_RESOURCE_VIDEO);
        }
 
        if (res_check(fh, AU0828_RESOURCE_VBI)) {
+               /* Cancel timeout thread in case they didn't call streamoff */
+               dev->vbi_timeout_running = 0;
+               del_timer_sync(&dev->vbi_timeout);
+
                videobuf_stop(&fh->vb_vbiq);
                res_free(fh, AU0828_RESOURCE_VBI);
        }
@@ -1048,6 +1116,13 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
                if (!res_get(fh, AU0828_RESOURCE_VBI))
                        return -EBUSY;
 
+               if (dev->vbi_timeout_running == 0) {
+                       /* Handle case where caller tries to read without
+                          calling streamon first */
+                       dev->vbi_timeout_running = 1;
+                       mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+               }
+
                return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
                                            filp->f_flags & O_NONBLOCK);
        }
@@ -1577,10 +1652,15 @@ static int vidioc_streamon(struct file *file, void *priv,
                v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
        }
 
-       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                rc = videobuf_streamon(&fh->vb_vidq);
-       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               dev->vid_timeout_running = 1;
+               mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                rc = videobuf_streamon(&fh->vb_vbiq);
+               dev->vbi_timeout_running = 1;
+               mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+       }
 
        return rc;
 }
@@ -1607,6 +1687,9 @@ static int vidioc_streamoff(struct file *file, void *priv,
                fh, type, fh->resources, dev->resources);
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev->vid_timeout_running = 0;
+               del_timer_sync(&dev->vid_timeout);
+
                v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
                rc = au0828_stream_interrupt(dev);
                if (rc != 0)
@@ -1621,6 +1704,9 @@ static int vidioc_streamoff(struct file *file, void *priv,
                videobuf_streamoff(&fh->vb_vidq);
                res_free(fh, AU0828_RESOURCE_VIDEO);
        } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               dev->vbi_timeout_running = 0;
+               del_timer_sync(&dev->vbi_timeout);
+
                videobuf_streamoff(&fh->vb_vbiq);
                res_free(fh, AU0828_RESOURCE_VBI);
        }
@@ -1672,7 +1758,12 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_reqbufs(&fh->vb_vidq, rb);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vidq, rb);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
+
+       return rc;
 }
 
 static int vidioc_querybuf(struct file *file, void *priv,
@@ -1686,7 +1777,12 @@ static int vidioc_querybuf(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       return videobuf_querybuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_querybuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1699,7 +1795,12 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
        if (rc < 0)
                return rc;
 
-       return videobuf_qbuf(&fh->vb_vidq, b);
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vidq, b);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_qbuf(&fh->vb_vbiq, b);
+
+       return rc;
 }
 
 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1720,17 +1821,13 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
                dev->greenscreen_detected = 0;
        }
 
-       return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
-}
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
-       struct au0828_fh *fh = priv;
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+       else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+               rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
 
-       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+       return rc;
 }
-#endif
 
 static struct v4l2_file_operations au0828_v4l_fops = {
        .owner      = THIS_MODULE,
@@ -1775,9 +1872,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_s_register          = vidioc_s_register,
 #endif
        .vidioc_g_chip_ident        = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf                = vidiocgmbuf,
-#endif
 };
 
 static const struct video_device au0828_video_template = {
@@ -1840,6 +1934,14 @@ int au0828_analog_register(struct au0828_dev *dev,
        INIT_LIST_HEAD(&dev->vbiq.active);
        INIT_LIST_HEAD(&dev->vbiq.queued);
 
+       dev->vid_timeout.function = au0828_vid_buffer_timeout;
+       dev->vid_timeout.data = (unsigned long) dev;
+       init_timer(&dev->vid_timeout);
+
+       dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+       dev->vbi_timeout.data = (unsigned long) dev;
+       init_timer(&dev->vbi_timeout);
+
        dev->width = NTSC_STD_W;
        dev->height = NTSC_STD_H;
        dev->field_size = dev->width * dev->height;