]> err.no Git - linux-2.6/blobdiff - drivers/media/video/ivtv/ivtv-fileops.c
Merge branch 'for-2.6.26' of master.kernel.org:/pub/scm/linux/kernel/git/jwboyer...
[linux-2.6] / drivers / media / video / ivtv / ivtv-fileops.c
index a200a8a95a2dc2ee125e6b32a94ab69b96727973..2b74b0ab147788c7942d5af34dfe1beeb954f904 100644 (file)
@@ -219,7 +219,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
                        /* Process pending program info updates and pending VBI data */
                        ivtv_update_pgm_info(itv);
 
-                       if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
+                       if (time_after(jiffies,
+                                      itv->dualwatch_jiffies +
+                                      msecs_to_jiffies(1000))) {
                                itv->dualwatch_jiffies = jiffies;
                                ivtv_dualwatch(itv);
                        }
@@ -542,6 +544,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        struct ivtv_open_id *id = filp->private_data;
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
+       struct yuv_playback_info *yi = &itv->yuv_info;
        struct ivtv_buffer *buf;
        struct ivtv_queue q;
        int bytes_written = 0;
@@ -580,6 +583,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
        set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 
 retry:
+       /* If possible, just DMA the entire frame - Check the data transfer size
+       since we may get here before the stream has been fully set-up */
+       if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
+               while (count >= itv->dma_data_req_size) {
+                       if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+                               bytes_written += itv->dma_data_req_size;
+                               user_buf += itv->dma_data_req_size;
+                               count -= itv->dma_data_req_size;
+                       } else {
+                               break;
+                       }
+               }
+               if (count == 0) {
+                       IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+                       return bytes_written;
+               }
+       }
+
        for (;;) {
                /* Gather buffers */
                while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
@@ -604,9 +625,16 @@ retry:
 
        /* copy user data into buffers */
        while ((buf = ivtv_dequeue(s, &q))) {
-               /* Make sure we really got all the user data */
-               rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+               /* yuv is a pain. Don't copy more data than needed for a single
+                  frame, otherwise we lose sync with the incoming stream */
+               if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+                   yi->stream_size + count > itv->dma_data_req_size)
+                       rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
+                               itv->dma_data_req_size - yi->stream_size);
+               else
+                       rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
 
+               /* Make sure we really got all the user data */
                if (rc < 0) {
                        ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
                        return rc;
@@ -615,6 +643,16 @@ retry:
                count -= rc;
                bytes_written += rc;
 
+               if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+                       yi->stream_size += rc;
+                       /* If we have a complete yuv frame, break loop now */
+                       if (yi->stream_size == itv->dma_data_req_size) {
+                               ivtv_enqueue(s, buf, &s->q_full);
+                               yi->stream_size = 0;
+                               break;
+                       }
+               }
+
                if (buf->bytesused != s->buf_size) {
                        /* incomplete, leave in q_io for next time */
                        ivtv_enqueue(s, buf, &s->q_io);
@@ -642,6 +680,9 @@ retry:
                if (s->q_full.length >= itv->dma_data_req_size) {
                        int got_sig;
 
+                       if (mode == OUT_YUV)
+                               ivtv_yuv_setup_stream_frame(itv);
+
                        prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
                        while (!(got_sig = signal_pending(current)) &&
                                        test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
@@ -714,8 +755,10 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        IVTV_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
 
-       if (eof || s->q_full.length)
+       if (s->q_full.length || s->q_io.length)
                return POLLIN | POLLRDNORM;
+       if (eof)
+               return POLLHUP;
        return 0;
 }
 
@@ -922,10 +965,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
        }
 
        /* YUV or MPG Decoding Mode? */
-       if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+       if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
                clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-       else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+       } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
                set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+               /* For yuv, we need to know the dma size before we start */
+               itv->dma_data_req_size =
+                               1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+               itv->yuv_info.stream_size = 0;
+       }
        return 0;
 }