]> err.no Git - linux-2.6/blobdiff - drivers/media/video/vivi.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / media / video / vivi.c
index 0346d1af3e62b9661fa269b7f38e5223dde61a4e..1db067c028157609c895b0124e72143acd94c8b2 100644 (file)
@@ -163,6 +163,7 @@ struct vivi_dev {
        struct list_head           vivi_devlist;
 
        struct mutex               lock;
+       spinlock_t                 slock;
 
        int                        users;
 
@@ -172,7 +173,8 @@ struct vivi_dev {
        struct vivi_dmaqueue       vidq;
 
        /* Several counters */
-       int                        h, m, s, us, jiffies;
+       int                        h, m, s, ms;
+       unsigned long              jiffies;
        char                       timestr[13];
 
        int                        mv_count;    /* Controls bars movement */
@@ -347,10 +349,10 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 
        /* Updates stream time */
 
-       dev->us += jiffies_to_usecs(jiffies-dev->jiffies);
+       dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
        dev->jiffies = jiffies;
-       if (dev->us >= 1000000) {
-               dev->us -= 1000000;
+       if (dev->ms >= 1000) {
+               dev->ms -= 1000;
                dev->s++;
                if (dev->s >= 60) {
                        dev->s -= 60;
@@ -364,7 +366,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                }
        }
        sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-                       dev->h, dev->m, dev->s,  (dev->us + 500) / 1000);
+                       dev->h, dev->m, dev->s, dev->ms);
 
        dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
                        dev->timestr, (unsigned long)tmpbuf, pos);
@@ -388,6 +390,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 
        int bc;
 
+       spin_lock(&dev->slock);
        /* Announces videobuf that all went ok */
        for (bc = 0;; bc++) {
                if (list_empty(&dma_q->active)) {
@@ -401,6 +404,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
                /* Nobody is waiting something to be done, just return */
                if (!waitqueue_active(&buf->vb.done)) {
                        mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+                       spin_unlock(&dev->slock);
                        return;
                }
 
@@ -419,50 +423,60 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
        if (bc != 1)
                dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
                        __FUNCTION__, bc);
+       spin_unlock(&dev->slock);
 }
 
+#define frames_to_ms(frames)                                   \
+       ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
 static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
        struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
-       int timeout;
+       int timeout, running_time;
        DECLARE_WAITQUEUE(wait, current);
 
        dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
                (unsigned long)dma_q);
 
        add_wait_queue(&dma_q->wq, &wait);
-       if (!kthread_should_stop()) {
-               dma_q->frame++;
-
-               /* Calculate time to wake up */
-               timeout = dma_q->ini_jiffies+
-                         msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR * 1000)
-                                          / WAKE_DENOMINATOR) - jiffies;
-
-               if (timeout <= 0) {
-                       int old = dma_q->frame;
-                       dma_q->frame = (jiffies_to_msecs(jiffies -
-                                       dma_q->ini_jiffies) *
-                                       WAKE_DENOMINATOR) /
-                                       (WAKE_NUMERATOR * 1000) + 1;
-
-                       timeout = dma_q->ini_jiffies+
-                               msecs_to_jiffies((dma_q->frame *
-                                                 WAKE_NUMERATOR * 1000)
-                                                 / WAKE_DENOMINATOR) - jiffies;
-
-                       dprintk(dev, 1, "underrun, losed %d frames. "
-                                  "Now, frame is %d. Waking on %d jiffies\n",
-                                  dma_q->frame-old, dma_q->frame, timeout);
-               } else
-                       dprintk(dev, 1, "will sleep for %i jiffies\n",
-                               timeout);
-
-               vivi_thread_tick(dma_q);
-
-               schedule_timeout_interruptible(timeout);
-       }
+       if (kthread_should_stop())
+               goto stop_task;
+
+       running_time = jiffies - dma_q->ini_jiffies;
+       dma_q->frame++;
+
+       /* Calculate time to wake up */
+       timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
+
+       if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
+               int old = dma_q->frame;
+               int nframes;
+
+               dma_q->frame = (jiffies_to_msecs(running_time) /
+                              frames_to_ms(1)) + 1;
+
+               timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
+                         - running_time;
+
+               if (unlikely (timeout <= 0))
+                       timeout = 1;
 
+               nframes = (dma_q->frame > old)?
+                                 dma_q->frame - old : old - dma_q->frame;
+
+               dprintk(dev, 1, "%ld: %s %d frames. "
+                       "Current frame is %d. Will sleep for %d jiffies\n",
+                       jiffies,
+                       (dma_q->frame > old)? "Underrun, losed" : "Overrun of",
+                       nframes, dma_q->frame, timeout);
+       } else
+               dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
+
+       vivi_thread_tick(dma_q);
+
+       schedule_timeout_interruptible(timeout);
+
+stop_task:
        remove_wait_queue(&dma_q->wq, &wait);
        try_to_freeze();
 }
@@ -591,6 +605,8 @@ static void vivi_vid_timeout(unsigned long data)
        struct vivi_dmaqueue *vidq = &dev->vidq;
        struct vivi_buffer   *buf;
 
+       spin_lock(&dev->slock);
+
        while (!list_empty(&vidq->active)) {
                buf = list_entry(vidq->active.next,
                                 struct vivi_buffer, vb.queue);
@@ -599,8 +615,9 @@ static void vivi_vid_timeout(unsigned long data)
                wake_up(&buf->vb.done);
                printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
        }
-
        restart_video_queue(vidq);
+
+       spin_unlock(&dev->slock);
 }
 
 /* ------------------------------------------------------------------
@@ -1057,14 +1074,14 @@ found:
        dev->h = 0;
        dev->m = 0;
        dev->s = 0;
-       dev->us = 0;
+       dev->ms = 0;
        dev->mv_count = 0;
        dev->jiffies = jiffies;
        sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
-                       dev->h, dev->m, dev->s, (dev->us + 500) / 1000);
+                       dev->h, dev->m, dev->s, dev->ms);
 
        videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
-                       NULL, NULL, fh->type, V4L2_FIELD_INTERLACED,
+                       NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
                        sizeof(struct vivi_buffer), fh);
 
        return 0;
@@ -1224,6 +1241,7 @@ static int __init vivi_init(void)
 
                /* initialize locks */
                mutex_init(&dev->lock);
+               spin_lock_init(&dev->slock);
 
                dev->vidq.timeout.function = vivi_vid_timeout;
                dev->vidq.timeout.data     = (unsigned long)dev;