From 6751a7d4aab2b5bca085df2a0346e7d87724bede Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 16:36:09 +0200 Subject: ivtv: fix incorrect round-robin implementation From: Hans Verkuil Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index 65622c1e4..f7bcdf74c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -869,8 +869,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) @@ -887,8 +888,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) } if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) { + itv->irq_rr_idx++; for (i = 0; i < IVTV_MAX_STREAMS; i++) { - int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; + int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS; struct ivtv_stream *s = &itv->streams[idx]; if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) -- cgit v1.2.3 From 28d6ba2f6c58a46a520e1323a0fe8170948bf5fc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 16:39:28 +0200 Subject: vp27smpx: clarify history of this source. From: Kazuhiko Kawakami Signed-off-by: Kazuhiko Kawakami Signed-off-by: Hans Verkuil --- linux/drivers/media/video/vp27smpx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux/drivers/media/video/vp27smpx.c b/linux/drivers/media/video/vp27smpx.c index 346d14cb8..3793930fe 100644 --- a/linux/drivers/media/video/vp27smpx.c +++ b/linux/drivers/media/video/vp27smpx.c @@ -3,7 +3,8 @@ * * Copyright (C) 2007 Hans Verkuil * - * Based on a tvaudio patch from Kazuhiko Kawakami + * Based on a tvaudio patch from Takahiro Adachi + * and Kazuhiko Kawakami * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From 23c9830c96f5c9ee0b845bd48efd5fc70356d83f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 16:46:05 +0200 Subject: ivtv: fix handling of INITIALIZE_INPUT fw call From: Hans Verkuil The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling, otherwise the computer can freeze or the top-third of the screen can start flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called at the right time and in the right way. In addition the stop capture handling was improved so that the last pending DMA transfer is also processed. Otherwise this would be the first data that arrived when a new capture was started which is not what you want. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-fileops.c | 19 ++++++++++-------- linux/drivers/media/video/ivtv/ivtv-ioctl.c | 3 +++ linux/drivers/media/video/ivtv/ivtv-streams.c | 28 +++++---------------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index 8ce2edf8a..eb6339674 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -888,12 +888,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -EBUSY; } + if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + if (atomic_read(&itv->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + kfree(item); + return -EBUSY; + } + } + /* Mark that the radio is being used. */ + set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* We have the radio */ ivtv_mute(itv); /* Switch tuner to radio */ ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); - /* Mark that the radio is being used. */ - set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); /* Select the correct audio input (i.e. radio tuner) */ ivtv_audio_set_io(itv); if (itv->hw_flags & IVTV_HW_SAA711X) @@ -927,13 +935,8 @@ void ivtv_mute(struct ivtv *itv) void ivtv_unmute(struct ivtv *itv) { - /* initialize or refresh input */ - if (atomic_read(&itv->capturing) == 0) - ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); - if (atomic_read(&itv->capturing)) { + ivtv_msleep_timeout(100, 0); ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); } diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 7d1a5e434..9a0c3df8d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -912,6 +912,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void IVTV_DEBUG_INFO("Input unchanged\n"); break; } + if (atomic_read(&itv->capturing) > 0) { + return -EBUSY; + } IVTV_DEBUG_INFO("Changing input from %d to %d\n", itv->active_input, inp); diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 405e2e3fc..0582b9d57 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ + itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - - ivtv_msleep_timeout(100, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, 0); } /* begin_capture */ @@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) int cap_type; unsigned long then; int stopmode; - u32 data[CX2341X_MBOX_MAX_DATA]; if (s->v4l2dev == NULL) return -EINVAL; @@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } then = jiffies; - /* Make sure DMA is complete */ - add_wait_queue(&s->waitq, &wait); - do { - /* check if DMA is pending */ - if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ - (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { - /* Check for last DMA */ - ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); - - if (data[0] == 1) { - IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); - break; - } - } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { - break; - } - } while (!ivtv_msleep_timeout(10, 1) && - then + msecs_to_jiffies(2000) > jiffies); - set_current_state(TASK_RUNNING); - remove_wait_queue(&s->waitq, &wait); + /* Handle any pending interrupts */ + ivtv_msleep_timeout(100, 1); } atomic_dec(&itv->capturing); -- cgit v1.2.3 From fe63b013b5d4c0822f2cb6868de131e3c62dcc35 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Jul 2007 17:07:12 +0200 Subject: ivtv: always steal full frames if out of buffers. From: Hans Verkuil When there are no more free buffers, then buffers are stolen from the predma queue. Buffers should be stolen from the head of that queue (which is where the most recently added buffers are) and all buffers belonging to a frame should be stolen. Otherwise 'half-frames' would remain in the queue, which leads to ugly playback and complete sync failure for YUV buffers. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.h | 9 ++++- linux/drivers/media/video/ivtv/ivtv-fileops.c | 3 +- linux/drivers/media/video/ivtv/ivtv-irq.c | 5 ++- linux/drivers/media/video/ivtv/ivtv-queue.c | 54 ++++++++++++++++----------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 3b8c839d9..2e8c937e1 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -362,7 +362,7 @@ struct ivtv_mailbox_data { }; /* per-buffer bit flags */ -#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ +#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */ /* per-stream, s_flags */ #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ @@ -447,7 +447,8 @@ struct ivtv_dma_page_info { struct ivtv_buffer { struct list_head list; dma_addr_t dma_handle; - unsigned long b_flags; + unsigned short b_flags; + unsigned short dma_xfer_cnt; char *buf; u32 bytesused; @@ -497,6 +498,10 @@ struct ivtv_stream { struct ivtv_queue q_dma; /* waiting for DMA */ struct ivtv_queue q_predma; /* waiting for DMA */ + /* DMA xfer counter, buffers belonging to the same DMA + xfer will have the same dma_xfer_cnt. */ + u16 dma_xfer_cnt; + /* Base Dev SG Array for cx23415/6 */ struct ivtv_SG_element *SGarray; struct ivtv_SG_element *PIOarray; diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index eb6339674..82c60c28b 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -245,8 +245,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, /* do we have new data? */ buf = ivtv_dequeue(s, &s->q_full); if (buf) { - if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) + if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) return buf; + buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; if (s->type == IVTV_ENC_STREAM_TYPE_MPG) /* byteswap MPG data */ ivtv_buf_swap(buf); diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index f7bcdf74c..32ceedf07 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -220,6 +220,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->SGarray[idx].src = cpu_to_le32(offset); s->SGarray[idx].size = cpu_to_le32(s->buf_size); buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; size -= buf->bytesused; @@ -292,7 +293,7 @@ static void dma_post(struct ivtv_stream *s) /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ if (s->type == IVTV_ENC_STREAM_TYPE_MPG || s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); + buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; } if (buf) buf->bytesused += s->dma_last_offset; @@ -402,12 +403,14 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) } itv->vbi.dma_offset = s_vbi->dma_offset; s_vbi->SG_length = 0; + s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } /* Mark last buffer size for Interrupt flag */ s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->dma_xfer_cnt++; if (s->type == IVTV_ENC_STREAM_TYPE_VBI) set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c index a04f9387f..bff75aeee 100644 --- a/linux/drivers/media/video/ivtv/ivtv-queue.c +++ b/linux/drivers/media/video/ivtv/ivtv-queue.c @@ -60,6 +60,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; + buf->dma_xfer_cnt = 0; } spin_lock_irqsave(&s->qlock, flags); list_add_tail(&buf->list, &q->list); @@ -87,7 +88,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) } static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, - struct ivtv_queue *to, int clear, int full) + struct ivtv_queue *to, int clear) { struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); @@ -97,13 +98,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, 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; - } + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; to->buffers++; to->length += s->buf_size; to->bytesused += buf->bytesused - buf->readpos; @@ -112,7 +107,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, /* 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. + needed, but only if 'from' is the free queue. 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 @@ -133,7 +128,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ int rc = 0; int from_free = from == &s->q_free; int to_free = to == &s->q_free; - int bytes_available; + int bytes_available, bytes_steal; spin_lock_irqsave(&s->qlock, flags); if (needed_bytes == 0) { @@ -142,32 +137,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_ } bytes_available = from_free ? from->length : from->bytesused; - bytes_available += steal ? steal->length : 0; + bytes_steal = (from_free && steal) ? steal->length : 0; - if (bytes_available < needed_bytes) { + if (bytes_available + bytes_steal < needed_bytes) { spin_unlock_irqrestore(&s->qlock, flags); return -ENOMEM; } + while (bytes_available < needed_bytes) { + struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + u16 dma_xfer_cnt = buf->dma_xfer_cnt; + + /* move buffers from the tail of the 'steal' queue to the tail of the + 'from' queue. Always copy all the buffers with the same dma_xfer_cnt + value, this ensures that you do not end up with partial frame data + if one frame is stored in multiple buffers. */ + while (dma_xfer_cnt == buf->dma_xfer_cnt) { + list_move_tail(steal->list.prev, &from->list); + rc++; + steal->buffers--; + steal->length -= s->buf_size; + steal->bytesused -= buf->bytesused - buf->readpos; + buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0; + from->buffers++; + from->length += s->buf_size; + bytes_available += s->buf_size; + if (list_empty(&steal->list)) + break; + buf = list_entry(steal->list.prev, struct ivtv_buffer, list); + } + } 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 */ - ivtv_queue_move_buf(s, from, to, 1, 0); + ivtv_queue_move_buf(s, from, to, 1); } } 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 */ - ivtv_queue_move_buf(s, from, to, to_free, rc); + ivtv_queue_move_buf(s, from, to, to_free); } } spin_unlock_irqrestore(&s->qlock, flags); -- cgit v1.2.3 From 4fcf11d4d6be97e5d2d4829f7a8af18205289d04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 29 Jul 2007 00:45:50 +0200 Subject: ivtv: Fix scatter/gather DMA timeouts From: Hans Verkuil It turns out that the cx23415/6 DMA engine cannot do scatter/gather DMA reliably. Every so often depending on the phase of the moon and your hardware configuration the cx2341x DMA engine simply chokes on it and you have to reboot to get it working again. This change replaced the scatter/gather DMA by single transfers at a time, where the driver is now responsible for DMA-ing each buffer. UDMA is still done using scatter/gather DMA, that will be fixed soon. Many thanks to Mark Bryars for discovering the link between scatter/gather and the DMA timeouts. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.h | 22 ++- linux/drivers/media/video/ivtv/ivtv-irq.c | 234 ++++++++++++++++---------- linux/drivers/media/video/ivtv/ivtv-queue.c | 63 ++++--- linux/drivers/media/video/ivtv/ivtv-queue.h | 8 +- linux/drivers/media/video/ivtv/ivtv-streams.c | 2 +- 5 files changed, 196 insertions(+), 133 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 2e8c937e1..8c5b452a3 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -388,7 +388,6 @@ struct ivtv_mailbox_data { #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ -#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ @@ -411,7 +410,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ /* Scatter-Gather array element, used in DMA transfers */ -struct ivtv_SG_element { +struct ivtv_sg_element { u32 src; u32 dst; u32 size; @@ -427,7 +426,7 @@ struct ivtv_user_dma { struct page *map[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; + struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; dma_addr_t SG_handle; int SG_length; @@ -478,6 +477,10 @@ struct ivtv_stream { int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ + u32 pending_offset; + u32 pending_backup; + u64 pending_pts; + u32 dma_offset; u32 dma_backup; u64 dma_pts; @@ -503,10 +506,13 @@ struct ivtv_stream { u16 dma_xfer_cnt; /* Base Dev SG Array for cx23415/6 */ - struct ivtv_SG_element *SGarray; - struct ivtv_SG_element *PIOarray; - dma_addr_t SG_handle; - int SG_length; + struct ivtv_sg_element *sg_pending; + struct ivtv_sg_element *sg_processing; + struct ivtv_sg_element *sg_dma; + dma_addr_t sg_handle; + int sg_pending_size; + int sg_processing_size; + int sg_processed; /* SG List of Buffers */ struct scatterlist *SGlist; @@ -647,7 +653,6 @@ struct vbi_info { u32 enc_start, enc_size; int fpi; u32 frame; - u32 dma_offset; u8 cc_data_odd[256]; u8 cc_data_even[256]; int cc_pos; @@ -734,6 +739,7 @@ struct ivtv { int cur_pio_stream; /* index of stream doing PIO */ u32 dma_data_req_offset; u32 dma_data_req_size; + int dma_retries; int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ spinlock_t lock; /* lock access to this struct */ int search_pack_header; diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index 32ceedf07..fc4f8048f 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -60,18 +60,18 @@ static void ivtv_pio_work_handler(struct ivtv *itv) buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list); list_for_each(p, &s->q_dma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); - u32 size = s->PIOarray[i].size & 0x3ffff; + u32 size = s->sg_processing[i].size & 0x3ffff; /* Copy the data from the card to the buffer */ if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size); + memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size); } else { - memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size); + memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); } - if (s->PIOarray[i].size & 0x80000000) - break; i++; + if (i == s->sg_processing_size) + break; } write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); } @@ -111,7 +111,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA u32 offset, size; u32 UVoffset = 0, UVsize = 0; int skip_bufs = s->q_predma.buffers; - int idx = s->SG_length; + int idx = s->sg_pending_size; int rc; /* sanity checks */ @@ -129,7 +129,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA case IVTV_ENC_STREAM_TYPE_MPG: offset = data[1]; size = data[2]; - s->dma_pts = 0; + s->pending_pts = 0; break; case IVTV_ENC_STREAM_TYPE_YUV: @@ -137,13 +137,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA size = data[2]; UVoffset = data[3]; UVsize = data[4]; - s->dma_pts = ((u64) data[5] << 32) | data[6]; + s->pending_pts = ((u64) data[5] << 32) | data[6]; break; case IVTV_ENC_STREAM_TYPE_PCM: offset = data[1] + 12; size = data[2] - 12; - s->dma_pts = read_dec(offset - 8) | + s->pending_pts = read_dec(offset - 8) | ((u64)(read_dec(offset - 12)) << 32); if (itv->has_cx23415) offset += IVTV_DECODER_OFFSET; @@ -156,13 +156,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA IVTV_DEBUG_INFO("VBI offset == 0\n"); return -1; } - s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); + s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); break; case IVTV_DEC_STREAM_TYPE_VBI: size = read_dec(itv->vbi.dec_start + 4) + 8; offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; - s->dma_pts = 0; + s->pending_pts = 0; offset += IVTV_DECODER_OFFSET; break; default: @@ -171,17 +171,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->SG_length == 0) { + if (s->sg_pending_size == 0) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); + s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); } else { - s->dma_backup = read_enc(offset); + s->pending_backup = read_enc(offset); write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); } - s->dma_offset = offset; + s->pending_offset = offset; } bytes_needed = size; @@ -208,7 +208,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } s->buffers_stolen = rc; - /* got the buffers, now fill in SGarray (DMA) */ + /* got the buffers, now fill in sg_pending */ buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); memset(buf->buf, 0, 128); list_for_each(p, &s->q_predma.list) { @@ -216,9 +216,9 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (skip_bufs-- > 0) continue; - s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].src = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(s->buf_size); + s->sg_pending[idx].dst = buf->dma_handle; + s->sg_pending[idx].src = offset; + s->sg_pending[idx].size = s->buf_size; buf->bytesused = (size < s->buf_size) ? size : s->buf_size; buf->dma_xfer_cnt = s->dma_xfer_cnt; @@ -236,7 +236,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } idx++; } - s->SG_length = idx; + s->sg_pending_size = idx; return 0; } @@ -338,9 +338,9 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) offset = uv_offset; y_done = 1; } - s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); - s->SGarray[idx].dst = cpu_to_le32(offset); - s->SGarray[idx].size = cpu_to_le32(buf->bytesused); + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; offset += buf->bytesused; bytes_written += buf->bytesused; @@ -349,10 +349,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) ivtv_buf_sync_for_device(s, buf); idx++; } - s->SG_length = idx; - - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); + s->sg_pending_size = idx; /* Sync Hardware SG List of buffers */ ivtv_stream_sync_for_device(s); @@ -368,6 +365,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) spin_unlock_irqrestore(&itv->dma_reg_lock, flags); } +static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); +} + +static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) +{ + struct ivtv *itv = s->itv; + + s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src); + s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst); + s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000); + s->sg_processed++; + /* Sync Hardware SG List of buffers */ + ivtv_stream_sync_for_device(s); + write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); + write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); +} + /* start the encoder DMA */ static void ivtv_dma_enc_start(struct ivtv_stream *s) { @@ -381,8 +406,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); if (ivtv_use_dma(s)) - s->SGarray[s->SG_length - 1].size = - cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); + s->sg_pending[s->sg_pending_size - 1].size += 256; /* If this is an MPEG stream, and VBI data is also pending, then append the VBI DMA to the MPEG DMA and transfer both sets of data at once. @@ -393,45 +417,39 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) sure we only use the MPEG DMA to transfer the VBI DMA if both are in use. This way no conflicts occur. */ clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && - s->SG_length + s_vbi->SG_length <= s->buffers) { + if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size && + s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) { ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); if (ivtv_use_dma(s_vbi)) - s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); - for (i = 0; i < s_vbi->SG_length; i++) { - s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; + s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256; + for (i = 0; i < s_vbi->sg_pending_size; i++) { + s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i]; } - itv->vbi.dma_offset = s_vbi->dma_offset; - s_vbi->SG_length = 0; + s_vbi->dma_offset = s_vbi->pending_offset; + s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } - /* Mark last buffer size for Interrupt flag */ - s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); s->dma_xfer_cnt++; - - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) - set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); - else - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + s->dma_offset = s->pending_offset; + s->dma_backup = s->pending_backup; + s->dma_pts = s->pending_pts; if (ivtv_use_pio(s)) { - for (i = 0; i < s->SG_length; i++) { - s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src); - s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size); - } set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); set_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = s->type; } else { - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_enc_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -445,10 +463,15 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s) if (s->q_predma.bytesused) ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); + s->dma_xfer_cnt++; + memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size); + s->sg_processing_size = s->sg_pending_size; + s->sg_pending_size = 0; + s->sg_processed = 0; + IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name); - /* put SG Handle into register 0x0c */ - write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); - write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); + itv->dma_retries = 0; + ivtv_dma_dec_start_xfer(s); set_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = s->type; itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); @@ -459,27 +482,42 @@ static void ivtv_irq_dma_read(struct ivtv *itv) { struct ivtv_stream *s = NULL; struct ivtv_buffer *buf; - int hw_stream_type; + int hw_stream_type = 0; IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - del_timer(&itv->dma_timer); - if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { - IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); + return; } + if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - hw_stream_type = 2; + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + + if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { + IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n", + read_reg(IVTV_REG_DMASTATUS), + s->sg_processed, s->sg_processing_size, itv->dma_retries); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } } - else { - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - hw_stream_type = 0; + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_dec_start_xfer(s); + return; } + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + hw_stream_type = 2; IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); - ivtv_stream_sync_for_cpu(s); - /* For some reason must kick the firmware, like PIO mode, I think this tells the firmware we are done and the size of the xfer so it can calculate what we need next. @@ -496,6 +534,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv) } wake_up(&s->waitq); } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -507,33 +546,44 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; - del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); - if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) - data[1] = 3; - else if (data[1] > 2) + IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); + if (itv->cur_dma_stream < 0) { + del_timer(&itv->dma_timer); return; - s = &itv->streams[ivtv_stream_map[data[1]]]; + } + s = &itv->streams[itv->cur_dma_stream]; + ivtv_stream_sync_for_cpu(s); + if (data[0] & 0x18) { - IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); + IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0], + s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); + if (itv->dma_retries == 3) { + itv->dma_retries = 0; + } + else { + /* Retry, starting with the first xfer segment. + Just retrying the current segment is not sufficient. */ + s->sg_processed = 0; + itv->dma_retries++; + } } - s->SG_length = 0; + if (s->sg_processed < s->sg_processing_size) { + /* DMA next buffer */ + ivtv_dma_enc_start_xfer(s); + return; + } + del_timer(&itv->dma_timer); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; dma_post(s); - ivtv_stream_sync_for_cpu(s); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } + s->sg_processing_size = 0; + s->sg_processed = 0; wake_up(&itv->dma_waitq); } @@ -547,8 +597,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->SG_length = 0; - clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); + s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); @@ -560,13 +609,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2); clear_bit(IVTV_F_I_PIO, &itv->i_flags); if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - u32 tmp; - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - tmp = s->dma_offset; - s->dma_offset = itv->vbi.dma_offset; dma_post(s); - s->dma_offset = tmp; } wake_up(&itv->dma_waitq); } @@ -578,19 +622,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv) del_timer(&itv->dma_timer); ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); + write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; /* retry */ - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) ivtv_dma_dec_start(s); else ivtv_dma_enc_start(s); return; } + if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { + ivtv_udma_start(itv); + return; + } clear_bit(IVTV_F_I_UDMA, &itv->i_flags); clear_bit(IVTV_F_I_DMA, &itv->i_flags); itv->cur_dma_stream = -1; @@ -634,14 +682,14 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) DMA the data. Since at most four VBI DMA buffers are available, we just drop the old requests when there are already three requests queued. */ - if (s->SG_length > 2) { + if (s->sg_pending_size > 2) { struct list_head *p; list_for_each(p, &s->q_predma.list) { struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); ivtv_buf_sync_for_cpu(s, buf); } ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->SG_length = 0; + s->sg_pending_size = 0; } /* if we can append the data, and the MPEG stream isn't capturing, then start a DMA request for just the VBI data. */ diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.c b/linux/drivers/media/video/ivtv/ivtv-queue.c index bff75aeee..d9a1478ca 100644 --- a/linux/drivers/media/video/ivtv/ivtv-queue.c +++ b/linux/drivers/media/video/ivtv/ivtv-queue.c @@ -195,7 +195,7 @@ void ivtv_flush_queues(struct ivtv_stream *s) int ivtv_stream_alloc(struct ivtv_stream *s) { struct ivtv *itv = s->itv; - int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; + int SGsize = sizeof(struct ivtv_sg_element) * s->buffers; int i; if (s->buffers == 0) @@ -205,27 +205,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s) s->dma != PCI_DMA_NONE ? "DMA " : "", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (ivtv_might_use_pio(s)) { - s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->PIOarray == NULL) { - IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name); - return -ENOMEM; - } + s->sg_pending = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_pending == NULL) { + IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name); + return -ENOMEM; } + s->sg_pending_size = 0; - /* Allocate DMA SG Arrays */ - s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); - if (s->SGarray == NULL) { - IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); - if (ivtv_might_use_pio(s)) { - kfree(s->PIOarray); - s->PIOarray = NULL; - } + s->sg_processing = (struct ivtv_sg_element *)kzalloc(SGsize, GFP_KERNEL); + if (s->sg_processing == NULL) { + IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + return -ENOMEM; + } + s->sg_processing_size = 0; + + s->sg_dma = (struct ivtv_sg_element *)kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL); + if (s->sg_dma == NULL) { + IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name); + kfree(s->sg_pending); + s->sg_pending = NULL; + kfree(s->sg_processing); + s->sg_processing = NULL; return -ENOMEM; } - s->SG_length = 0; if (ivtv_might_use_dma(s)) { - s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); + s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma); ivtv_stream_sync_for_cpu(s); } @@ -272,16 +278,19 @@ void ivtv_stream_free(struct ivtv_stream *s) } /* Free SG Array/Lists */ - if (s->SGarray != NULL) { - if (s->SG_handle != IVTV_DMA_UNMAPPED) { - pci_unmap_single(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); - s->SG_handle = IVTV_DMA_UNMAPPED; + if (s->sg_dma != NULL) { + if (s->sg_handle != IVTV_DMA_UNMAPPED) { + pci_unmap_single(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); + s->sg_handle = IVTV_DMA_UNMAPPED; } - kfree(s->SGarray); - kfree(s->PIOarray); - s->PIOarray = NULL; - s->SGarray = NULL; - s->SG_length = 0; + kfree(s->sg_pending); + kfree(s->sg_processing); + kfree(s->sg_dma); + s->sg_pending = NULL; + s->sg_processing = NULL; + s->sg_dma = NULL; + s->sg_pending_size = 0; + s->sg_processing_size = 0; } } diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.h b/linux/drivers/media/video/ivtv/ivtv-queue.h index 2ed8d5482..14a9f7fe5 100644 --- a/linux/drivers/media/video/ivtv/ivtv-queue.h +++ b/linux/drivers/media/video/ivtv/ivtv-queue.h @@ -79,13 +79,13 @@ void ivtv_stream_free(struct ivtv_stream *s); static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) { if (ivtv_use_dma(s)) - pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, - sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle, + sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE); } diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 0582b9d57..d1cc366c2 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -154,7 +154,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; - s->SG_handle = IVTV_DMA_UNMAPPED; + s->sg_handle = IVTV_DMA_UNMAPPED; ivtv_queue_init(&s->q_free); ivtv_queue_init(&s->q_full); ivtv_queue_init(&s->q_dma); -- cgit v1.2.3 From d9dfbb9adf32defc0309c29ce0267d28b7d5de38 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 29 Jul 2007 20:22:05 +0200 Subject: ivtv: fix stop stream locking. From: Hans Verkuil Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-streams.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index d1cc366c2..4272fbc0b 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -751,6 +751,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } + /* ensure these actions are done only once */ + mutex_lock(&itv->serialize_lock); + /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -803,9 +806,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(IVTV_F_S_STREAMING, &s->s_flags); - /* ensure these global cleanup actions are done only once */ - mutex_lock(&itv->serialize_lock); - if (s->type == IVTV_ENC_STREAM_TYPE_VBI) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); -- cgit v1.2.3 From cfc5c4e6bc9c0c61bb5696b0198117b9d34ddc3f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 20:16:00 +0200 Subject: ivtv: fix VBI reinsertion decoding From: Hans Verkuil - Invalid VBI packets should result in an empty VBI frame, not in an zero-sized frame that causes the reader to incorrectly return a 0 (EOF) value. - PIO completion should not reset the sg_pending_size field. - The DMA offset detection code should be ignored for PIO transfers: it somehow messes up the data on the card and is not needed anyway for PIO. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-irq.c | 5 ++--- linux/drivers/media/video/ivtv/ivtv-vbi.c | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index fc4f8048f..f6f9e490b 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -171,7 +171,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA } /* if this is the start of the DMA then fill in the magic cookie */ - if (s->sg_pending_size == 0) { + if (s->sg_pending_size == 0 && ivtv_use_dma(s)) { if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); @@ -258,7 +258,7 @@ static void dma_post(struct ivtv_stream *s) /* Sync Buffer */ ivtv_buf_sync_for_cpu(s, buf); - if (x == 0) { + if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) { @@ -597,7 +597,6 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv) } s = &itv->streams[itv->cur_pio_stream]; IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - s->sg_pending_size = 0; clear_bit(IVTV_F_I_PIO, &itv->i_flags); itv->cur_pio_stream = -1; dma_post(s); diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c index a7282a91b..a58c833c2 100644 --- a/linux/drivers/media/video/ivtv/ivtv-vbi.c +++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c @@ -163,8 +163,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) linemask[1] = 0xf; p += 4; } else { - /* unknown VBI data stream */ - return 0; + /* unknown VBI data, convert to empty VBI frame */ + linemask[0] = linemask[1] = 0; } for (i = 0; i < 36; i++) { int err = 0; -- cgit v1.2.3 From 1e0fb811716f6d1e429f43701e30d4ca10e142db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 20:48:42 +0200 Subject: ivtv: retry/timer improvements From: Hans Verkuil - Give up frame after three retries. - When the last capture/decode ends, make sure to delete the dma_timer. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-irq.c | 4 ++++ linux/drivers/media/video/ivtv/ivtv-streams.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index f6f9e490b..365176612 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -500,7 +500,9 @@ static void ivtv_irq_dma_read(struct ivtv *itv) s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. @@ -560,7 +562,9 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv) s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries); write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); if (itv->dma_retries == 3) { + /* Too many retries, give up on this frame */ itv->dma_retries = 0; + s->sg_processed = s->sg_processing_size; } else { /* Retry, starting with the first xfer segment. diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 4272fbc0b..2e632014c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -816,6 +816,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) /* Set the following Interrupt mask bits for capture */ ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); + del_timer(&itv->dma_timer); /* event notification (off) */ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { @@ -873,6 +874,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); + del_timer(&itv->dma_timer); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); clear_bit(IVTV_F_S_STREAMING, &s->s_flags); -- cgit v1.2.3 From 10d95c49de7046635946793e094e6f76dfeadd5c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 Aug 2007 12:16:07 +0200 Subject: cx25840: make proper use of SOFT_RESET. From: Hans Verkuil Whenever the 0x80b register is used the microcontroller should be reset. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/cx25840/cx25840-audio.c | 22 ++++++++++------------ linux/drivers/media/video/cx25840/cx25840-core.c | 7 ++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/linux/drivers/media/video/cx25840/cx25840-audio.c b/linux/drivers/media/video/cx25840/cx25840-audio.c index 6266e5ccf..34ad90469 100644 --- a/linux/drivers/media/video/cx25840/cx25840-audio.c +++ b/linux/drivers/media/video/cx25840/cx25840-audio.c @@ -161,13 +161,12 @@ void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = i2c_get_clientdata(client); + /* assert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x01); + /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); - /* assert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x01); - /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); @@ -185,15 +184,14 @@ void cx25840_audio_set_path(struct i2c_client *client) set_audclk_freq(client, state->audclk_freq); - /* deassert soft reset */ - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0x00); - if (state->aud_input != CX25840_AUDIO_SERIAL) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } + + /* deassert soft reset */ + cx25840_and_or(client, 0x810, ~0x1, 0x00); } static int get_volume(struct i2c_client *client) @@ -334,18 +332,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 1); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0); cx25840_write(client, 0x8d3, 0x1f); } - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 1); retval = set_audclk_freq(client, *(u32 *)arg); - if (!state->is_cx25836) - cx25840_and_or(client, 0x810, ~0x1, 0); if (state->aud_input != CX25840_AUDIO_SERIAL) { cx25840_and_or(client, 0x803, ~0x10, 0x10); } + if (!state->is_cx25836) + cx25840_and_or(client, 0x810, ~0x1, 0); return retval; case VIDIOC_G_CTRL: diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index 640ac9bdb..49b43f2a1 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -261,6 +261,7 @@ static void input_change(struct i2c_client *client) } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); + cx25840_and_or(client, 0x810, ~0x01, 1); if (state->radio) { cx25840_write(client, 0x808, 0xf9); @@ -295,11 +296,7 @@ static void input_change(struct i2c_client *client) cx25840_write(client, 0x80b, 0x10); } - if (cx25840_read(client, 0x803) & 0x10) { - /* restart audio decoder microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } + cx25840_and_or(client, 0x810, ~0x01, 0); } static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, -- cgit v1.2.3 From 6c093022de6610694c4b629afcdf18201a4cbadc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 18 Aug 2007 20:58:51 +0200 Subject: ivtv: fix udma yuv bug From: Ian Armstrong Using udma yuv causes the driver becomes locked into that mode. This prevents use of the mpeg decoder & non-udma yuv output. This patch clears the operating mode when the device is closed. Signed-off-by: Ian Armstrong Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-fileops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index 82c60c28b..b2ff2488d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -753,9 +753,11 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) ivtv_yuv_close(itv); } if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) - itv->output_mode = OUT_NONE; + itv->output_mode = OUT_NONE; + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV) + itv->output_mode = OUT_NONE; else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) - itv->output_mode = OUT_NONE; + itv->output_mode = OUT_NONE; itv->speed = 0; clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); -- cgit v1.2.3 From 32e56900143835f0987500c4181a1f4cdf5bd11c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 19 Aug 2007 04:05:54 -0400 Subject: b2c2-flexcop: fix Airstar HD5000 tuning regression From: Trent Piepho Git changeset 6bdcc6e6dbab8daffd05e5026486f34ba41a6c72 dropped the stand-alone lgh06xf module, whose functionality was absorbed into the dvb-pll module. However, there was a minor difference between the code in lgh06xf and dvb-pll, which caused a regression in b2c2-flexcop devices using the LG-H06xF NIM. dvb-pll will probe for the presence of an i2c pll chip by performing a single byte read, the lgh06xf driver did not do this. Unfortunately, the code in flexcop-i2c.c does not currently support 1 byte or 0 byte reads as a probe. Such probes with the current code will always fail. In order to work around this problem, and restore proper functionality of the Airstar HD5000 device, this hack was created to make the probe appear to succeed. The single byte read in dvb_pll_attach is the only place where such a probe would ever occur, so this change is safe, and will not affect any other devices. Of course, if one knew how to actually perform the read operation, it would be better to go that route. In the meantime, however, we must apply this workaround, in order to prevent the regression that causes tuning to fail on the Airstar HD5000 ATSC device. Thanks to Jarod Wilson, who had originally reported this regression, and to Geoffrey Hausheer, whose original workaround patch led us to find the actual cause of the problem. Signed-off-by: Trent Piepho Acked-by: Jarod Wilson Cc: Geoffrey Hausheer Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/b2c2/flexcop-i2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c index 02a0ea6e1..6bf858a43 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -135,6 +135,13 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs struct flexcop_device *fc = i2c_get_adapdata(i2c_adap); int i, ret = 0; + /* Some drivers use 1 byte or 0 byte reads as probes, which this + * driver doesn't support. These probes will always fail, so this + * hack makes them always succeed. If one knew how, it would of + * course be better to actually do the read. */ + if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1) + return 1; + if (mutex_lock_interruptible(&fc->i2c_mutex)) return -ERESTARTSYS; -- cgit v1.2.3 From ff6ea73d1cd8b7198aece33161303d835a4599d0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 10:09:37 +0200 Subject: ivtv: setup TV output standard on init to prevent flicker From: Hans Verkuil The TV output standard was set only on first use, which meant that the saa7127 was set to NTSC until then, leading to flickering on PAL systems. Since the saa7127 has no firmware it is OK to initialize it immediately. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index 621d830e9..7aa8d1cc9 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -1149,6 +1149,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, are not. */ itv->tuner_std = itv->std; + if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); + } + retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); -- cgit v1.2.3 From ced78b0ce0549dfd374d3d22144897d6b9c3d8aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 10:32:33 +0200 Subject: ivtv: specify some stream sizes in kB instead of MB From: Hans Verkuil Some streams (PCM, VBI decoding) do not need that much memory, so specify the allocated memory in kB instead of MB to limit memory usage. E.g. 1 MB is overkill for the VBI decoding stream, 64 kB is enough. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.c | 18 +++++++++--------- linux/drivers/media/video/ivtv/ivtv-driver.h | 8 +++++--- linux/drivers/media/video/ivtv/ivtv-streams.c | 14 +++++++------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index 7aa8d1cc9..619efb5f3 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -208,7 +208,7 @@ MODULE_PARM_DESC(enc_vbi_buffers, "Encoder VBI Buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); MODULE_PARM_DESC(dec_mpg_buffers, "Decoder MPG buffers (in MB)\n" @@ -217,7 +217,7 @@ MODULE_PARM_DESC(dec_yuv_buffers, "Decoder YUV buffers (in MB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); MODULE_PARM_DESC(dec_vbi_buffers, - "Decoder VBI buffers (in MB)\n" + "Decoder VBI buffers (in kB)\n" "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); MODULE_PARM_DESC(newi2c, "Use new I2C implementation\n" @@ -547,13 +547,13 @@ static void ivtv_process_options(struct ivtv *itv) const char *chipname; int i, j; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; - itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024; + itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024; + itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; itv->options.cardtype = cardtype[itv->num]; itv->options.tuner = tuner[itv->num]; itv->options.radio = radio[itv->num]; diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 8c5b452a3..7ca9a775d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -192,10 +192,12 @@ extern const u32 yuv_offset[4]; #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 -#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 +/* Exception: size in kB for this stream (MB is overkill) */ +#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320 #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 -#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 +/* Exception: size in kB for this stream (MB is way overkill) */ +#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64 /* ======================================================================== */ /* ========================== END USER SETTABLE DMA VARIABLES ============= */ @@ -327,7 +329,7 @@ extern int ivtv_debug; struct ivtv_options { - int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ + int kilobytes[IVTV_MAX_STREAMS]; /* Size in kilobytes of each stream */ int cardtype; /* force card type on load */ int tuner; /* set tuner on load */ int radio; /* enable/disable radio */ diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 2e632014c..fab5c51b1 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -150,7 +150,7 @@ static void ivtv_stream_init(struct ivtv *itv, int type) s->dma = ivtv_stream_info[type].dma; s->buf_size = itv->stream_buf_size[type]; if (s->buf_size) - s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; + s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size; spin_lock_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; @@ -192,7 +192,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && - itv->options.megabytes[type] == 0) { + itv->options.kilobytes[type] == 0) { IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); return 0; } @@ -238,18 +238,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d MB)\n", - s->v4l2dev->minor, s->name, itv->options.megabytes[type]); + IVTV_INFO("Registered device video%d for %s (%d kB)\n", + s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: IVTV_INFO("Registered device radio%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); break; case VFL_TYPE_VBI: - if (itv->options.megabytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", + if (itv->options.kilobytes[type]) + IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, - s->name, itv->options.megabytes[type]); + s->name, itv->options.kilobytes[type]); else IVTV_INFO("Registered device vbi%d for %s\n", s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); -- cgit v1.2.3 From c3d804165d726f99515e40376d836ff879ec1631 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 11:08:58 +0200 Subject: ivtv: improve debug messages From: Hans Verkuil - add FILE debug flag for open/close/read/write/poll. - show cmd for encoder/decoder command ioctl. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.c | 18 +++++++-- linux/drivers/media/video/ivtv/ivtv-driver.h | 55 ++++++++++++++------------- linux/drivers/media/video/ivtv/ivtv-fileops.c | 18 +++++---- linux/drivers/media/video/ivtv/ivtv-ioctl.c | 9 ++++- linux/drivers/media/video/ivtv/ivtv-mailbox.c | 6 +-- 5 files changed, 64 insertions(+), 42 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index 619efb5f3..241c43b38 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -186,8 +186,18 @@ MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: errors only\n" - "\t\t\t(debug = 1023 gives full debugging)"); + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: ioctl\n" + "\t\t\t 16/0x0010: file\n" + "\t\t\t 32/0x0020: dma\n" + "\t\t\t 64/0x0040: irq\n" + "\t\t\t 128/0x0080: decoder\n" + "\t\t\t 256/0x0100: yuv\n" + "\t\t\t 512/0x0200: i2c\n" + "\t\t\t1024/0x0400: high volume\n"); MODULE_PARM_DESC(ivtv_pci_latency, "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" "\t\t\tDefault: Yes"); @@ -1358,9 +1368,9 @@ static int module_start(void) return -1; } - if (ivtv_debug < 0 || ivtv_debug > 1023) { + if (ivtv_debug < 0 || ivtv_debug > 2047) { ivtv_debug = 0; - printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n"); + printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); } if (pci_register_driver(&ivtv_pci_driver)) { diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 7ca9a775d..7d5a64447 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -262,17 +262,18 @@ extern const u32 yuv_offset[4]; /* debugging */ -#define IVTV_DBGFLG_WARN (1 << 0) -#define IVTV_DBGFLG_INFO (1 << 1) -#define IVTV_DBGFLG_API (1 << 2) -#define IVTV_DBGFLG_DMA (1 << 3) -#define IVTV_DBGFLG_IOCTL (1 << 4) -#define IVTV_DBGFLG_I2C (1 << 5) -#define IVTV_DBGFLG_IRQ (1 << 6) -#define IVTV_DBGFLG_DEC (1 << 7) -#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_WARN (1 << 0) +#define IVTV_DBGFLG_INFO (1 << 1) +#define IVTV_DBGFLG_MB (1 << 2) +#define IVTV_DBGFLG_IOCTL (1 << 3) +#define IVTV_DBGFLG_FILE (1 << 4) +#define IVTV_DBGFLG_DMA (1 << 5) +#define IVTV_DBGFLG_IRQ (1 << 6) +#define IVTV_DBGFLG_DEC (1 << 7) +#define IVTV_DBGFLG_YUV (1 << 8) +#define IVTV_DBGFLG_I2C (1 << 9) /* Flag to turn on high volume debugging */ -#define IVTV_DBGFLG_HIGHVOL (1 << 9) +#define IVTV_DBGFLG_HIGHVOL (1 << 10) /* NOTE: extra space before comma in 'itv->num , ## args' is required for gcc-2.95, otherwise it won't compile. */ @@ -281,30 +282,32 @@ extern const u32 yuv_offset[4]; if ((x) & ivtv_debug) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \ do { \ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ } while (0) -#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args) -#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args) -#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args) -#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) +#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args) +#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args) +#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args) +#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args) #define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) -#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) -#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) -#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) +#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args) +#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) +#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) +#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args) +#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) /* Standard kernel messages */ #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index b2ff2488d..5add53ef6 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -407,7 +407,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; struct ivtv *itv = s->itv; - IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc); + IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) pos += rc; return rc; @@ -498,7 +498,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ struct ivtv_stream *s = &itv->streams[id->type]; int rc; - IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); rc = ivtv_start_capture(id); if (rc) @@ -536,7 +536,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c int rc; DEFINE_WAIT(wait); - IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name); + IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); if (s->type != IVTV_DEC_STREAM_TYPE_MPG && s->type != IVTV_DEC_STREAM_TYPE_YUV && @@ -644,7 +644,7 @@ retry: to transfer the rest. */ if (count && !(filp->f_flags & O_NONBLOCK)) goto retry; - IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); return bytes_written; } @@ -656,6 +656,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) int res = 0; /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Decoder poll\n"); poll_wait(filp, &s->waitq, wait); set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); @@ -685,9 +686,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) s->name, rc); return POLLERR; } + IVTV_DEBUG_FILE("Encoder poll started capture\n"); } /* add stream's waitq to the poll list */ + IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); if (eof || s->q_full.length) @@ -700,7 +703,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* 'Unclaim' this stream */ @@ -738,7 +741,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close() of %s\n", s->name); /* Stop decoding */ if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { @@ -770,7 +773,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - IVTV_DEBUG_IOCTL("close() of %s\n", s->name); + IVTV_DEBUG_FILE("close %s\n", s->name); v4l2_prio_close(&itv->prio, &id->prio); @@ -853,6 +856,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) IVTV_ERR("Failed to initialize on minor %d\n", minor); return -ENXIO; } + IVTV_DEBUG_FILE("open %s\n", s->name); if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 9a0c3df8d..3cf6bbb04 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1143,12 +1143,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void memset(&enc->raw, 0, sizeof(enc->raw)); switch (enc->cmd) { case V4L2_ENC_CMD_START: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); enc->flags = 0; if (try) return 0; return ivtv_start_capture(id); case V4L2_ENC_CMD_STOP: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; if (try) return 0; @@ -1156,6 +1158,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void return 0; case V4L2_ENC_CMD_PAUSE: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); enc->flags = 0; if (try) return 0; @@ -1168,6 +1171,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; case V4L2_ENC_CMD_RESUME: + IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); enc->flags = 0; if (try) return 0; @@ -1179,6 +1183,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_unmute(itv); break; default: + IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); return -EINVAL; } break; @@ -1413,9 +1418,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) int try = (cmd == VIDEO_TRY_COMMAND); if (try) - IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd); else - IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); + IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd); return ivtv_video_command(itv, id, vc, try); } diff --git a/linux/drivers/media/video/ivtv/ivtv-mailbox.c b/linux/drivers/media/video/ivtv/ivtv-mailbox.c index 5e3b67920..b05436da7 100644 --- a/linux/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/linux/drivers/media/video/ivtv/ivtv-mailbox.c @@ -225,15 +225,15 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) } if (args < 0 || args > CX2341X_MBOX_MAX_DATA || cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { - IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); + IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args); return -EINVAL; } if (api_info[cmd].flags & API_HIGH_VOL) { - IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name); } else { - IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); + IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name); } /* clear possibly uninitialized part of data array */ -- cgit v1.2.3 From ccf3b850cb4a71df10dd6741a9bc17632c20876e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 12:10:55 +0200 Subject: ivtv: move serialization to the fileops level. From: Hans Verkuil Serialization is now done on the open/close/ioctl level and also when the read/write/poll start an encoder/decoder stream. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-fileops.c | 95 ++++++++++++++++----------- linux/drivers/media/video/ivtv/ivtv-ioctl.c | 26 ++++++-- linux/drivers/media/video/ivtv/ivtv-streams.c | 11 ---- 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index 5add53ef6..109c8c6c9 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -500,7 +500,9 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + mutex_lock(&itv->serialize_lock); rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) return rc; return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); @@ -611,7 +613,9 @@ retry: } /* Start decoder (returns 0 if already started) */ + mutex_lock(&itv->serialize_lock); rc = ivtv_start_decoding(id, itv->speed); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); @@ -679,8 +683,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) /* Start a capture if there is none */ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { - int rc = ivtv_start_capture(id); + int rc; + mutex_lock(&itv->serialize_lock); + rc = ivtv_start_capture(id); + mutex_unlock(&itv->serialize_lock); if (rc) { IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", s->name, rc); @@ -786,6 +793,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) /* 'Unclaim' this stream */ /* Stop radio */ + mutex_lock(&itv->serialize_lock); if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { /* Closing radio device, return to TV mode */ ivtv_mute(itv); @@ -820,53 +828,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp) ivtv_stop_capture(id, 0); } kfree(id); + mutex_unlock(&itv->serialize_lock); return 0; } -int ivtv_v4l2_open(struct inode *inode, struct file *filp) +static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) { - int x, y = 0; + struct ivtv *itv = s->itv; struct ivtv_open_id *item; - struct ivtv *itv = NULL; - struct ivtv_stream *s = NULL; - int minor = iminor(inode); - /* Find which card this open was on */ - spin_lock(&ivtv_cards_lock); - for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { - /* find out which stream this open was on */ - for (y = 0; y < IVTV_MAX_STREAMS; y++) { - s = &ivtv_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { - itv = ivtv_cards[x]; - break; - } - } - } - spin_unlock(&ivtv_cards_lock); - - if (itv == NULL) { - /* Couldn't find a device registered - on that minor, shouldn't happen! */ - IVTV_WARN("No ivtv device found on minor %d\n", minor); - return -ENXIO; - } - - if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on minor %d\n", minor); - return -ENXIO; - } IVTV_DEBUG_FILE("open %s\n", s->name); - if (y == IVTV_DEC_STREAM_TYPE_MPG && + if (s->type == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV && + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) return -EBUSY; - if (y == IVTV_DEC_STREAM_TYPE_YUV) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { if (read_reg(0x82c) == 0) { IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); /* return -ENODEV; */ @@ -881,7 +862,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENOMEM; } item->itv = itv; - item->type = y; + item->type = s->type; v4l2_prio_open(&itv->prio, &item->prio); item->open_id = itv->open_id++; @@ -923,14 +904,50 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (y == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (y == IVTV_DEC_STREAM_TYPE_YUV) - { + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + return 0; +} + +int ivtv_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct ivtv *itv = NULL; + struct ivtv_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&ivtv_cards_lock); + for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < IVTV_MAX_STREAMS; y++) { + s = &ivtv_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + itv = ivtv_cards[x]; + break; + } + } } + spin_unlock(&ivtv_cards_lock); - return 0; + if (itv == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + IVTV_WARN("No ivtv device found on minor %d\n", minor); + return -ENXIO; + } + + mutex_lock(&itv->serialize_lock); + if (ivtv_init_on_first_open(itv)) { + IVTV_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&itv->serialize_lock); + return -ENXIO; + } + res = ivtv_serialized_open(s, filp); + mutex_unlock(&itv->serialize_lock); + return res; } void ivtv_mute(struct ivtv *itv) diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 3cf6bbb04..61d3dc7c2 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1451,11 +1451,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; if (nonblocking) return -EAGAIN; - /* wait for event */ + /* Wait for event. Note that serialize_lock is locked, + so to allow other processes to access the driver while + we are waiting unlock first and later lock again. */ + mutex_unlock(&itv->serialize_lock); prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) schedule(); finish_wait(&itv->event_waitq, &wait); + mutex_lock(&itv->serialize_lock); if (signal_pending(current)) { /* return if a signal was received */ IVTV_DEBUG_INFO("User stopped wait for event\n"); @@ -1585,12 +1589,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, return 0; } -int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; - struct ivtv *itv = id->itv; - /* Filter dvb ioctls that cannot be handled by video_usercopy */ switch (cmd) { case VIDEO_SELECT_SOURCE: @@ -1625,3 +1626,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); } + +int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; + struct ivtv *itv = id->itv; + int res; + + mutex_lock(&itv->serialize_lock); + res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg); + mutex_unlock(&itv->serialize_lock); + return res; +} diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index fab5c51b1..65fa247e3 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (s->v4l2dev == NULL) return -EINVAL; - /* Big serialization lock to ensure no two streams are started - simultaneously: that can give all sorts of weird results. */ - mutex_lock(&itv->serialize_lock); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); switch (s->type) { @@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) 0, sizeof(itv->vbi.sliced_mpeg_size)); break; default: - mutex_unlock(&itv->serialize_lock); return -EINVAL; } s->subtype = subtype; @@ -564,7 +560,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) { IVTV_DEBUG_WARN( "Error starting capture!\n"); - mutex_unlock(&itv->serialize_lock); return -EINVAL; } @@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) /* you're live! sit back and await interrupts :) */ atomic_inc(&itv->capturing); - mutex_unlock(&itv->serialize_lock); return 0; } @@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) stopmode = 1; } - /* ensure these actions are done only once */ - mutex_lock(&itv->serialize_lock); - /* end_capture */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); @@ -810,7 +801,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); if (atomic_read(&itv->capturing) > 0) { - mutex_unlock(&itv->serialize_lock); return 0; } @@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) } wake_up(&s->waitq); - mutex_unlock(&itv->serialize_lock); return 0; } -- cgit v1.2.3 From d046d4686743f982d91394c7896a45d0237d0c59 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 12:11:44 +0200 Subject: ivtv-fb: remove unused header includes. From: Hans Verkuil Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-fb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-fb.c b/linux/drivers/media/video/ivtv/ivtv-fb.c index d2cc03172..008076543 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fb.c +++ b/linux/drivers/media/video/ivtv/ivtv-fb.c @@ -57,12 +57,8 @@ #endif #include "ivtv-driver.h" -#include "ivtv-queue.h" #include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-fileops.h" #include "ivtv-mailbox.h" -#include "ivtv-cards.h" #include /* card parameters */ -- cgit v1.2.3 From 4188f0e10a47f5633e7fc7eda97b41eeb49e1070 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 17:25:39 +0200 Subject: ivtv: add support for highmem udma From: Hans Verkuil When trying to DMA userspace buffers to the cx23415 you need to check whether the page is in highmem. If this is the case, then bounce buffers have to be used to allow DMA. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.h | 2 ++ linux/drivers/media/video/ivtv/ivtv-udma.c | 45 +++++++++++++++++++++++----- linux/drivers/media/video/ivtv/ivtv-yuv.c | 9 +++++- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 7d5a64447..abd8c6bf8 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -429,6 +429,8 @@ struct ivtv_user_dma { #endif int page_count; struct page *map[IVTV_DMA_SG_OSD_ENT]; + /* Needed when dealing with highmem userspace buffers */ + struct page *bouncemap[IVTV_DMA_SG_OSD_ENT]; /* Base Dev SG Array for cx23415/6 */ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; diff --git a/linux/drivers/media/video/ivtv/ivtv-udma.c b/linux/drivers/media/video/ivtv/ivtv-udma.c index bd642e1aa..5592abbe1 100644 --- a/linux/drivers/media/video/ivtv/ivtv-udma.c +++ b/linux/drivers/media/video/ivtv/ivtv-udma.c @@ -38,23 +38,38 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) { int i, offset; + unsigned long flags; offset = dma_page->offset; /* Fill SG Array with new values */ for (i = 0; i < dma_page->page_count; i++) { - if (i == dma_page->page_count - 1) { - dma->SGlist[map_offset].length = dma_page->tail; + unsigned int len = (i == dma_page->page_count - 1) ? + dma_page->tail : PAGE_SIZE - offset; + + dma->SGlist[map_offset].length = len; + dma->SGlist[map_offset].offset = offset; + if (PageHighMem(dma->map[map_offset])) { + void *src; + + if (dma->bouncemap[map_offset] == NULL) + dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); + if (dma->bouncemap[map_offset] == NULL) + return -ENOMEM; + local_irq_save(flags); + src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; + memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); + kunmap_atomic(src, KM_BOUNCE_READ); + local_irq_restore(flags); + dma->SGlist[map_offset].page = dma->bouncemap[map_offset]; } else { - dma->SGlist[map_offset].length = PAGE_SIZE - offset; + dma->SGlist[map_offset].page = dma->map[map_offset]; } - dma->SGlist[map_offset].offset = offset; - dma->SGlist[map_offset].page = dma->map[map_offset]; offset = 0; map_offset++; } - return map_offset; + return 0; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, { struct ivtv_dma_page_info user_dma; struct ivtv_user_dma *dma = &itv->udma; - int err; + int i, err; IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); @@ -123,7 +138,14 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - ivtv_udma_fill_sg_list(dma, &user_dma, 0); + err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); + if (err) { + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return err; + } /* Map SG List */ dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); @@ -166,6 +188,8 @@ void ivtv_udma_unmap(struct ivtv *itv) void ivtv_udma_free(struct ivtv *itv) { + int i; + /* Unmap SG Array */ if (itv->udma.SG_handle) { pci_unmap_single(itv->dev, itv->udma.SG_handle, @@ -176,6 +200,11 @@ void ivtv_udma_free(struct ivtv *itv) if (itv->udma.SG_length) { pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); } + + for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) { + if (itv->udma.bouncemap[i]) + __free_page(itv->udma.bouncemap[i]); + } } void ivtv_udma_start(struct ivtv *itv) diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c index fa8c76f3d..2ae7556f5 100644 --- a/linux/drivers/media/video/ivtv/ivtv-yuv.c +++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); + for (i = 0; i < dma->page_count; i++) { + put_page(dma->map[i]); + } + dma->page_count = 0; + return -ENOMEM; + } dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ -- cgit v1.2.3 From c6335006c82d58c81b020a32abd2570a5e667d07 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 20:03:05 +0200 Subject: ivtv: log stereo/bilingual audio modes From: Hans Verkuil Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 61d3dc7c2..6b5cf7450 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1240,7 +1240,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s\n", audin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, + (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; @@ -1252,11 +1253,20 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "YUV Frames", "Passthrough", }; + static const char * const audio_modes[] = { + "Stereo", + "Left", + "Right", + "Mono", + "Swapped" + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); IVTV_INFO("Video Output: %s\n", vidout.name); - IVTV_INFO("Audio Output: %s\n", audout.name); + IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name, + audio_modes[itv->audio_stereo_mode], + audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; IVTV_INFO("Output Mode: %s\n", output_modes[mode]); -- cgit v1.2.3 From 8a6d57d665385ce55fc31b961e424185ecd3b4ae Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 22:56:41 +0200 Subject: ivtv: fix IVTV_IOC_DMA_FRAME bug introduced by highmem bugfix. From: Hans Verkuil The return value of ivtv_udma_fill_sg_list() was changed by the highmem bugfix, but that return value was still used in ivtv-yuv.c. Revert to the old return value, but in addition return -1 in case of a memory allocation error. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-udma.c | 12 +++++++----- linux/drivers/media/video/ivtv/ivtv-yuv.c | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-udma.c b/linux/drivers/media/video/ivtv/ivtv-udma.c index 5592abbe1..7e503adac 100644 --- a/linux/drivers/media/video/ivtv/ivtv-udma.c +++ b/linux/drivers/media/video/ivtv/ivtv-udma.c @@ -40,6 +40,9 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info int i, offset; unsigned long flags; + if (map_offset < 0) + return map_offset; + offset = dma_page->offset; /* Fill SG Array with new values */ @@ -55,7 +58,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info if (dma->bouncemap[map_offset] == NULL) dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL); if (dma->bouncemap[map_offset] == NULL) - return -ENOMEM; + return -1; local_irq_save(flags); src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset; memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len); @@ -69,7 +72,7 @@ int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info offset = 0; map_offset++; } - return 0; + return map_offset; } void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { @@ -138,13 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, dma->page_count = user_dma.page_count; /* Fill SG List with new values */ - err = ivtv_udma_fill_sg_list(dma, &user_dma, 0); - if (err) { + if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); } dma->page_count = 0; - return err; + return -ENOMEM; } /* Map SG List */ diff --git a/linux/drivers/media/video/ivtv/ivtv-yuv.c b/linux/drivers/media/video/ivtv/ivtv-yuv.c index 2ae7556f5..1922c1da2 100644 --- a/linux/drivers/media/video/ivtv/ivtv-yuv.c +++ b/linux/drivers/media/video/ivtv/ivtv-yuv.c @@ -83,7 +83,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } /* Fill & map SG List */ - if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) { + if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); -- cgit v1.2.3 From 1808b8dd0052d2ba4d3c7831dfd3fbe135935581 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Aug 2007 23:59:42 +0200 Subject: ivtv: add VIDIOC_OVERLAY From: Hans Verkuil Add VIDIOC_OVERLAY to enable/disable the OSD. Also add the OSD state to the log status report. Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-ioctl.c | 45 +++++++++++++++++++++++---- linux/drivers/media/video/ivtv/ivtv-streams.c | 6 ++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 6b5cf7450..1e8d288b9 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1222,9 +1222,19 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void break; } + case VIDIOC_OVERLAY: { + int *on = arg; + + if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0); + break; + } + case VIDIOC_LOG_STATUS: { int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; + u32 data[CX2341X_MBOX_MAX_DATA]; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1239,8 +1249,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); ivtv_get_input(itv, itv->active_input, &vidin); ivtv_get_audio_input(itv, itv->audio_input, &audin); - IVTV_INFO("Video Input: %s\n", vidin.name); - IVTV_INFO("Audio Input: %s%s\n", audin.name, + IVTV_INFO("Video Input: %s\n", vidin.name); + IVTV_INFO("Audio Input: %s%s\n", audin.name, (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; @@ -1260,6 +1270,22 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void "Mono", "Swapped" }; + static const char * const alpha_mode[] = { + "None", + "Global", + "Local", + "Global and Local" + }; + static const char * const pixel_format[] = { + "Indexed", + "RGB 5:6:5", + "ARGB 1:5:5:5", + "ARGB 1:4:4:4", + "ARGB 8:8:8:8", + "5", + "6", + "7", + }; ivtv_get_output(itv, itv->active_output, &vidout); ivtv_get_audio_output(itv, 0, &audout); @@ -1269,12 +1295,17 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void audio_modes[itv->audio_bilingual_mode]); if (mode < 0 || mode > OUT_PASSTHROUGH) mode = OUT_NONE; - IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + IVTV_INFO("Output Mode: %s\n", output_modes[mode]); + ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); + IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", + data[0] & 1 ? "On" : "Off", + alpha_mode[(data[0] >> 1) & 0x3], + pixel_format[(data[0] >> 3) & 0x7]); } - IVTV_INFO("Tuner: %s\n", + IVTV_INFO("Tuner: %s\n", test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); cx2341x_log_status(&itv->params, itv->name); - IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); + IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; @@ -1284,7 +1315,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void (s->buffers - s->q_free.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } - IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); + IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted); IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); break; } @@ -1506,6 +1537,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_S_AUDOUT: case VIDIOC_S_EXT_CTRLS: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: ret = v4l2_prio_check(&itv->prio, &id->prio); if (ret) return ret; @@ -1559,6 +1591,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_TRY_ENCODER_CMD: case VIDIOC_G_FBUF: case VIDIOC_S_FBUF: + case VIDIOC_OVERLAY: if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 65fa247e3..ebf925c54 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -75,7 +75,7 @@ static struct { struct file_operations *fops; } ivtv_stream_info[] = { { /* IVTV_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", + "encoder MPG", VFL_TYPE_GRABBER, 0, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, &ivtv_v4l2_enc_fops @@ -93,7 +93,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", + "encoder PCM", VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, &ivtv_v4l2_enc_fops @@ -105,7 +105,7 @@ static struct { &ivtv_v4l2_enc_fops }, { /* IVTV_DEC_STREAM_TYPE_MPG */ - "decoder MPEG", + "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, &ivtv_v4l2_dec_fops -- cgit v1.2.3 From 636d8a20cebdf6c1829cc7e05ecf2d61c4bad253 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 Aug 2007 00:05:20 +0200 Subject: v4l2-ctl: add VIDIOC_OVERLAY support. From: Hans Verkuil Signed-off-by: Hans Verkuil --- v4l2-apps/util/v4l2-ctl.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp index fda6eec48..4cee687bb 100644 --- a/v4l2-apps/util/v4l2-ctl.cpp +++ b/v4l2-apps/util/v4l2-ctl.cpp @@ -117,6 +117,7 @@ enum Option { OptGetOutputCropCap, OptGetOverlayCropCap, OptGetOutputOverlayCropCap, + OptOverlay, OptLast = 256 }; @@ -226,6 +227,7 @@ static struct option long_options[] = { {"get-cropcap-output-overlay", no_argument, 0, OptGetOutputOverlayCropCap}, {"get-crop-output-overlay", no_argument, 0, OptGetOutputOverlayCrop}, {"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop}, + {"overlay", required_argument, 0, OptOverlay}, {0, 0, 0, 0} }; @@ -317,6 +319,7 @@ static void usage(void) printf(" vps: VPS (PAL/SECAM)\n"); printf(" --get-fmt-vbi query the VBI capture format [VIDIOC_G_FMT]\n"); printf(" --get-fmt-vbi-out query the VBI output format [VIDIOC_G_FMT]\n"); + printf(" --overlay= turn overlay on (1) or off (0) (VIDIOC_OVERLAY)\n"); printf(" --get-fbuf query the overlay framebuffer data [VIDIOC_G_FBUF]\n"); printf(" --set-fbuf=chromakey=<0/1>,global_alpha=<0/1>,local_alpha=<0/1>,local_inv_alpha=<0/1>\n"); printf(" set the overlay framebuffer [VIDIOC_S_FBUF]\n"); @@ -1166,6 +1169,7 @@ int main(int argc, char **argv) double freq = 0; /* get/set frequency */ struct v4l2_frequency vf; /* get_freq/set_freq */ struct v4l2_standard vs; /* list_std */ + int overlay; /* overlay */ char short_options[26 * 2 * 2 + 1]; int idx = 0; @@ -1317,6 +1321,9 @@ int main(int argc, char **argv) } } break; + case OptOverlay: + overlay = strtol(optarg, 0L, 0); + break; case OptSetCrop: parse_crop(optarg, set_crop, vcrop); break; @@ -1692,6 +1699,10 @@ int main(int argc, char **argv) } } + if (options[OptOverlay]) { + doioctl(fd, VIDIOC_OVERLAY, &overlay, "VIDIOC_OVERLAY"); + } + if (options[OptSetCrop]) { do_crop(fd, set_crop, vcrop, V4L2_BUF_TYPE_VIDEO_CAPTURE); } -- cgit v1.2.3