Commit 643e8350 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

media: cx18: convert to vb2

This patch converts cx18 from the old deprecated videobuf framework
to the 'new' vb2 framework.
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 5f225889
...@@ -3,7 +3,7 @@ config VIDEO_CX18 ...@@ -3,7 +3,7 @@ config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support" tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_DEV && DVB_CORE && PCI && I2C depends on VIDEO_DEV && DVB_CORE && PCI && I2C
select I2C_ALGOBIT select I2C_ALGOBIT
select VIDEOBUF_VMALLOC select VIDEOBUF2_VMALLOC
depends on RC_CORE depends on RC_CORE
select VIDEO_TUNER select VIDEO_TUNER
select VIDEO_TVEEPROM select VIDEO_TVEEPROM
......
...@@ -48,9 +48,8 @@ ...@@ -48,9 +48,8 @@
#include <media/dvb_net.h> #include <media/dvb_net.h>
#include <media/dvbdev.h> #include <media/dvbdev.h>
/* Videobuf / YUV support */ /* vb2 YUV support */
#include <media/videobuf-core.h> #include <media/videobuf2-vmalloc.h>
#include <media/videobuf-vmalloc.h>
#ifndef CONFIG_PCI #ifndef CONFIG_PCI
# error "This driver requires kernel PCI support." # error "This driver requires kernel PCI support."
...@@ -284,6 +283,14 @@ struct cx18_options { ...@@ -284,6 +283,14 @@ struct cx18_options {
#define list_entry_is_past_end(pos, head, member) \ #define list_entry_is_past_end(pos, head, member) \
(&pos->member == (head)) (&pos->member == (head))
struct cx18_vb2_buffer {
/* Common video buffer sub-system struct */
struct vb2_v4l2_buffer vb;
struct list_head list;
v4l2_std_id tvnorm; /* selected tv norm */
u32 bytes_used;
};
struct cx18_buffer { struct cx18_buffer {
struct list_head list; struct list_head list;
dma_addr_t dma_handle; dma_addr_t dma_handle;
...@@ -399,19 +406,12 @@ struct cx18_stream { ...@@ -399,19 +406,12 @@ struct cx18_stream {
struct list_head vb_capture; /* video capture queue */ struct list_head vb_capture; /* video capture queue */
spinlock_t vb_lock; spinlock_t vb_lock;
struct timer_list vb_timeout; struct timer_list vb_timeout;
u32 sequence;
struct videobuf_queue vbuf_q; struct vb2_queue vidq;
spinlock_t vbuf_q_lock; /* Protect vbuf_q */
enum v4l2_buf_type vb_type; enum v4l2_buf_type vb_type;
}; };
struct cx18_videobuf_buffer {
/* Common video buffer sub-system struct */
struct videobuf_buffer vb;
v4l2_std_id tvnorm; /* selected tv norm */
u32 bytes_used;
};
struct cx18_open_id { struct cx18_open_id {
struct v4l2_fh fh; struct v4l2_fh fh;
u32 open_id; u32 open_id;
......
...@@ -584,12 +584,6 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, ...@@ -584,12 +584,6 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
if (rc) if (rc)
return rc; return rc;
if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}
return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
} }
...@@ -618,17 +612,6 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) ...@@ -618,17 +612,6 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_FILE("Encoder poll started capture\n"); CX18_DEBUG_FILE("Encoder poll started capture\n");
} }
if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
__poll_t videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
if (v4l2_event_pending(&id->fh))
res |= EPOLLPRI;
if (eof && videobuf_poll == EPOLLERR)
return res | EPOLLHUP;
return res | videobuf_poll;
}
/* add stream's waitq to the poll list */ /* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n"); CX18_DEBUG_HI_FILE("Encoder poll\n");
if (v4l2_event_pending(&id->fh)) if (v4l2_event_pending(&id->fh))
...@@ -643,62 +626,20 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) ...@@ -643,62 +626,20 @@ __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
return res; return res;
} }
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
/* Start a capture if there is none */
if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
int rc;
mutex_lock(&cx->serialize_lock);
rc = cx18_start_capture(id);
mutex_unlock(&cx->serialize_lock);
if (rc) {
CX18_DEBUG_INFO(
"Could not start capture for %s (%d)\n",
s->name, rc);
return -EINVAL;
}
CX18_DEBUG_FILE("Encoder mmap started capture\n");
}
return videobuf_mmap_mapper(&s->vbuf_q, vma);
}
return -EINVAL;
}
void cx18_vb_timeout(struct timer_list *t) void cx18_vb_timeout(struct timer_list *t)
{ {
struct cx18_stream *s = from_timer(s, t, vb_timeout); struct cx18_stream *s = from_timer(s, t, vb_timeout);
struct cx18_videobuf_buffer *buf;
unsigned long flags;
/* Return all of the buffers in error state, so the vbi/vid inode /*
* Return all of the buffers in error state, so the vbi/vid inode
* can return from blocking. * can return from blocking.
*/ */
spin_lock_irqsave(&s->vb_lock, flags); cx18_clear_queue(s, VB2_BUF_STATE_ERROR);
while (!list_empty(&s->vb_capture)) {
buf = list_entry(s->vb_capture.next,
struct cx18_videobuf_buffer, vb.queue);
list_del(&buf->vb.queue);
buf->vb.state = VIDEOBUF_ERROR;
wake_up(&buf->vb.done);
}
spin_unlock_irqrestore(&s->vb_lock, flags);
} }
void cx18_stop_capture(struct cx18_open_id *id, int gop_end) void cx18_stop_capture(struct cx18_stream *s, int gop_end)
{ {
struct cx18 *cx = id->cx; struct cx18 *cx = s->cx;
struct cx18_stream *s = &cx->streams[id->type];
struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
...@@ -709,7 +650,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) ...@@ -709,7 +650,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
/* Stop capturing */ /* Stop capturing */
if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
CX18_DEBUG_INFO("close stopping capture\n"); CX18_DEBUG_INFO("close stopping capture\n");
if (id->type == CX18_ENC_STREAM_TYPE_MPG) { if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
/* Stop internal use associated VBI and IDX streams */ /* Stop internal use associated VBI and IDX streams */
if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
...@@ -721,7 +662,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) ...@@ -721,7 +662,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
cx18_stop_v4l2_encode_stream(s_idx, 0); cx18_stop_v4l2_encode_stream(s_idx, 0);
} }
} }
if (id->type == CX18_ENC_STREAM_TYPE_VBI && if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
/* Also used internally, don't stop capturing */ /* Also used internally, don't stop capturing */
s->id = -1; s->id = -1;
...@@ -741,6 +682,7 @@ int cx18_v4l2_close(struct file *filp) ...@@ -741,6 +682,7 @@ int cx18_v4l2_close(struct file *filp)
struct cx18_open_id *id = fh2id(fh); struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx; struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type]; struct cx18_stream *s = &cx->streams[id->type];
struct video_device *vdev = &s->video_dev;
CX18_DEBUG_IOCTL("close() of %s\n", s->name); CX18_DEBUG_IOCTL("close() of %s\n", s->name);
...@@ -766,12 +708,17 @@ int cx18_v4l2_close(struct file *filp) ...@@ -766,12 +708,17 @@ int cx18_v4l2_close(struct file *filp)
cx18_unmute(cx); cx18_unmute(cx);
} }
if (id->type == CX18_ENC_STREAM_TYPE_YUV &&
filp->private_data == vdev->queue->owner) {
vb2_queue_release(vdev->queue);
vdev->queue->owner = NULL;
}
v4l2_fh_del(fh); v4l2_fh_del(fh);
v4l2_fh_exit(fh); v4l2_fh_exit(fh);
/* 'Unclaim' this stream */ /* 'Unclaim' this stream */
if (s->id == id->open_id) if (id->type != CX18_ENC_STREAM_TYPE_YUV && s->id == id->open_id)
cx18_stop_capture(id, 0); cx18_stop_capture(s, 0);
kfree(id); kfree(id);
mutex_unlock(&cx->serialize_lock); mutex_unlock(&cx->serialize_lock);
return 0; return 0;
......
...@@ -16,10 +16,11 @@ ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, ...@@ -16,10 +16,11 @@ ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
int cx18_v4l2_close(struct file *filp); int cx18_v4l2_close(struct file *filp);
__poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); __poll_t cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
int cx18_start_capture(struct cx18_open_id *id); int cx18_start_capture(struct cx18_open_id *id);
void cx18_stop_capture(struct cx18_open_id *id, int gop_end); void cx18_stop_capture(struct cx18_stream *s, int gop_end);
void cx18_mute(struct cx18 *cx); void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx); void cx18_unmute(struct cx18 *cx);
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
void cx18_clear_queue(struct cx18_stream *s, enum vb2_buffer_state state);
void cx18_vb_timeout(struct timer_list *t); void cx18_vb_timeout(struct timer_list *t);
/* Shared with cx18-alsa module */ /* Shared with cx18-alsa module */
......
...@@ -803,117 +803,6 @@ static int cx18_g_enc_index(struct file *file, void *fh, ...@@ -803,117 +803,6 @@ static int cx18_g_enc_index(struct file *file, void *fh,
return 0; return 0;
} }
static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
{
struct videobuf_queue *q = NULL;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
switch (s->vb_type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
q = &s->vbuf_q;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
break;
default:
break;
}
return q;
}
static int cx18_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
/* Start the hardware only if we're the video device */
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
if (id->type != CX18_ENC_STREAM_TYPE_YUV)
return -EINVAL;
/* Establish a buffer timeout */
mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
return videobuf_streamon(cx18_vb_queue(id));
}
static int cx18_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
/* Start the hardware only if we're the video device */
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
if (id->type != CX18_ENC_STREAM_TYPE_YUV)
return -EINVAL;
return videobuf_streamoff(cx18_vb_queue(id));
}
static int cx18_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
return videobuf_reqbufs(cx18_vb_queue(id), rb);
}
static int cx18_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
return videobuf_querybuf(cx18_vb_queue(id), b);
}
static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
return videobuf_qbuf(cx18_vb_queue(id), b);
}
static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct cx18_open_id *id = file->private_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];
if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
return -EINVAL;
return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
}
static int cx18_encoder_cmd(struct file *file, void *fh, static int cx18_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc) struct v4l2_encoder_cmd *enc)
{ {
...@@ -930,7 +819,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, ...@@ -930,7 +819,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
case V4L2_ENC_CMD_STOP: case V4L2_ENC_CMD_STOP:
CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
cx18_stop_capture(id, cx18_stop_capture(&cx->streams[id->type],
enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
break; break;
...@@ -1106,12 +995,15 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { ...@@ -1106,12 +995,15 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_s_register = cx18_s_register, .vidioc_s_register = cx18_s_register,
#endif #endif
.vidioc_default = cx18_default, .vidioc_default = cx18_default,
.vidioc_streamon = cx18_streamon,
.vidioc_streamoff = cx18_streamoff, .vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_reqbufs = cx18_reqbufs, .vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_querybuf = cx18_querybuf, .vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_qbuf = cx18_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_dqbuf = cx18_dqbuf, .vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
}; };
......
...@@ -145,36 +145,37 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) ...@@ -145,36 +145,37 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
} }
} }
static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, static void cx18_mdl_send_to_vb2(struct cx18_stream *s, struct cx18_mdl *mdl)
struct cx18_mdl *mdl)
{ {
struct cx18_videobuf_buffer *vb_buf; struct cx18_vb2_buffer *vb_buf;
struct cx18_buffer *buf; struct cx18_buffer *buf;
u8 *p; u8 *p;
u32 offset = 0; u32 offset = 0;
int dispatch = 0; int dispatch = 0;
unsigned long bsize;
if (mdl->bytesused == 0) if (mdl->bytesused == 0)
return; return;
/* Acquire a videobuf buffer, clone to and and release it */ /* Acquire a vb2 buffer, clone to and release it */
spin_lock(&s->vb_lock); spin_lock(&s->vb_lock);
if (list_empty(&s->vb_capture)) if (list_empty(&s->vb_capture))
goto out; goto out;
vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, vb_buf = list_first_entry(&s->vb_capture, struct cx18_vb2_buffer,
vb.queue); list);
p = videobuf_to_vmalloc(&vb_buf->vb); p = vb2_plane_vaddr(&vb_buf->vb.vb2_buf, 0);
if (!p) if (!p)
goto out; goto out;
bsize = vb2_get_plane_payload(&vb_buf->vb.vb2_buf, 0);
offset = vb_buf->bytes_used; offset = vb_buf->bytes_used;
list_for_each_entry(buf, &mdl->buf_list, list) { list_for_each_entry(buf, &mdl->buf_list, list) {
if (buf->bytesused == 0) if (buf->bytesused == 0)
break; break;
if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { if ((offset + buf->bytesused) <= bsize) {
memcpy(p + offset, buf->buf, buf->bytesused); memcpy(p + offset, buf->buf, buf->bytesused);
offset += buf->bytesused; offset += buf->bytesused;
vb_buf->bytes_used += buf->bytesused; vb_buf->bytes_used += buf->bytesused;
...@@ -188,10 +189,10 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, ...@@ -188,10 +189,10 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
} }
if (dispatch) { if (dispatch) {
vb_buf->vb.ts = ktime_get_ns(); vb_buf->vb.vb2_buf.timestamp = ktime_get_ns();
list_del(&vb_buf->vb.queue); vb_buf->vb.sequence = s->sequence++;
vb_buf->vb.state = VIDEOBUF_DONE; list_del(&vb_buf->list);
wake_up(&vb_buf->vb.done); vb2_buffer_done(&vb_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
} }
mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
...@@ -304,7 +305,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) ...@@ -304,7 +305,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
cx18_enqueue(s, mdl, &s->q_full); cx18_enqueue(s, mdl, &s->q_full);
} }
} else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
cx18_mdl_send_to_videobuf(s, mdl); cx18_mdl_send_to_vb2(s, mdl);
cx18_enqueue(s, mdl, &s->q_free); cx18_enqueue(s, mdl, &s->q_free);
} else { } else {
cx18_enqueue(s, mdl, &s->q_full); cx18_enqueue(s, mdl, &s->q_full);
......
...@@ -29,7 +29,16 @@ static const struct v4l2_file_operations cx18_v4l2_enc_fops = { ...@@ -29,7 +29,16 @@ static const struct v4l2_file_operations cx18_v4l2_enc_fops = {
.unlocked_ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
.release = cx18_v4l2_close, .release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll, .poll = cx18_v4l2_enc_poll,
.mmap = cx18_v4l2_mmap, };
static const struct v4l2_file_operations cx18_v4l2_enc_yuv_fops = {
.owner = THIS_MODULE,
.open = cx18_v4l2_open,
.unlocked_ioctl = video_ioctl2,
.release = cx18_v4l2_close,
.poll = vb2_fop_poll,
.read = vb2_fop_read,
.mmap = vb2_fop_mmap,
}; };
/* offset from 0 to register ts v4l2 minors on */ /* offset from 0 to register ts v4l2 minors on */
...@@ -91,156 +100,142 @@ static struct { ...@@ -91,156 +100,142 @@ static struct {
}, },
}; };
static int cx18_queue_setup(struct vb2_queue *vq,
static void cx18_dma_free(struct videobuf_queue *q, unsigned int *nbuffers, unsigned int *nplanes,
struct cx18_stream *s, struct cx18_videobuf_buffer *buf) unsigned int sizes[], struct device *alloc_devs[])
{
videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_vmalloc_free(&buf->vb);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
static int cx18_prepare_buffer(struct videobuf_queue *q,
struct cx18_stream *s,
struct cx18_videobuf_buffer *buf,
u32 pixelformat,
unsigned int width, unsigned int height,
enum v4l2_field field)
{ {
struct cx18_stream *s = vb2_get_drv_priv(vq);
struct cx18 *cx = s->cx; struct cx18 *cx = s->cx;
int rc = 0; unsigned int szimage;
/* check settings */
buf->bytes_used = 0;
if ((width < 48) || (height < 32))
return -EINVAL;
buf->vb.size = (width * height * 2);
if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
return -EINVAL;
/* alloc + fill struct (if changed) */
if (buf->vb.width != width || buf->vb.height != height ||
buf->vb.field != field || s->pixelformat != pixelformat ||
buf->tvnorm != cx->std) {
buf->vb.width = width; /*
buf->vb.height = height; * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
buf->vb.field = field; * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
buf->tvnorm = cx->std; */
s->pixelformat = pixelformat;
/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
s->vb_bytes_per_frame = height * 720 * 3 / 2; szimage = cx->cxhdl.height * 720 * 3 / 2;
else else
s->vb_bytes_per_frame = height * 720 * 2; szimage = cx->cxhdl.height * 720 * 2;
cx18_dma_free(q, s, buf);
}
if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) /*
return -EINVAL; * Let's request at least three buffers: two for the
* DMA engine and one for userspace.
if (buf->vb.field == 0) */
buf->vb.field = V4L2_FIELD_INTERLACED; if (vq->num_buffers + *nbuffers < 3)
*nbuffers = 3 - vq->num_buffers;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
buf->tvnorm = cx->std;
s->pixelformat = pixelformat;
/* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) if (*nplanes) {
UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ if (*nplanes != 1 || sizes[0] < szimage)
if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) return -EINVAL;
s->vb_bytes_per_frame = height * 720 * 3 / 2;
else
s->vb_bytes_per_frame = height * 720 * 2;
rc = videobuf_iolock(q, &buf->vb, NULL);
if (rc != 0)
goto fail;
}
buf->vb.state = VIDEOBUF_PREPARED;
return 0; return 0;
}
fail: sizes[0] = szimage;
cx18_dma_free(q, s, buf); *nplanes = 1;
return rc; return 0;
} }
/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) static void cx18_buf_queue(struct vb2_buffer *vb)
1440 is a single line of 4:2:2 YUV at 720 luma samples wide {
*/ struct cx18_stream *s = vb2_get_drv_priv(vb->vb2_queue);
#define VB_MIN_BUFFERS 32 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
#define VB_MIN_BUFSIZE 4147200 struct cx18_vb2_buffer *buf =
container_of(vbuf, struct cx18_vb2_buffer, vb);
unsigned long flags;
spin_lock_irqsave(&s->vb_lock, flags);
list_add_tail(&buf->list, &s->vb_capture);
spin_unlock_irqrestore(&s->vb_lock, flags);
}
static int buffer_setup(struct videobuf_queue *q, static int cx18_buf_prepare(struct vb2_buffer *vb)
unsigned int *count, unsigned int *size)
{ {
struct cx18_stream *s = q->priv_data; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx18_stream *s = vb2_get_drv_priv(vb->vb2_queue);
struct cx18 *cx = s->cx; struct cx18 *cx = s->cx;
unsigned int size;
*size = 2 * cx->cxhdl.width * cx->cxhdl.height; /*
if (*count == 0) * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
*count = VB_MIN_BUFFERS; * UYUV YUV size is (Y=(h*720) + UV=(h*(720)))
*/
while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16)
(*count)--; size = cx->cxhdl.height * 720 * 3 / 2;
else
q->field = V4L2_FIELD_INTERLACED; size = cx->cxhdl.height * 720 * 2;
q->last = V4L2_FIELD_INTERLACED;
if (vb2_plane_size(vb, 0) < size)
return -EINVAL;
vb2_set_plane_payload(vb, 0, size);
vbuf->field = V4L2_FIELD_INTERLACED;
return 0; return 0;
} }
static int buffer_prepare(struct videobuf_queue *q, void cx18_clear_queue(struct cx18_stream *s, enum vb2_buffer_state state)
struct videobuf_buffer *vb,
enum v4l2_field field)
{ {
struct cx18_videobuf_buffer *buf = while (!list_empty(&s->vb_capture)) {
container_of(vb, struct cx18_videobuf_buffer, vb); struct cx18_vb2_buffer *buf;
struct cx18_stream *s = q->priv_data;
struct cx18 *cx = s->cx;
return cx18_prepare_buffer(q, s, buf, s->pixelformat, buf = list_first_entry(&s->vb_capture,
cx->cxhdl.width, cx->cxhdl.height, field); struct cx18_vb2_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf, state);
}
} }
static void buffer_release(struct videobuf_queue *q, static int cx18_start_streaming(struct vb2_queue *vq, unsigned int count)
struct videobuf_buffer *vb)
{ {
struct cx18_videobuf_buffer *buf = struct v4l2_fh *owner = vq->owner;
container_of(vb, struct cx18_videobuf_buffer, vb); struct cx18_stream *s = vb2_get_drv_priv(vq);
struct cx18_stream *s = q->priv_data; unsigned long flags;
int rc;
if (WARN_ON(!owner)) {
rc = -EIO;
goto clear_queue;
}
s->sequence = 0;
rc = cx18_start_capture(fh2id(owner));
if (!rc) {
/* Establish a buffer timeout */
mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
return 0;
}
cx18_dma_free(q, s, buf); clear_queue:
spin_lock_irqsave(&s->vb_lock, flags);
cx18_clear_queue(s, VB2_BUF_STATE_QUEUED);
spin_unlock_irqrestore(&s->vb_lock, flags);
return rc;
} }
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) static void cx18_stop_streaming(struct vb2_queue *vq)
{ {
struct cx18_videobuf_buffer *buf = struct cx18_stream *s = vb2_get_drv_priv(vq);
container_of(vb, struct cx18_videobuf_buffer, vb); unsigned long flags;
struct cx18_stream *s = q->priv_data;
cx18_stop_capture(s, 0);
buf->vb.state = VIDEOBUF_QUEUED; timer_delete_sync(&s->vb_timeout);
spin_lock_irqsave(&s->vb_lock, flags);
list_add_tail(&buf->vb.queue, &s->vb_capture); cx18_clear_queue(s, VB2_BUF_STATE_ERROR);
spin_unlock_irqrestore(&s->vb_lock, flags);
} }
static const struct videobuf_queue_ops cx18_videobuf_qops = { static const struct vb2_ops cx18_vb2_qops = {
.buf_setup = buffer_setup, .queue_setup = cx18_queue_setup,
.buf_prepare = buffer_prepare, .buf_queue = cx18_buf_queue,
.buf_queue = buffer_queue, .buf_prepare = cx18_buf_prepare,
.buf_release = buffer_release, .start_streaming = cx18_start_streaming,
.stop_streaming = cx18_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
}; };
static void cx18_stream_init(struct cx18 *cx, int type) static int cx18_stream_init(struct cx18 *cx, int type)
{ {
struct cx18_stream *s = &cx->streams[type]; struct cx18_stream *s = &cx->streams[type];
int err = 0;
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
...@@ -275,22 +270,33 @@ static void cx18_stream_init(struct cx18 *cx, int type) ...@@ -275,22 +270,33 @@ static void cx18_stream_init(struct cx18 *cx, int type)
INIT_LIST_HEAD(&s->vb_capture); INIT_LIST_HEAD(&s->vb_capture);
timer_setup(&s->vb_timeout, cx18_vb_timeout, 0); timer_setup(&s->vb_timeout, cx18_vb_timeout, 0);
spin_lock_init(&s->vb_lock); spin_lock_init(&s->vb_lock);
if (type == CX18_ENC_STREAM_TYPE_YUV) {
spin_lock_init(&s->vbuf_q_lock);
if (type == CX18_ENC_STREAM_TYPE_YUV) {
s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
&cx->pci_dev->dev, &s->vbuf_q_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx18_videobuf_buffer),
s, &cx->serialize_lock);
/* Assume the previous pixel default */ /* Assume the previous pixel default */
s->pixelformat = V4L2_PIX_FMT_NV12_16L16; s->pixelformat = V4L2_PIX_FMT_NV12_16L16;
s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2;
s->vb_bytes_per_line = 720; s->vb_bytes_per_line = 720;
s->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
s->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
s->vidq.drv_priv = s;
s->vidq.buf_struct_size = sizeof(struct cx18_vb2_buffer);
s->vidq.ops = &cx18_vb2_qops;
s->vidq.mem_ops = &vb2_vmalloc_memops;
s->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
s->vidq.min_buffers_needed = 2;
s->vidq.gfp_flags = GFP_DMA32;
s->vidq.dev = &cx->pci_dev->dev;
s->vidq.lock = &cx->serialize_lock;
err = vb2_queue_init(&s->vidq);
if (err)
v4l2_err(&cx->v4l2_dev, "cannot init vb2 queue\n");
s->video_dev.queue = &s->vidq;
} }
return err;
} }
static int cx18_prep_dev(struct cx18 *cx, int type) static int cx18_prep_dev(struct cx18 *cx, int type)
...@@ -299,6 +305,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) ...@@ -299,6 +305,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
u32 cap = cx->v4l2_cap; u32 cap = cx->v4l2_cap;
int num_offset = cx18_stream_info[type].num_offset; int num_offset = cx18_stream_info[type].num_offset;
int num = cx->instance + cx18_first_minor + num_offset; int num = cx->instance + cx18_first_minor + num_offset;
int err;
/* /*
* These five fields are always initialized. * These five fields are always initialized.
...@@ -330,7 +337,9 @@ static int cx18_prep_dev(struct cx18 *cx, int type) ...@@ -330,7 +337,9 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
return 0; return 0;
} }
cx18_stream_init(cx, type); err = cx18_stream_init(cx, type);
if (err)
return err;
/* Allocate the cx18_dvb struct only for the TS on cards with DTV */ /* Allocate the cx18_dvb struct only for the TS on cards with DTV */
if (type == CX18_ENC_STREAM_TYPE_TS) { if (type == CX18_ENC_STREAM_TYPE_TS) {
...@@ -356,6 +365,9 @@ static int cx18_prep_dev(struct cx18 *cx, int type) ...@@ -356,6 +365,9 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->video_dev.num = num; s->video_dev.num = num;
s->video_dev.v4l2_dev = &cx->v4l2_dev; s->video_dev.v4l2_dev = &cx->v4l2_dev;
if (type == CX18_ENC_STREAM_TYPE_YUV)
s->video_dev.fops = &cx18_v4l2_enc_yuv_fops;
else
s->video_dev.fops = &cx18_v4l2_enc_fops; s->video_dev.fops = &cx18_v4l2_enc_fops;
s->video_dev.release = video_device_release_empty; s->video_dev.release = video_device_release_empty;
if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER) if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER)
...@@ -525,11 +537,11 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) ...@@ -525,11 +537,11 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
if (vdev->v4l2_dev == NULL) if (vdev->v4l2_dev == NULL)
continue; continue;
if (type == CX18_ENC_STREAM_TYPE_YUV)
videobuf_mmap_free(&cx->streams[type].vbuf_q);
cx18_stream_free(&cx->streams[type]); cx18_stream_free(&cx->streams[type]);
if (type == CX18_ENC_STREAM_TYPE_YUV)
vb2_video_unregister_device(vdev);
else
video_unregister_device(vdev); video_unregister_device(vdev);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment