#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
-void *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc(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->vmalloc)
- return q->int_ops->vmalloc(buf);
- else
- return NULL;
+ if (q->int_ops->vaddr)
+ return q->int_ops->vaddr(buf);
+ return NULL;
}
-EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vaddr);
/* --------------------------------------------------------------------- */
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:
static int __videobuf_mmap_free(struct videobuf_queue *q)
{
int i;
- int rc;
if (!q)
return 0;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- rc = CALL(q, mmap_free, q);
-
- q->is_mmapped = 0;
-
- if (rc < 0)
- return rc;
+ for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ if (q->bufs[i] && q->bufs[i]->map)
+ return -EBUSY;
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
q->bufs[i] = NULL;
}
- return rc;
+ return 0;
}
int videobuf_mmap_free(struct videobuf_queue *q)
"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) {
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);
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;
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)
}
/* 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;
}
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;
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;
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);
- q->is_mmapped = 1;
+ 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);