summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2008-08-29 14:50:35 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-08-29 14:50:35 -0300
commit42b611c065802d5d31f3fd7629bc10e2b134c661 (patch)
tree572f7d18a8a2d82fb720f745d56ffaccddb0ab2d /linux
parent8030ee67bdce5ce3725581d715f9451b950d45da (diff)
parent59261d01832b22f9e02fcdced94a1156259db422 (diff)
downloadmediapointer-dvb-s2-42b611c065802d5d31f3fd7629bc10e2b134c661.tar.gz
mediapointer-dvb-s2-42b611c065802d5d31f3fd7629bc10e2b134c661.tar.bz2
merge: http://linuxtv.org/hg/~awalls/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/video/cx18/cx18-driver.h6
-rw-r--r--linux/drivers/media/video/cx18/cx18-fileops.c47
-rw-r--r--linux/drivers/media/video/cx18/cx18-ioctl.c20
-rw-r--r--linux/drivers/media/video/cx18/cx18-mailbox.c1
-rw-r--r--linux/drivers/media/video/cx18/cx18-queue.c112
-rw-r--r--linux/drivers/media/video/cx18/cx18-streams.c19
-rw-r--r--linux/drivers/media/video/cx18/cx23418.h2
7 files changed, 87 insertions, 120 deletions
diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h
index 4801bc7fb..26359897d 100644
--- a/linux/drivers/media/video/cx18/cx18-driver.h
+++ b/linux/drivers/media/video/cx18/cx18-driver.h
@@ -216,8 +216,7 @@ struct cx18_buffer {
struct cx18_queue {
struct list_head list;
- u32 buffers;
- u32 length;
+ atomic_t buffers;
u32 bytesused;
};
@@ -237,6 +236,8 @@ struct cx18_dvb {
struct cx18; /* forward reference */
struct cx18_scb; /* forward reference */
+#define CX18_INVALID_TASK_HANDLE 0xffffffff
+
struct cx18_stream {
/* These first four fields are always set, even if the stream
is not actually created. */
@@ -259,7 +260,6 @@ struct cx18_stream {
/* Buffer Stats */
u32 buffers;
u32 buf_size;
- u32 buffers_stolen;
/* Buffer Queues */
struct cx18_queue q_free; /* free buffers */
diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c
index 12f9de74d..6ef8a99aa 100644
--- a/linux/drivers/media/video/cx18/cx18-fileops.c
+++ b/linux/drivers/media/video/cx18/cx18-fileops.c
@@ -132,6 +132,7 @@ static void cx18_dualwatch(struct cx18 *cx)
u16 new_stereo_mode;
const u16 stereo_mask = 0x0300;
const u16 dual = 0x0200;
+ u32 h;
new_stereo_mode = cx->params.audio_properties & stereo_mask;
memset(&vt, 0, sizeof(vt));
@@ -143,13 +144,21 @@ static void cx18_dualwatch(struct cx18 *cx)
if (new_stereo_mode == cx->dualwatch_stereo_mode)
return;
- new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+ new_bitmap = new_stereo_mode
+ | (cx->params.audio_properties & ~stereo_mask);
- CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
- cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+ CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
+ "new audio_bitmask=0x%ux\n",
+ cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
- if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
- cx18_find_handle(cx), new_bitmap) == 0) {
+ h = cx18_find_handle(cx);
+ if (h == CX18_INVALID_TASK_HANDLE) {
+ CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
+ return;
+ }
+
+ if (cx18_vapi(cx,
+ CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
cx->dualwatch_stereo_mode = new_stereo_mode;
return;
}
@@ -258,7 +267,7 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
/* New buffers might have become available before we were added
to the waitqueue */
- if (!s->q_full.buffers)
+ if (!atomic_read(&s->q_full.buffers))
schedule();
finish_wait(&s->waitq, &wait);
if (signal_pending(current)) {
@@ -544,7 +553,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (s->q_full.length || s->q_io.length)
+ if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
return POLLIN | POLLRDNORM;
if (eof)
return POLLHUP;
@@ -730,20 +739,28 @@ int cx18_v4l2_open(struct inode *inode, struct file *filp)
void cx18_mute(struct cx18 *cx)
{
- if (atomic_read(&cx->ana_capturing))
- cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
- cx18_find_handle(cx), 1);
+ u32 h;
+ if (atomic_read(&cx->ana_capturing)) {
+ h = cx18_find_handle(cx);
+ if (h != CX18_INVALID_TASK_HANDLE)
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);
+ else
+ CX18_ERR("Can't find valid task handle for mute\n");
+ }
CX18_DEBUG_INFO("Mute\n");
}
void cx18_unmute(struct cx18 *cx)
{
+ u32 h;
if (atomic_read(&cx->ana_capturing)) {
- cx18_msleep_timeout(100, 0);
- cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
- cx18_find_handle(cx), 12);
- cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
- cx18_find_handle(cx), 0);
+ h = cx18_find_handle(cx);
+ if (h != CX18_INVALID_TASK_HANDLE) {
+ cx18_msleep_timeout(100, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12);
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0);
+ } else
+ CX18_ERR("Can't find valid task handle for unmute\n");
}
CX18_DEBUG_INFO("Unmute\n");
}
diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c
index e6c2bfa5d..3f5c2d09a 100644
--- a/linux/drivers/media/video/cx18/cx18-ioctl.c
+++ b/linux/drivers/media/video/cx18/cx18-ioctl.c
@@ -727,6 +727,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
{
struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
+ u32 h;
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
@@ -748,8 +749,14 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
return -EPERM;
if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
return 0;
+ h = cx18_find_handle(cx);
+ if (h == CX18_INVALID_TASK_HANDLE) {
+ CX18_ERR("Can't find valid task handle for "
+ "V4L2_ENC_CMD_PAUSE\n");
+ return -EBADFD;
+ }
cx18_mute(cx);
- cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);
break;
case V4L2_ENC_CMD_RESUME:
@@ -759,7 +766,13 @@ static int cx18_encoder_cmd(struct file *file, void *fh,
return -EPERM;
if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
return 0;
- cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ h = cx18_find_handle(cx);
+ if (h == CX18_INVALID_TASK_HANDLE) {
+ CX18_ERR("Can't find valid task handle for "
+ "V4L2_ENC_CMD_RESUME\n");
+ return -EBADFD;
+ }
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);
cx18_unmute(cx);
break;
@@ -836,7 +849,8 @@ static int cx18_log_status(struct file *file, void *fh)
continue;
CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
s->name, s->s_flags,
- (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers - atomic_read(&s->q_free.buffers))
+ * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c
index 93177514e..1b9fbf9a6 100644
--- a/linux/drivers/media/video/cx18/cx18-mailbox.c
+++ b/linux/drivers/media/video/cx18/cx18-mailbox.c
@@ -82,6 +82,7 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
+ API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, 0),
API_ENTRY(0, 0, 0),
};
diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c
index a31da49f9..a33ba04a2 100644
--- a/linux/drivers/media/video/cx18/cx18-queue.c
+++ b/linux/drivers/media/video/cx18/cx18-queue.c
@@ -37,8 +37,7 @@ void cx18_buf_swap(struct cx18_buffer *buf)
void cx18_queue_init(struct cx18_queue *q)
{
INIT_LIST_HEAD(&q->list);
- q->buffers = 0;
- q->length = 0;
+ atomic_set(&q->buffers, 0);
q->bytesused = 0;
}
@@ -55,8 +54,7 @@ void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
}
spin_lock_irqsave(&s->qlock, flags);
list_add_tail(&buf->list, &q->list);
- q->buffers++;
- q->length += s->buf_size;
+ atomic_inc(&q->buffers);
q->bytesused += buf->bytesused - buf->readpos;
spin_unlock_irqrestore(&s->qlock, flags);
}
@@ -70,8 +68,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
if (!list_empty(&q->list)) {
buf = list_entry(q->list.next, struct cx18_buffer, list);
list_del_init(q->list.next);
- q->buffers--;
- q->length -= s->buf_size;
+ atomic_dec(&q->buffers);
q->bytesused -= buf->bytesused - buf->readpos;
}
spin_unlock_irqrestore(&s->qlock, flags);
@@ -95,10 +92,8 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
/* the transport buffers are handled differently,
they are not moved to the full queue */
if (s->type != CX18_ENC_STREAM_TYPE_TS) {
- s->q_free.buffers--;
- s->q_free.length -= s->buf_size;
- s->q_full.buffers++;
- s->q_full.length += s->buf_size;
+ atomic_dec(&s->q_free.buffers);
+ atomic_inc(&s->q_full.buffers);
s->q_full.bytesused += buf->bytesused;
list_move_tail(&buf->list, &s->q_full.list);
}
@@ -110,99 +105,30 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
return NULL;
}
-static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
- struct cx18_queue *to, int clear, int full)
-{
- struct cx18_buffer *buf =
- list_entry(from->list.next, struct cx18_buffer, list);
-
- list_move_tail(from->list.next, &to->list);
- from->buffers--;
- from->length -= s->buf_size;
- from->bytesused -= buf->bytesused - buf->readpos;
- /* special handling for q_free */
- if (clear)
- buf->bytesused = buf->readpos = buf->b_flags = 0;
- else if (full) {
- /* special handling for stolen buffers, assume
- all bytes are used. */
- buf->bytesused = s->buf_size;
- buf->readpos = buf->b_flags = 0;
- }
- to->buffers++;
- to->length += s->buf_size;
- to->bytesused += buf->bytesused - buf->readpos;
-}
-
-/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
- If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
- If 'steal' != NULL, then buffers may also taken from that queue if
- needed.
-
- The buffer is automatically cleared if it goes to the free queue. It is
- also cleared if buffers need to be taken from the 'steal' queue and
- the 'from' queue is the free queue.
-
- When 'from' is q_free, then needed_bytes is compared to the total
- available buffer length, otherwise needed_bytes is compared to the
- bytesused value. For the 'steal' queue the total available buffer
- length is always used.
-
- -ENOMEM is returned if the buffers could not be obtained, 0 if all
- buffers where obtained from the 'from' list and if non-zero then
- the number of stolen buffers is returned. */
-static int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
- struct cx18_queue *steal, struct cx18_queue *to,
- int needed_bytes)
+/* Move all buffers of a queue to q_free, while flushing the buffers */
+static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
{
unsigned long flags;
- int rc = 0;
- int from_free = from == &s->q_free;
- int to_free = to == &s->q_free;
- int bytes_available;
-
- spin_lock_irqsave(&s->qlock, flags);
- if (needed_bytes == 0) {
- from_free = 1;
- needed_bytes = from->length;
- }
-
- bytes_available = from_free ? from->length : from->bytesused;
- bytes_available += steal ? steal->length : 0;
+ struct cx18_buffer *buf;
- if (bytes_available < needed_bytes) {
- spin_unlock_irqrestore(&s->qlock, flags);
- return -ENOMEM;
- }
- if (from_free) {
- u32 old_length = to->length;
+ if (q == &s->q_free)
+ return;
- while (to->length - old_length < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- cx18_queue_move_buf(s, from, to, 1, 0);
- }
- } else {
- u32 old_bytesused = to->bytesused;
-
- while (to->bytesused - old_bytesused < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- cx18_queue_move_buf(s, from, to, to_free, rc);
- }
+ spin_lock_irqsave(&s->qlock, flags);
+ while (!list_empty(&q->list)) {
+ buf = list_entry(q->list.next, struct cx18_buffer, list);
+ list_move_tail(q->list.next, &s->q_free.list);
+ buf->bytesused = buf->readpos = buf->b_flags = 0;
+ atomic_inc(&s->q_free.buffers);
}
+ cx18_queue_init(q);
spin_unlock_irqrestore(&s->qlock, flags);
- return rc;
}
void cx18_flush_queues(struct cx18_stream *s)
{
- cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
- cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+ cx18_queue_flush(s, &s->q_io);
+ cx18_queue_flush(s, &s->q_full);
}
int cx18_stream_alloc(struct cx18_stream *s)
diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c
index 911a97ce3..02a443104 100644
--- a/linux/drivers/media/video/cx18/cx18-streams.c
+++ b/linux/drivers/media/video/cx18/cx18-streams.c
@@ -119,7 +119,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->cx = cx;
s->type = type;
s->name = cx18_stream_info[type].name;
- s->handle = 0xffffffff;
+ s->handle = CX18_INVALID_TASK_HANDLE;
s->dma = cx18_stream_info[type].dma;
s->buf_size = cx->stream_buf_size[type];
@@ -432,7 +432,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
default:
return -EINVAL;
}
- s->buffers_stolen = 0;
/* mute/unmute video */
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
@@ -489,7 +488,14 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
/* begin_capture */
if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
CX18_DEBUG_WARN("Error starting capture!\n");
+ /* Ensure we're really not capturing before releasing MDLs */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
+ else
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
return -EINVAL;
}
@@ -568,6 +574,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
#endif
}
+ /* Tell the CX23418 it can't use our buffers anymore */
+ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+
if (s->type != CX18_ENC_STREAM_TYPE_TS)
atomic_dec(&cx->ana_capturing);
atomic_dec(&cx->tot_capturing);
@@ -576,7 +585,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
- s->handle = 0xffffffff;
+ s->handle = CX18_INVALID_TASK_HANDLE;
if (atomic_read(&cx->tot_capturing) > 0)
return 0;
@@ -595,8 +604,8 @@ u32 cx18_find_handle(struct cx18 *cx)
for (i = 0; i < CX18_MAX_STREAMS; i++) {
struct cx18_stream *s = &cx->streams[i];
- if (s->v4l2dev && s->handle)
+ if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE))
return s->handle;
}
- return 0;
+ return CX18_INVALID_TASK_HANDLE;
}
diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h
index e7ed05305..668f968d7 100644
--- a/linux/drivers/media/video/cx18/cx23418.h
+++ b/linux/drivers/media/video/cx18/cx23418.h
@@ -351,7 +351,7 @@
Descriptor Lists to the driver
IN[0] - Task handle. Handle of the task to start
ReturnCode - One of the ERR_DE_... */
-/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */
+#define CX18_CPU_DE_RELEASE_MDL (CPU_CMD_MASK_DE | 0x0006)
/* Description: This command signals the cpu that the dat buffer has been
consumed and ready for re-use.