|
@@ -35,6 +35,7 @@
|
|
|
#include <media/v4l2-ioctl.h>
|
|
|
#include <media/v4l2-subdev.h>
|
|
|
#include <media/v4l2-event.h>
|
|
|
+#include <media/videobuf2-vmalloc.h>
|
|
|
#include <media/saa7115.h>
|
|
|
|
|
|
#include "go7007.h"
|
|
@@ -43,66 +44,6 @@
|
|
|
#define call_all(dev, o, f, args...) \
|
|
|
v4l2_device_call_until_err(dev, 0, o, f, ##args)
|
|
|
|
|
|
-static void deactivate_buffer(struct go7007_buffer *gobuf)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- if (gobuf->state != BUF_STATE_IDLE) {
|
|
|
- list_del(&gobuf->stream);
|
|
|
- gobuf->state = BUF_STATE_IDLE;
|
|
|
- }
|
|
|
- if (gobuf->page_count > 0) {
|
|
|
- for (i = 0; i < gobuf->page_count; ++i)
|
|
|
- page_cache_release(gobuf->pages[i]);
|
|
|
- gobuf->page_count = 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void abort_queued(struct go7007 *go)
|
|
|
-{
|
|
|
- struct go7007_buffer *gobuf, *next;
|
|
|
-
|
|
|
- list_for_each_entry_safe(gobuf, next, &go->stream, stream) {
|
|
|
- deactivate_buffer(gobuf);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int go7007_streamoff(struct go7007 *go)
|
|
|
-{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- mutex_lock(&go->hw_lock);
|
|
|
- if (go->streaming) {
|
|
|
- go->streaming = 0;
|
|
|
- go7007_stream_stop(go);
|
|
|
- spin_lock_irqsave(&go->spinlock, flags);
|
|
|
- abort_queued(go);
|
|
|
- spin_unlock_irqrestore(&go->spinlock, flags);
|
|
|
- go7007_reset_encoder(go);
|
|
|
- }
|
|
|
- mutex_unlock(&go->hw_lock);
|
|
|
- v4l2_ctrl_grab(go->mpeg_video_gop_size, false);
|
|
|
- v4l2_ctrl_grab(go->mpeg_video_gop_closure, false);
|
|
|
- v4l2_ctrl_grab(go->mpeg_video_bitrate, false);
|
|
|
- v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int go7007_release(struct file *file)
|
|
|
-{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
-
|
|
|
- if (file->private_data == go->bufs_owner && go->buf_count > 0) {
|
|
|
- go7007_streamoff(go);
|
|
|
- go->in_use = 0;
|
|
|
- kfree(go->bufs);
|
|
|
- go->bufs = NULL;
|
|
|
- go->buf_count = 0;
|
|
|
- go->bufs_owner = NULL;
|
|
|
- }
|
|
|
- return v4l2_fh_release(file);
|
|
|
-}
|
|
|
-
|
|
|
static bool valid_pixelformat(u32 pixelformat)
|
|
|
{
|
|
|
switch (pixelformat) {
|
|
@@ -116,15 +57,15 @@ static bool valid_pixelformat(u32 pixelformat)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
|
|
|
+static u32 get_frame_type_flag(struct go7007_buffer *vb, int format)
|
|
|
{
|
|
|
- u8 *f = page_address(gobuf->pages[0]);
|
|
|
+ u8 *ptr = vb2_plane_vaddr(&vb->vb, 0);
|
|
|
|
|
|
switch (format) {
|
|
|
case V4L2_PIX_FMT_MJPEG:
|
|
|
return V4L2_BUF_FLAG_KEYFRAME;
|
|
|
case V4L2_PIX_FMT_MPEG4:
|
|
|
- switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) {
|
|
|
+ switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) {
|
|
|
case 0:
|
|
|
return V4L2_BUF_FLAG_KEYFRAME;
|
|
|
case 1:
|
|
@@ -136,7 +77,7 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
|
|
|
}
|
|
|
case V4L2_PIX_FMT_MPEG1:
|
|
|
case V4L2_PIX_FMT_MPEG2:
|
|
|
- switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) {
|
|
|
+ switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) {
|
|
|
case 1:
|
|
|
return V4L2_BUF_FLAG_KEYFRAME;
|
|
|
case 2:
|
|
@@ -412,7 +353,8 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|
|
strlcpy(cap->card, go->name, sizeof(cap->card));
|
|
|
strlcpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
|
|
|
|
|
|
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
|
|
|
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
|
|
|
+ V4L2_CAP_STREAMING;
|
|
|
|
|
|
if (go->board_info->num_aud_inputs)
|
|
|
cap->device_caps |= V4L2_CAP_AUDIO;
|
|
@@ -485,293 +427,125 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
|
|
{
|
|
|
struct go7007 *go = video_drvdata(file);
|
|
|
|
|
|
- if (go->streaming)
|
|
|
+ if (vb2_is_busy(&go->vidq))
|
|
|
return -EBUSY;
|
|
|
|
|
|
return set_capture_size(go, fmt, 0);
|
|
|
}
|
|
|
|
|
|
-static int vidioc_reqbufs(struct file *file, void *priv,
|
|
|
- struct v4l2_requestbuffers *req)
|
|
|
+static int go7007_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 go7007 *go = video_drvdata(file);
|
|
|
- int retval = -EBUSY;
|
|
|
- unsigned int count, i;
|
|
|
-
|
|
|
- if (go->streaming)
|
|
|
- return retval;
|
|
|
-
|
|
|
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
|
|
|
- req->memory != V4L2_MEMORY_MMAP)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- for (i = 0; i < go->buf_count; ++i)
|
|
|
- if (go->bufs[i].mapped > 0)
|
|
|
- goto unlock_and_return;
|
|
|
-
|
|
|
- set_formatting(go);
|
|
|
- mutex_lock(&go->hw_lock);
|
|
|
- if (go->in_use > 0 && go->buf_count == 0) {
|
|
|
- mutex_unlock(&go->hw_lock);
|
|
|
- goto unlock_and_return;
|
|
|
- }
|
|
|
+ sizes[0] = GO7007_BUF_SIZE;
|
|
|
+ *num_planes = 1;
|
|
|
|
|
|
- if (go->buf_count > 0)
|
|
|
- kfree(go->bufs);
|
|
|
-
|
|
|
- retval = -ENOMEM;
|
|
|
- count = req->count;
|
|
|
- if (count > 0) {
|
|
|
- if (count < 2)
|
|
|
- count = 2;
|
|
|
- if (count > 32)
|
|
|
- count = 32;
|
|
|
-
|
|
|
- go->bufs = kcalloc(count, sizeof(struct go7007_buffer),
|
|
|
- GFP_KERNEL);
|
|
|
-
|
|
|
- if (!go->bufs) {
|
|
|
- mutex_unlock(&go->hw_lock);
|
|
|
- goto unlock_and_return;
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < count; ++i) {
|
|
|
- go->bufs[i].go = go;
|
|
|
- go->bufs[i].index = i;
|
|
|
- go->bufs[i].state = BUF_STATE_IDLE;
|
|
|
- go->bufs[i].mapped = 0;
|
|
|
- }
|
|
|
-
|
|
|
- go->in_use = 1;
|
|
|
- go->bufs_owner = file->private_data;
|
|
|
- } else {
|
|
|
- go->in_use = 0;
|
|
|
- go->bufs_owner = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- go->buf_count = count;
|
|
|
- mutex_unlock(&go->hw_lock);
|
|
|
-
|
|
|
- memset(req, 0, sizeof(*req));
|
|
|
-
|
|
|
- req->count = count;
|
|
|
- req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
- req->memory = V4L2_MEMORY_MMAP;
|
|
|
+ if (*num_buffers < 2)
|
|
|
+ *num_buffers = 2;
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-unlock_and_return:
|
|
|
- return retval;
|
|
|
}
|
|
|
|
|
|
-static int vidioc_querybuf(struct file *file, void *priv,
|
|
|
- struct v4l2_buffer *buf)
|
|
|
+static void go7007_buf_queue(struct vb2_buffer *vb)
|
|
|
{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- int retval = -EINVAL;
|
|
|
- unsigned int index;
|
|
|
-
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return retval;
|
|
|
-
|
|
|
- index = buf->index;
|
|
|
-
|
|
|
- if (index >= go->buf_count)
|
|
|
- goto unlock_and_return;
|
|
|
-
|
|
|
- memset(buf, 0, sizeof(*buf));
|
|
|
- buf->index = index;
|
|
|
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
-
|
|
|
- switch (go->bufs[index].state) {
|
|
|
- case BUF_STATE_QUEUED:
|
|
|
- buf->flags = V4L2_BUF_FLAG_QUEUED;
|
|
|
- break;
|
|
|
- case BUF_STATE_DONE:
|
|
|
- buf->flags = V4L2_BUF_FLAG_DONE;
|
|
|
- break;
|
|
|
- default:
|
|
|
- buf->flags = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (go->bufs[index].mapped)
|
|
|
- buf->flags |= V4L2_BUF_FLAG_MAPPED;
|
|
|
- buf->memory = V4L2_MEMORY_MMAP;
|
|
|
- buf->m.offset = index * GO7007_BUF_SIZE;
|
|
|
- buf->length = GO7007_BUF_SIZE;
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-unlock_and_return:
|
|
|
- return retval;
|
|
|
-}
|
|
|
-
|
|
|
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
|
|
-{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- struct go7007_buffer *gobuf;
|
|
|
+ struct vb2_queue *vq = vb->vb2_queue;
|
|
|
+ struct go7007 *go = vb2_get_drv_priv(vq);
|
|
|
+ struct go7007_buffer *go7007_vb =
|
|
|
+ container_of(vb, struct go7007_buffer, vb);
|
|
|
unsigned long flags;
|
|
|
- int retval = -EINVAL;
|
|
|
- int ret;
|
|
|
-
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
|
|
|
- buf->memory != V4L2_MEMORY_MMAP)
|
|
|
- return retval;
|
|
|
-
|
|
|
- if (buf->index >= go->buf_count)
|
|
|
- goto unlock_and_return;
|
|
|
|
|
|
- gobuf = &go->bufs[buf->index];
|
|
|
- if (!gobuf->mapped)
|
|
|
- goto unlock_and_return;
|
|
|
-
|
|
|
- retval = -EBUSY;
|
|
|
- if (gobuf->state != BUF_STATE_IDLE)
|
|
|
- goto unlock_and_return;
|
|
|
-
|
|
|
- /* offset will be 0 until we really support USERPTR streaming */
|
|
|
- gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
|
|
|
- gobuf->bytesused = 0;
|
|
|
- gobuf->frame_offset = 0;
|
|
|
- gobuf->modet_active = 0;
|
|
|
- if (gobuf->offset > 0)
|
|
|
- gobuf->page_count = GO7007_BUF_PAGES + 1;
|
|
|
- else
|
|
|
- gobuf->page_count = GO7007_BUF_PAGES;
|
|
|
-
|
|
|
- retval = -ENOMEM;
|
|
|
- down_read(¤t->mm->mmap_sem);
|
|
|
- ret = get_user_pages(current, current->mm,
|
|
|
- gobuf->user_addr & PAGE_MASK, gobuf->page_count,
|
|
|
- 1, 1, gobuf->pages, NULL);
|
|
|
- up_read(¤t->mm->mmap_sem);
|
|
|
-
|
|
|
- if (ret != gobuf->page_count) {
|
|
|
- int i;
|
|
|
- for (i = 0; i < ret; ++i)
|
|
|
- page_cache_release(gobuf->pages[i]);
|
|
|
- gobuf->page_count = 0;
|
|
|
- goto unlock_and_return;
|
|
|
- }
|
|
|
-
|
|
|
- gobuf->state = BUF_STATE_QUEUED;
|
|
|
spin_lock_irqsave(&go->spinlock, flags);
|
|
|
- list_add_tail(&gobuf->stream, &go->stream);
|
|
|
+ list_add_tail(&go7007_vb->list, &go->vidq_active);
|
|
|
spin_unlock_irqrestore(&go->spinlock, flags);
|
|
|
+}
|
|
|
|
|
|
- return 0;
|
|
|
+static int go7007_buf_prepare(struct vb2_buffer *vb)
|
|
|
+{
|
|
|
+ struct go7007_buffer *go7007_vb =
|
|
|
+ container_of(vb, struct go7007_buffer, vb);
|
|
|
|
|
|
-unlock_and_return:
|
|
|
- return retval;
|
|
|
+ go7007_vb->modet_active = 0;
|
|
|
+ go7007_vb->frame_offset = 0;
|
|
|
+ vb->v4l2_planes[0].bytesused = 0;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
|
|
+static int go7007_buf_finish(struct vb2_buffer *vb)
|
|
|
{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- struct go7007_buffer *gobuf;
|
|
|
- int retval = -EINVAL;
|
|
|
- unsigned long flags;
|
|
|
- u32 frame_type_flag;
|
|
|
- DEFINE_WAIT(wait);
|
|
|
-
|
|
|
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return retval;
|
|
|
- if (buf->memory != V4L2_MEMORY_MMAP)
|
|
|
- return retval;
|
|
|
-
|
|
|
- if (list_empty(&go->stream))
|
|
|
- goto unlock_and_return;
|
|
|
- gobuf = list_entry(go->stream.next,
|
|
|
- struct go7007_buffer, stream);
|
|
|
-
|
|
|
- retval = -EAGAIN;
|
|
|
- if (gobuf->state != BUF_STATE_DONE &&
|
|
|
- !(file->f_flags & O_NONBLOCK)) {
|
|
|
- for (;;) {
|
|
|
- prepare_to_wait(&go->frame_waitq, &wait,
|
|
|
- TASK_INTERRUPTIBLE);
|
|
|
- if (gobuf->state == BUF_STATE_DONE)
|
|
|
- break;
|
|
|
- if (signal_pending(current)) {
|
|
|
- retval = -ERESTARTSYS;
|
|
|
- break;
|
|
|
- }
|
|
|
- schedule();
|
|
|
- }
|
|
|
- finish_wait(&go->frame_waitq, &wait);
|
|
|
- }
|
|
|
- if (gobuf->state != BUF_STATE_DONE)
|
|
|
- goto unlock_and_return;
|
|
|
-
|
|
|
- spin_lock_irqsave(&go->spinlock, flags);
|
|
|
- deactivate_buffer(gobuf);
|
|
|
- spin_unlock_irqrestore(&go->spinlock, flags);
|
|
|
- frame_type_flag = get_frame_type_flag(gobuf, go->format);
|
|
|
- gobuf->state = BUF_STATE_IDLE;
|
|
|
-
|
|
|
- memset(buf, 0, sizeof(*buf));
|
|
|
- buf->index = gobuf->index;
|
|
|
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
- buf->bytesused = gobuf->bytesused;
|
|
|
- buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
|
|
|
+ struct vb2_queue *vq = vb->vb2_queue;
|
|
|
+ struct go7007 *go = vb2_get_drv_priv(vq);
|
|
|
+ struct go7007_buffer *go7007_vb =
|
|
|
+ container_of(vb, struct go7007_buffer, vb);
|
|
|
+ u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format);
|
|
|
+ struct v4l2_buffer *buf = &vb->v4l2_buf;
|
|
|
+
|
|
|
+ buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME |
|
|
|
+ V4L2_BUF_FLAG_PFRAME);
|
|
|
+ buf->flags |= frame_type_flag;
|
|
|
buf->field = V4L2_FIELD_NONE;
|
|
|
- buf->timestamp = gobuf->timestamp;
|
|
|
- buf->sequence = gobuf->seq;
|
|
|
- buf->memory = V4L2_MEMORY_MMAP;
|
|
|
- buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
|
|
|
- buf->length = GO7007_BUF_SIZE;
|
|
|
- buf->reserved = gobuf->modet_active;
|
|
|
-
|
|
|
return 0;
|
|
|
-
|
|
|
-unlock_and_return:
|
|
|
- return retval;
|
|
|
}
|
|
|
|
|
|
-static int vidioc_streamon(struct file *file, void *priv,
|
|
|
- enum v4l2_buf_type type)
|
|
|
+static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
|
|
|
{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- int retval = 0;
|
|
|
-
|
|
|
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
+ struct go7007 *go = vb2_get_drv_priv(q);
|
|
|
+ int ret;
|
|
|
|
|
|
+ set_formatting(go);
|
|
|
mutex_lock(&go->hw_lock);
|
|
|
-
|
|
|
- if (!go->streaming) {
|
|
|
- go->streaming = 1;
|
|
|
- go->next_seq = 0;
|
|
|
- go->active_buf = NULL;
|
|
|
- if (go7007_start_encoder(go) < 0)
|
|
|
- retval = -EIO;
|
|
|
- else
|
|
|
- retval = 0;
|
|
|
- }
|
|
|
+ go->next_seq = 0;
|
|
|
+ go->active_buf = NULL;
|
|
|
+ q->streaming = 1;
|
|
|
+ if (go7007_start_encoder(go) < 0)
|
|
|
+ ret = -EIO;
|
|
|
+ else
|
|
|
+ ret = 0;
|
|
|
mutex_unlock(&go->hw_lock);
|
|
|
+ if (ret) {
|
|
|
+ q->streaming = 0;
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
call_all(&go->v4l2_dev, video, s_stream, 1);
|
|
|
v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
|
|
|
v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
|
|
|
v4l2_ctrl_grab(go->mpeg_video_bitrate, true);
|
|
|
v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true);
|
|
|
-
|
|
|
- return retval;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static int vidioc_streamoff(struct file *file, void *priv,
|
|
|
- enum v4l2_buf_type type)
|
|
|
+static int go7007_stop_streaming(struct vb2_queue *q)
|
|
|
{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
+ struct go7007 *go = vb2_get_drv_priv(q);
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
- return -EINVAL;
|
|
|
- go7007_streamoff(go);
|
|
|
+ q->streaming = 0;
|
|
|
+ go7007_stream_stop(go);
|
|
|
+ mutex_lock(&go->hw_lock);
|
|
|
+ go7007_reset_encoder(go);
|
|
|
+ mutex_unlock(&go->hw_lock);
|
|
|
call_all(&go->v4l2_dev, video, s_stream, 0);
|
|
|
|
|
|
+ spin_lock_irqsave(&go->spinlock, flags);
|
|
|
+ INIT_LIST_HEAD(&go->vidq_active);
|
|
|
+ spin_unlock_irqrestore(&go->spinlock, flags);
|
|
|
+ v4l2_ctrl_grab(go->mpeg_video_gop_size, false);
|
|
|
+ v4l2_ctrl_grab(go->mpeg_video_gop_closure, false);
|
|
|
+ v4l2_ctrl_grab(go->mpeg_video_bitrate, false);
|
|
|
+ v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static struct vb2_ops go7007_video_qops = {
|
|
|
+ .queue_setup = go7007_queue_setup,
|
|
|
+ .buf_queue = go7007_buf_queue,
|
|
|
+ .buf_prepare = go7007_buf_prepare,
|
|
|
+ .buf_finish = go7007_buf_finish,
|
|
|
+ .start_streaming = go7007_start_streaming,
|
|
|
+ .stop_streaming = go7007_stop_streaming,
|
|
|
+ .wait_prepare = vb2_ops_wait_prepare,
|
|
|
+ .wait_finish = vb2_ops_wait_finish,
|
|
|
+};
|
|
|
+
|
|
|
static int vidioc_g_parm(struct file *filp, void *priv,
|
|
|
struct v4l2_streamparm *parm)
|
|
|
{
|
|
@@ -895,7 +669,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
|
|
|
{
|
|
|
struct go7007 *go = video_drvdata(file);
|
|
|
|
|
|
- if (go->streaming)
|
|
|
+ if (vb2_is_busy(&go->vidq))
|
|
|
return -EBUSY;
|
|
|
|
|
|
go->std = std;
|
|
@@ -1006,7 +780,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
|
|
|
|
|
|
if (input >= go->board_info->num_inputs)
|
|
|
return -EINVAL;
|
|
|
- if (go->streaming)
|
|
|
+ if (vb2_is_busy(&go->vidq))
|
|
|
return -EBUSY;
|
|
|
|
|
|
go->input = input;
|
|
@@ -1193,95 +967,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static ssize_t go7007_read(struct file *file, char __user *data,
|
|
|
- size_t count, loff_t *ppos)
|
|
|
-{
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
-static void go7007_vm_open(struct vm_area_struct *vma)
|
|
|
-{
|
|
|
- struct go7007_buffer *gobuf = vma->vm_private_data;
|
|
|
-
|
|
|
- ++gobuf->mapped;
|
|
|
-}
|
|
|
-
|
|
|
-static void go7007_vm_close(struct vm_area_struct *vma)
|
|
|
-{
|
|
|
- struct go7007_buffer *gobuf = vma->vm_private_data;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- if (--gobuf->mapped == 0) {
|
|
|
- spin_lock_irqsave(&gobuf->go->spinlock, flags);
|
|
|
- deactivate_buffer(gobuf);
|
|
|
- spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* Copied from videobuf-dma-sg.c */
|
|
|
-static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
-{
|
|
|
- struct page *page;
|
|
|
-
|
|
|
- page = alloc_page(GFP_USER | __GFP_DMA32);
|
|
|
- if (!page)
|
|
|
- return VM_FAULT_OOM;
|
|
|
- clear_user_highpage(page, (unsigned long)vmf->virtual_address);
|
|
|
- vmf->page = page;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static struct vm_operations_struct go7007_vm_ops = {
|
|
|
- .open = go7007_vm_open,
|
|
|
- .close = go7007_vm_close,
|
|
|
- .fault = go7007_vm_fault,
|
|
|
-};
|
|
|
-
|
|
|
-static int go7007_mmap(struct file *file, struct vm_area_struct *vma)
|
|
|
-{
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- unsigned int index;
|
|
|
-
|
|
|
- if (go->status != STATUS_ONLINE)
|
|
|
- return -EIO;
|
|
|
- if (!(vma->vm_flags & VM_SHARED))
|
|
|
- return -EINVAL; /* only support VM_SHARED mapping */
|
|
|
- if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE)
|
|
|
- return -EINVAL; /* must map exactly one full buffer */
|
|
|
- index = vma->vm_pgoff / GO7007_BUF_PAGES;
|
|
|
- if (index >= go->buf_count)
|
|
|
- return -EINVAL; /* trying to map beyond requested buffers */
|
|
|
- if (index * GO7007_BUF_PAGES != vma->vm_pgoff)
|
|
|
- return -EINVAL; /* offset is not aligned on buffer boundary */
|
|
|
- if (go->bufs[index].mapped > 0)
|
|
|
- return -EBUSY;
|
|
|
- go->bufs[index].mapped = 1;
|
|
|
- go->bufs[index].user_addr = vma->vm_start;
|
|
|
- vma->vm_ops = &go7007_vm_ops;
|
|
|
- vma->vm_flags |= VM_DONTEXPAND;
|
|
|
- vma->vm_flags &= ~VM_IO;
|
|
|
- vma->vm_private_data = &go->bufs[index];
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned int go7007_poll(struct file *file, poll_table *wait)
|
|
|
-{
|
|
|
- unsigned long req_events = poll_requested_events(wait);
|
|
|
- struct go7007 *go = video_drvdata(file);
|
|
|
- struct go7007_buffer *gobuf;
|
|
|
- unsigned int res = v4l2_ctrl_poll(file, wait);
|
|
|
-
|
|
|
- if (!(req_events & (POLLIN | POLLRDNORM)))
|
|
|
- return res;
|
|
|
- if (list_empty(&go->stream))
|
|
|
- return POLLERR;
|
|
|
- gobuf = list_entry(go->stream.next, struct go7007_buffer, stream);
|
|
|
- poll_wait(file, &go->frame_waitq, wait);
|
|
|
- if (gobuf->state == BUF_STATE_DONE)
|
|
|
- return res | POLLIN | POLLRDNORM;
|
|
|
- return res;
|
|
|
-}
|
|
|
-
|
|
|
static void go7007_vfl_release(struct video_device *vfd)
|
|
|
{
|
|
|
video_device_release(vfd);
|
|
@@ -1290,11 +975,11 @@ static void go7007_vfl_release(struct video_device *vfd)
|
|
|
static struct v4l2_file_operations go7007_fops = {
|
|
|
.owner = THIS_MODULE,
|
|
|
.open = v4l2_fh_open,
|
|
|
- .release = go7007_release,
|
|
|
- .ioctl = video_ioctl2,
|
|
|
- .read = go7007_read,
|
|
|
- .mmap = go7007_mmap,
|
|
|
- .poll = go7007_poll,
|
|
|
+ .release = vb2_fop_release,
|
|
|
+ .unlocked_ioctl = video_ioctl2,
|
|
|
+ .read = vb2_fop_read,
|
|
|
+ .mmap = vb2_fop_mmap,
|
|
|
+ .poll = vb2_fop_poll,
|
|
|
};
|
|
|
|
|
|
static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
@@ -1303,10 +988,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
|
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
|
|
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
|
|
|
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
|
|
|
- .vidioc_reqbufs = vidioc_reqbufs,
|
|
|
- .vidioc_querybuf = vidioc_querybuf,
|
|
|
- .vidioc_qbuf = vidioc_qbuf,
|
|
|
- .vidioc_dqbuf = vidioc_dqbuf,
|
|
|
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
|
|
|
+ .vidioc_querybuf = vb2_ioctl_querybuf,
|
|
|
+ .vidioc_qbuf = vb2_ioctl_qbuf,
|
|
|
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
|
|
|
.vidioc_g_std = vidioc_g_std,
|
|
|
.vidioc_s_std = vidioc_s_std,
|
|
|
.vidioc_querystd = vidioc_querystd,
|
|
@@ -1316,8 +1001,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
|
.vidioc_enumaudio = vidioc_enumaudio,
|
|
|
.vidioc_g_audio = vidioc_g_audio,
|
|
|
.vidioc_s_audio = vidioc_s_audio,
|
|
|
- .vidioc_streamon = vidioc_streamon,
|
|
|
- .vidioc_streamoff = vidioc_streamoff,
|
|
|
+ .vidioc_streamon = vb2_ioctl_streamon,
|
|
|
+ .vidioc_streamoff = vb2_ioctl_streamoff,
|
|
|
.vidioc_g_tuner = vidioc_g_tuner,
|
|
|
.vidioc_s_tuner = vidioc_s_tuner,
|
|
|
.vidioc_g_frequency = vidioc_g_frequency,
|
|
@@ -1379,10 +1064,27 @@ int go7007_v4l2_init(struct go7007 *go)
|
|
|
{
|
|
|
int rv;
|
|
|
|
|
|
+ mutex_init(&go->serialize_lock);
|
|
|
+ mutex_init(&go->queue_lock);
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&go->vidq_active);
|
|
|
+ go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
+ go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
|
|
|
+ go->vidq.ops = &go7007_video_qops;
|
|
|
+ go->vidq.mem_ops = &vb2_vmalloc_memops;
|
|
|
+ go->vidq.drv_priv = go;
|
|
|
+ go->vidq.buf_struct_size = sizeof(struct go7007_buffer);
|
|
|
+ go->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
|
|
+ go->vidq.lock = &go->queue_lock;
|
|
|
+ rv = vb2_queue_init(&go->vidq);
|
|
|
+ if (rv)
|
|
|
+ return rv;
|
|
|
go->video_dev = video_device_alloc();
|
|
|
if (go->video_dev == NULL)
|
|
|
return -ENOMEM;
|
|
|
*go->video_dev = go7007_template;
|
|
|
+ go->video_dev->lock = &go->serialize_lock;
|
|
|
+ go->video_dev->queue = &go->vidq;
|
|
|
set_bit(V4L2_FL_USE_FH_PRIO, &go->video_dev->flags);
|
|
|
video_set_drvdata(go->video_dev, go);
|
|
|
go->video_dev->v4l2_dev = &go->v4l2_dev;
|
|
@@ -1436,16 +1138,5 @@ int go7007_v4l2_init(struct go7007 *go)
|
|
|
|
|
|
void go7007_v4l2_remove(struct go7007 *go)
|
|
|
{
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- mutex_lock(&go->hw_lock);
|
|
|
- if (go->streaming) {
|
|
|
- go->streaming = 0;
|
|
|
- go7007_stream_stop(go);
|
|
|
- spin_lock_irqsave(&go->spinlock, flags);
|
|
|
- abort_queued(go);
|
|
|
- spin_unlock_irqrestore(&go->spinlock, flags);
|
|
|
- }
|
|
|
- mutex_unlock(&go->hw_lock);
|
|
|
v4l2_ctrl_handler_free(&go->hdl);
|
|
|
}
|