The patch number 8775 was added via Mauro Carvalho Chehab <[EMAIL PROTECTED]> to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward compatible with older kernels. Compatibility modifications will be removed before inclusion into the mainstream Kernel If anyone has any objections, please let us know by sending a message to: [EMAIL PROTECTED] ------ From: Mauro Carvalho Chehab <[EMAIL PROTECTED]> merge: http://linuxtv.org/hg/~awalls/v4l-dvb Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]> --- linux/drivers/media/video/cx18/cx18-driver.h | 6 linux/drivers/media/video/cx18/cx18-fileops.c | 51 +++++-- linux/drivers/media/video/cx18/cx18-ioctl.c | 20 ++ linux/drivers/media/video/cx18/cx18-mailbox.c | 1 linux/drivers/media/video/cx18/cx18-queue.c | 122 +++--------------- linux/drivers/media/video/cx18/cx18-streams.c | 21 ++- linux/drivers/media/video/cx18/cx23418.h | 2 7 files changed, 95 insertions(+), 128 deletions(-) diff -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-driver.h --- a/linux/drivers/media/video/cx18/cx18-driver.h Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-driver.h Fri Aug 29 14:50:35 2008 -0300 @@ -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; /* forward reference */ 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-fileops.c --- a/linux/drivers/media/video/cx18/cx18-fileops.c Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-fileops.c Fri Aug 29 14:50:35 2008 -0300 @@ -132,6 +132,7 @@ static void cx18_dualwatch(struct cx18 * 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 * if (new_stereo_mode == cx->dualwatch_stereo_mode) return; - 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); - - if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, - cx18_find_handle(cx), new_bitmap) == 0) { + 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); + + 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_buff 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 f 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, 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-ioctl.c --- a/linux/drivers/media/video/cx18/cx18-ioctl.c Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c Fri Aug 29 14:50:35 2008 -0300 @@ -727,6 +727,7 @@ static int cx18_encoder_cmd(struct file { 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 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 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 * 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-mailbox.c --- a/linux/drivers/media/video/cx18/cx18-mailbox.c Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c Fri Aug 29 14:50:35 2008 -0300 @@ -82,6 +82,7 @@ static const struct cx18_api_info api_in 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-queue.c --- a/linux/drivers/media/video/cx18/cx18-queue.c Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-queue.c Fri Aug 29 14:50:35 2008 -0300 @@ -37,8 +37,7 @@ void cx18_queue_init(struct cx18_queue * 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, } 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 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_i /* 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_i 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) +/* 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; + struct cx18_buffer *buf; + + if (q == &s->q_free) + return; + + 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; - 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) -{ - 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; - - if (bytes_available < needed_bytes) { - spin_unlock_irqrestore(&s->qlock, flags); - return -ENOMEM; - } - if (from_free) { - u32 old_length = to->length; - - 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_unlock_irqrestore(&s->qlock, flags); - return rc; + atomic_inc(&s->q_free.buffers); + } + cx18_queue_init(q); + spin_unlock_irqrestore(&s->qlock, flags); } 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx18-streams.c --- a/linux/drivers/media/video/cx18/cx18-streams.c Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx18-streams.c Fri Aug 29 14:50:35 2008 -0300 @@ -119,7 +119,7 @@ static void cx18_stream_init(struct cx18 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 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 /* 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 #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 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 -r b3f843ea3306 -r 308121fcdc32 linux/drivers/media/video/cx18/cx23418.h --- a/linux/drivers/media/video/cx18/cx23418.h Fri Aug 29 14:46:21 2008 -0300 +++ b/linux/drivers/media/video/cx18/cx23418.h Fri Aug 29 14:50:35 2008 -0300 @@ -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. --- Patch is available at: http://linuxtv.org/hg/v4l-dvb/rev/308121fcdc3296c14bbf2a98d19cf3aee0638388 _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits