Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 250213
b: refs/heads/master
c: b7101de
h: refs/heads/master
i:
  250211: b812daa
v: v3
  • Loading branch information
Steven Toth authored and Mauro Carvalho Chehab committed May 20, 2011
1 parent a7b8dbb commit 88ce236
Show file tree
Hide file tree
Showing 9 changed files with 467 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5ed9bd02444a00bb1e8ecc1baa8ecdb633afc126
refs/heads/master: b7101de3fff596b35e45cd9fb7007caa07e97c9a
2 changes: 2 additions & 0 deletions trunk/drivers/media/video/cx18/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
select I2C_ALGOBIT
select VIDEOBUF_DVB
select VIDEOBUF_VMALLOC
depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
Expand Down
25 changes: 25 additions & 0 deletions trunk/drivers/media/video/cx18/cx18-driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
#include "dvb_net.h"
#include "dvbdev.h"

/* Videobuf / YUV support */
#include <media/videobuf-core.h>
#include <media/videobuf-vmalloc.h>

#ifndef CONFIG_PCI
# error "This driver requires kernel PCI support."
#endif
Expand Down Expand Up @@ -403,13 +407,34 @@ struct cx18_stream {
struct cx18_queue q_idle; /* idle - not in rotation */

struct work_struct out_work_order;

/* Videobuf for YUV video */
u32 pixelformat;
struct list_head vb_capture; /* video capture queue */
spinlock_t vb_lock;
struct v4l2_framebuffer fbuf;
v4l2_std_id tvnorm; /* selected tv norm */
struct timer_list vb_timeout;
int vbwidth;
int vbheight;
};

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 v4l2_fh fh;
u32 open_id;
int type;
struct cx18 *cx;

struct videobuf_queue vbuf_q;
spinlock_t s_lock; /* Protect vbuf_q */
enum v4l2_buf_type vb_type;
};

static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
Expand Down
214 changes: 214 additions & 0 deletions trunk/drivers/media/video/cx18/cx18-fileops.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
mutex_unlock(&cx->serialize_lock);
if (rc)
return rc;

if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
return videobuf_read_stream(&id->vbuf_q, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}

return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
}

Expand All @@ -622,6 +629,11 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_FILE("Encoder poll started capture\n");
}

if ((id->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(id->type == CX18_ENC_STREAM_TYPE_YUV)) {
return videobuf_poll_stream(filp, &id->vbuf_q, wait);
}

/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
Expand All @@ -633,6 +645,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
return 0;
}

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 ((id->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 poll started capture\n");
}

return videobuf_mmap_mapper(&id->vbuf_q, vma);
}

return -EINVAL;
}

void cx18_vb_timeout(unsigned long data)
{
struct cx18_stream *s = (struct cx18_stream *)data;
struct cx18_videobuf_buffer *buf;
unsigned long flags;

/* Return all of the buffers in error state, so the vbi/vid inode
* can return from blocking.
*/
spin_lock_irqsave(&s->vb_lock, flags);
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)
{
struct cx18 *cx = id->cx;
Expand Down Expand Up @@ -716,12 +780,150 @@ int cx18_v4l2_close(struct file *filp)
cx18_release_stream(s);
} else {
cx18_stop_capture(id, 0);
if (id->type == CX18_ENC_STREAM_TYPE_YUV)
videobuf_mmap_free(&id->vbuf_q);
}
kfree(id);
mutex_unlock(&cx->serialize_lock);
return 0;
}

void cx18_dma_free(struct videobuf_queue *q,
struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
{
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)
{
int rc = 0;

/* check settings */
buf->bytes_used = 0;

if ((width < 48) || (height < 32))
return -EINVAL;

buf->vb.size = (width * height * 16 /*fmt->depth*/) >> 3;
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 != s->tvnorm) {

buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
buf->tvnorm = s->tvnorm;
s->pixelformat = pixelformat;

cx18_dma_free(q, s, buf);
}

if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
return -EINVAL;

if (buf->vb.field == 0)
buf->vb.field = V4L2_FIELD_INTERLACED;

if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
buf->tvnorm = s->tvnorm;
s->pixelformat = pixelformat;

rc = videobuf_iolock(q, &buf->vb, &s->fbuf);
if (rc != 0)
goto fail;
}
buf->vb.state = VIDEOBUF_PREPARED;
return 0;

fail:
cx18_dma_free(q, s, buf);
return rc;

}

#define VB_MIN_BUFFERS 32
#define VB_MIN_BUFSIZE 0x208000

static int buffer_setup(struct videobuf_queue *q,
unsigned int *count, unsigned int *size)
{
struct cx18_open_id *id = q->priv_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];

*size = 2 * s->vbwidth * s->vbheight;
if (*count == 0)
*count = VB_MIN_BUFFERS;

while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
(*count)--;

q->field = V4L2_FIELD_INTERLACED;
q->last = V4L2_FIELD_INTERLACED;

return 0;
}

static int buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx18_videobuf_buffer *buf =
container_of(vb, struct cx18_videobuf_buffer, vb);
struct cx18_open_id *id = q->priv_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];

return cx18_prepare_buffer(q, s, buf, s->pixelformat,
s->vbwidth, s->vbheight, field);
}

static void buffer_release(struct videobuf_queue *q,
struct videobuf_buffer *vb)
{
struct cx18_videobuf_buffer *buf =
container_of(vb, struct cx18_videobuf_buffer, vb);
struct cx18_open_id *id = q->priv_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];

cx18_dma_free(q, s, buf);
}

static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct cx18_videobuf_buffer *buf =
container_of(vb, struct cx18_videobuf_buffer, vb);
struct cx18_open_id *id = q->priv_data;
struct cx18 *cx = id->cx;
struct cx18_stream *s = &cx->streams[id->type];

buf->vb.state = VIDEOBUF_QUEUED;

list_add_tail(&buf->vb.queue, &s->vb_capture);
}

static struct videobuf_queue_ops cx18_videobuf_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
};

static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
{
struct cx18 *cx = s->cx;
Expand All @@ -740,6 +942,9 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
item->cx = cx;
item->type = s->type;

spin_lock_init(&item->s_lock);
item->vb_type = 0;

item->open_id = cx->open_id++;
filp->private_data = &item->fh;

Expand Down Expand Up @@ -774,6 +979,15 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
/* Done! Unmute and continue. */
cx18_unmute(cx);
}
if (item->type == CX18_ENC_STREAM_TYPE_YUV) {
item->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
videobuf_queue_vmalloc_init(&item->vbuf_q, &cx18_videobuf_qops,
&cx->pci_dev->dev, &item->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx18_videobuf_buffer),
item, &cx->serialize_lock);
}
v4l2_fh_add(&item->fh);
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/media/video/cx18/cx18-fileops.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id);
void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx);
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
void cx18_vb_timeout(unsigned long data);

/* Shared with cx18-alsa module */
int cx18_claim_stream(struct cx18_open_id *id, int type);
Expand Down
Loading

0 comments on commit 88ce236

Please sign in to comment.