Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / drivers / media / video / videobuf-core.c
index 26241a8..7d33784 100644 (file)
@@ -105,15 +105,14 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
 }
 EXPORT_SYMBOL_GPL(videobuf_iolock);
 
-void *videobuf_queue_to_vmalloc(struct videobuf_queue *q,
-                               struct videobuf_buffer *buf)
+void *videobuf_queue_to_vaddr(struct videobuf_queue *q,
+                             struct videobuf_buffer *buf)
 {
        if (q->int_ops->vaddr)
                return q->int_ops->vaddr(buf);
-       else
-               return NULL;
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr);
 
 /* --------------------------------------------------------------------- */
 
@@ -286,8 +285,10 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
        case VIDEOBUF_ACTIVE:
                b->flags |= V4L2_BUF_FLAG_QUEUED;
                break;
-       case VIDEOBUF_DONE:
        case VIDEOBUF_ERROR:
+               b->flags |= V4L2_BUF_FLAG_ERROR;
+               /* fall through */
+       case VIDEOBUF_DONE:
                b->flags |= V4L2_BUF_FLAG_DONE;
                break;
        case VIDEOBUF_NEEDS_INIT:
@@ -545,6 +546,13 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
                                   "but buffer addr is zero!\n");
                        goto done;
                }
+               if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
+                   || q->type == V4L2_BUF_TYPE_VBI_OUTPUT
+                   || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+                       buf->size = b->bytesused;
+                       buf->field = b->field;
+                       buf->ts = b->timestamp;
+               }
                break;
        case V4L2_MEMORY_USERPTR:
                if (b->length < buf->bsize) {
@@ -664,6 +672,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
 
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
+       memset(b, 0, sizeof(*b));
        mutex_lock(&q->vb_lock);
 
        retval = stream_next_buffer(q, &buf, nonblocking);
@@ -675,23 +684,20 @@ int videobuf_dqbuf(struct videobuf_queue *q,
        switch (buf->state) {
        case VIDEOBUF_ERROR:
                dprintk(1, "dqbuf: state is error\n");
-               retval = -EIO;
-               CALL(q, sync, q, buf);
-               buf->state = VIDEOBUF_IDLE;
                break;
        case VIDEOBUF_DONE:
                dprintk(1, "dqbuf: state is done\n");
-               CALL(q, sync, q, buf);
-               buf->state = VIDEOBUF_IDLE;
                break;
        default:
                dprintk(1, "dqbuf: state invalid\n");
                retval = -EINVAL;
                goto done;
        }
-       list_del(&buf->stream);
-       memset(b, 0, sizeof(*b));
+       CALL(q, sync, q, buf);
        videobuf_status(q, b, buf, q->type);
+       list_del(&buf->stream);
+       buf->state = VIDEOBUF_IDLE;
+       b->flags &= ~V4L2_BUF_FLAG_DONE;
 done:
        mutex_unlock(&q->vb_lock);
        return retval;
@@ -794,6 +800,49 @@ done:
        return retval;
 }
 
+static int __videobuf_copy_to_user(struct videobuf_queue *q,
+                                  struct videobuf_buffer *buf,
+                                  char __user *data, size_t count,
+                                  int nonblocking)
+{
+       void *vaddr = CALL(q, vaddr, buf);
+
+       /* copy to userspace */
+       if (count > buf->size - q->read_off)
+               count = buf->size - q->read_off;
+
+       if (copy_to_user(data, vaddr + q->read_off, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static int __videobuf_copy_stream(struct videobuf_queue *q,
+                                 struct videobuf_buffer *buf,
+                                 char __user *data, size_t count, size_t pos,
+                                 int vbihack, int nonblocking)
+{
+       unsigned int *fc = CALL(q, vaddr, buf);
+
+       if (vbihack) {
+               /* dirty, undocumented hack -- pass the frame counter
+                       * within the last four bytes of each vbi data block.
+                       * We need that one to maintain backward compatibility
+                       * to all vbi decoding software out there ... */
+               fc += (buf->size >> 2) - 1;
+               *fc = buf->field_count >> 1;
+               dprintk(1, "vbihack: %d\n", *fc);
+       }
+
+       /* copy stuff using the common method */
+       count = __videobuf_copy_to_user(q, buf, data, count, nonblocking);
+
+       if ((count == -EFAULT) && (pos == 0))
+               return -EFAULT;
+
+       return count;
+}
+
 ssize_t videobuf_read_one(struct videobuf_queue *q,
                          char __user *data, size_t count, loff_t *ppos,
                          int nonblocking)
@@ -862,7 +911,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
        }
 
        /* Copy to userspace */
-       retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
+       retval = __videobuf_copy_to_user(q, q->read_buf, data, count, nonblocking);
        if (retval < 0)
                goto done;
 
@@ -1004,7 +1053,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
                }
 
                if (q->read_buf->state == VIDEOBUF_DONE) {
-                       rc = CALL(q, copy_stream, q, data + retval, count,
+                       rc = __videobuf_copy_stream(q, q->read_buf, data + retval, count,
                                        retval, vbihack, nonblocking);
                        if (rc < 0) {
                                retval = rc;
@@ -1071,8 +1120,18 @@ unsigned int videobuf_poll_stream(struct file *file,
        if (0 == rc) {
                poll_wait(file, &buf->done, wait);
                if (buf->state == VIDEOBUF_DONE ||
-                   buf->state == VIDEOBUF_ERROR)
-                       rc = POLLIN|POLLRDNORM;
+                   buf->state == VIDEOBUF_ERROR) {
+                       switch (q->type) {
+                       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+                       case V4L2_BUF_TYPE_VBI_OUTPUT:
+                       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+                               rc = POLLOUT | POLLWRNORM;
+                               break;
+                       default:
+                               rc = POLLIN | POLLRDNORM;
+                               break;
+                       }
+               }
        }
        mutex_unlock(&q->vb_lock);
        return rc;
@@ -1081,15 +1140,29 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 
 int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
 {
-       int retval;
+       int rc = -EINVAL;
+       int i;
 
        MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
+       if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) {
+               dprintk(1, "mmap appl bug: PROT_WRITE and MAP_SHARED are required\n");
+               return -EINVAL;
+       }
+
        mutex_lock(&q->vb_lock);
-       retval = CALL(q, mmap_mapper, q, vma);
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               struct videobuf_buffer *buf = q->bufs[i];
+
+               if (buf && buf->memory == V4L2_MEMORY_MMAP &&
+                               buf->boff == (vma->vm_pgoff << PAGE_SHIFT)) {
+                       rc = CALL(q, mmap_mapper, q, buf, vma);
+                       break;
+               }
+       }
        mutex_unlock(&q->vb_lock);
 
-       return retval;
+       return rc;
 }
 EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);