#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-dma-contig.h>
#include "solo6x10.h"
#include "tw28.h"
}
static void solo_fillbuf(struct solo_dev *solo_dev,
- struct videobuf_buffer *vb)
+ struct vb2_buffer *vb)
{
dma_addr_t vbuf;
unsigned int fdma_addr;
int error = -1;
int i;
- vbuf = videobuf_to_dma_contig(vb);
+ vbuf = vb2_dma_contig_plane_dma_addr(vb, 0);
if (!vbuf)
goto finish_buf;
if (erase_off(solo_dev)) {
- void *p = videobuf_queue_to_vaddr(&solo_dev->vidq, vb);
+ void *p = vb2_plane_vaddr(vb, 0);
int image_size = solo_image_size(solo_dev);
for (i = 0; i < image_size; i += 2) {
((u8 *)p)[i] = 0x80;
}
finish_buf:
- if (error) {
- vb->state = VIDEOBUF_ERROR;
- } else {
- vb->state = VIDEOBUF_DONE;
- vb->field_count++;
+ if (!error) {
+ vb2_set_plane_payload(vb, 0,
+ solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
+ vb->v4l2_buf.sequence++;
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
}
- wake_up(&vb->done);
+ vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
}
static void solo_thread_try(struct solo_dev *solo_dev)
{
- struct videobuf_buffer *vb;
+ struct solo_vb2_buf *vb;
/* Only "break" from this loop if slock is held, otherwise
* just return. */
if (list_empty(&solo_dev->vidq_active))
break;
- vb = list_first_entry(&solo_dev->vidq_active, struct videobuf_buffer,
- queue);
-
- if (!waitqueue_active(&vb->done))
- break;
+ vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
+ list);
solo_dev->old_write = cur_write;
- list_del(&vb->queue);
- vb->state = VIDEOBUF_ACTIVE;
+ list_del(&vb->list);
spin_unlock(&solo_dev->slock);
- solo_fillbuf(solo_dev, vb);
+ solo_fillbuf(solo_dev, &vb->vb);
}
assert_spin_locked(&solo_dev->slock);
{
int ret = 0;
- if (atomic_inc_return(&solo_dev->disp_users) == 1)
- solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
-
solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
if (IS_ERR(solo_dev->kthread)) {
ret = PTR_ERR(solo_dev->kthread);
solo_dev->kthread = NULL;
+ return ret;
}
+ solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
return ret;
}
if (!solo_dev->kthread)
return;
+ solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
kthread_stop(solo_dev->kthread);
solo_dev->kthread = NULL;
-
- if (atomic_dec_return(&solo_dev->disp_users) == 0)
- solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
}
-static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct solo_dev *solo_dev = vq->priv_data;
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
- *size = solo_image_size(solo_dev);
+ sizes[0] = solo_image_size(solo_dev);
+ alloc_ctxs[0] = solo_dev->alloc_ctx;
+ *num_planes = 1;
- if (*count < MIN_VID_BUFFERS)
- *count = MIN_VID_BUFFERS;
+ if (*num_buffers < MIN_VID_BUFFERS)
+ *num_buffers = MIN_VID_BUFFERS;
return 0;
}
-static int solo_buf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct solo_dev *solo_dev = vq->priv_data;
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
- vb->size = solo_image_size(solo_dev);
- if (vb->baddr != 0 && vb->bsize < vb->size)
- return -EINVAL;
+ return solo_start_thread(solo_dev);
+}
- /* XXX: These properties only change when queue is idle */
- vb->width = solo_dev->video_hsize;
- vb->height = solo_vlines(solo_dev);
- vb->bytesperline = solo_bytesperline(solo_dev);
- vb->field = field;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- int rc = videobuf_iolock(vq, vb, NULL);
- if (rc < 0) {
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return rc;
- }
- }
- vb->state = VIDEOBUF_PREPARED;
+static int solo_stop_streaming(struct vb2_queue *q)
+{
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+ solo_stop_thread(solo_dev);
+ INIT_LIST_HEAD(&solo_dev->vidq_active);
return 0;
}
-static void solo_buf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
+static void solo_buf_queue(struct vb2_buffer *vb)
{
- struct solo_dev *solo_dev = vq->priv_data;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
+ struct solo_vb2_buf *solo_vb =
+ container_of(vb, struct solo_vb2_buf, vb);
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &solo_dev->vidq_active);
+ spin_lock(&solo_dev->slock);
+ list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
+ spin_unlock(&solo_dev->slock);
wake_up_interruptible(&solo_dev->disp_thread_wait);
}
-static void solo_buf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static const struct videobuf_queue_ops solo_video_qops = {
- .buf_setup = solo_buf_setup,
- .buf_prepare = solo_buf_prepare,
+static const struct vb2_ops solo_video_qops = {
+ .queue_setup = solo_queue_setup,
.buf_queue = solo_buf_queue,
- .buf_release = solo_buf_release,
+ .start_streaming = solo_start_streaming,
+ .stop_streaming = solo_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
-static unsigned int solo_v4l2_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
- unsigned long req_events = poll_requested_events(wait);
- unsigned res = v4l2_ctrl_poll(file, wait);
-
- if (!(req_events & (POLLIN | POLLRDNORM)))
- return res;
- return res | videobuf_poll_stream(file, &solo_dev->vidq, wait);
-}
-
-static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_mmap_mapper(&solo_dev->vidq, vma);
-}
-
-static ssize_t solo_v4l2_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_read_stream(&solo_dev->vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static int solo_v4l2_release(struct file *file)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- solo_stop_thread(solo_dev);
- videobuf_stop(&solo_dev->vidq);
- videobuf_mmap_free(&solo_dev->vidq);
- return v4l2_fh_release(file);
-}
-
static int solo_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
{
struct solo_dev *solo_dev = video_drvdata(file);
- if (videobuf_queue_is_busy(&solo_dev->vidq))
+ if (vb2_is_busy(&solo_dev->vidq))
return -EBUSY;
/* For right now, if it doesn't match our running config,
return 0;
}
-static int solo_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_reqbufs(&solo_dev->vidq, req);
-}
-
-static int solo_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_querybuf(&solo_dev->vidq, buf);
-}
-
-static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_qbuf(&solo_dev->vidq, buf);
-}
-
-static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- return videobuf_dqbuf(&solo_dev->vidq, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
- int ret;
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- ret = solo_start_thread(solo_dev);
- if (ret)
- return ret;
-
- return videobuf_streamon(&solo_dev->vidq);
-}
-
-static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return videobuf_streamoff(&solo_dev->vidq);
-}
-
static int solo_s_std(struct file *file, void *priv, v4l2_std_id i)
{
return 0;
static const struct v4l2_file_operations solo_v4l2_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
- .release = solo_v4l2_release,
- .read = solo_v4l2_read,
- .poll = solo_v4l2_poll,
- .mmap = solo_v4l2_mmap,
- .ioctl = video_ioctl2,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
.vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
.vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
/* Streaming I/O */
- .vidioc_reqbufs = solo_reqbufs,
- .vidioc_querybuf = solo_querybuf,
- .vidioc_qbuf = solo_qbuf,
- .vidioc_dqbuf = solo_dqbuf,
- .vidioc_streamon = solo_streamon,
- .vidioc_streamoff = solo_streamoff,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
/* Logging and events */
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
int ret;
int i;
- atomic_set(&solo_dev->disp_users, 0);
init_waitqueue_head(&solo_dev->disp_thread_wait);
+ spin_lock_init(&solo_dev->slock);
+ mutex_init(&solo_dev->lock);
+ INIT_LIST_HEAD(&solo_dev->vidq_active);
solo_dev->vfd = video_device_alloc();
if (!solo_dev->vfd)
*solo_dev->vfd = solo_v4l2_template;
solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+ solo_dev->vfd->queue = &solo_dev->vidq;
+ solo_dev->vfd->lock = &solo_dev->lock;
v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
- if (solo_dev->disp_hdl.error)
- return solo_dev->disp_hdl.error;
+ if (solo_dev->disp_hdl.error) {
+ ret = solo_dev->disp_hdl.error;
+ goto fail;
+ }
solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags);
video_set_drvdata(solo_dev->vfd, solo_dev);
- spin_lock_init(&solo_dev->slock);
- INIT_LIST_HEAD(&solo_dev->vidq_active);
-
- videobuf_queue_dma_contig_init(&solo_dev->vidq, &solo_video_qops,
- &solo_dev->pdev->dev, &solo_dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer),
- solo_dev, NULL);
+ solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ solo_dev->vidq.ops = &solo_video_qops;
+ solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
+ solo_dev->vidq.drv_priv = solo_dev;
+ solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ solo_dev->vidq.gfp_flags = __GFP_DMA32;
+ solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+ solo_dev->vidq.lock = &solo_dev->lock;
+ ret = vb2_queue_init(&solo_dev->vidq);
+ if (ret < 0)
+ goto fail;
+
+ solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
+ if (IS_ERR(solo_dev->alloc_ctx)) {
+ dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
+ return PTR_ERR(solo_dev->alloc_ctx);
+ }
/* Cycle all the channels and clear */
for (i = 0; i < solo_dev->nr_chans; i++) {
/* Do nothing */;
ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
- if (ret < 0) {
- video_device_release(solo_dev->vfd);
- solo_dev->vfd = NULL;
- return ret;
- }
+ if (ret < 0)
+ goto fail;
snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
SOLO6X10_NAME, solo_dev->vfd->num);
solo_dev->nr_chans, solo_dev->nr_ext);
return 0;
+
+fail:
+ video_device_release(solo_dev->vfd);
+ vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+ v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+ solo_dev->vfd = NULL;
+ return ret;
}
void solo_v4l2_exit(struct solo_dev *solo_dev)
return;
video_unregister_device(solo_dev->vfd);
+ vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
solo_dev->vfd = NULL;
}