diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 12:13:30 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 16:36:22 -0300 |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/video/ivtv/ivtv-irq.c | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) | |
download | op-kernel-dev-b285192a43f0432d82c2c10974204e78af0da596.zip op-kernel-dev-b285192a43f0432d82c2c10974204e78af0da596.tar.gz |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-irq.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-irq.c | 1038 |
1 files changed, 0 insertions, 1038 deletions
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c deleted file mode 100644 index 1b3b957..0000000 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* interrupt handling - Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> - - 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "ivtv-driver.h" -#include "ivtv-queue.h" -#include "ivtv-udma.h" -#include "ivtv-irq.h" -#include "ivtv-mailbox.h" -#include "ivtv-vbi.h" -#include "ivtv-yuv.h" -#include <media/v4l2-event.h> - -#define DMA_MAGIC_COOKIE 0x000001fe - -static void ivtv_dma_dec_start(struct ivtv_stream *s); - -static const int ivtv_stream_map[] = { - IVTV_ENC_STREAM_TYPE_MPG, - IVTV_ENC_STREAM_TYPE_YUV, - IVTV_ENC_STREAM_TYPE_PCM, - IVTV_ENC_STREAM_TYPE_VBI, -}; - - -static void ivtv_pio_work_handler(struct ivtv *itv) -{ - struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream]; - struct ivtv_buffer *buf; - int i = 0; - - IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); - if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || - s->vdev == NULL || !ivtv_use_pio(s)) { - itv->cur_pio_stream = -1; - /* trigger PIO complete user interrupt */ - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); - return; - } - IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name); - list_for_each_entry(buf, &s->q_dma.list, list) { - 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->sg_processing[i].src - IVTV_DECODER_OFFSET, size); - } - else { - memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size); - } - i++; - if (i == s->sg_processing_size) - break; - } - write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); -} - -void ivtv_irq_work_handler(struct kthread_work *work) -{ - struct ivtv *itv = container_of(work, struct ivtv, irq_work); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) - ivtv_pio_work_handler(itv); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) - ivtv_vbi_work_handler(itv); - - if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) - ivtv_yuv_work_handler(itv); -} - -/* Determine the required DMA size, setup enough buffers in the predma queue and - actually copy the data from the card to the buffers in case a PIO transfer is - required for this stream. - */ -static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf; - u32 bytes_needed = 0; - u32 offset, size; - u32 UVoffset = 0, UVsize = 0; - int skip_bufs = s->q_predma.buffers; - int idx = s->sg_pending_size; - int rc; - - /* sanity checks */ - if (s->vdev == NULL) { - IVTV_DEBUG_WARN("Stream %s not started\n", s->name); - return -1; - } - if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { - IVTV_DEBUG_WARN("Stream %s not open\n", s->name); - return -1; - } - - /* determine offset, size and PTS for the various streams */ - switch (s->type) { - case IVTV_ENC_STREAM_TYPE_MPG: - offset = data[1]; - size = data[2]; - s->pending_pts = 0; - break; - - case IVTV_ENC_STREAM_TYPE_YUV: - offset = data[1]; - size = data[2]; - UVoffset = data[3]; - UVsize = data[4]; - 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->pending_pts = read_dec(offset - 8) | - ((u64)(read_dec(offset - 12)) << 32); - if (itv->has_cx23415) - offset += IVTV_DECODER_OFFSET; - break; - - case IVTV_ENC_STREAM_TYPE_VBI: - size = itv->vbi.enc_size * itv->vbi.fpi; - offset = read_enc(itv->vbi.enc_start - 4) + 12; - if (offset == 12) { - IVTV_DEBUG_INFO("VBI offset == 0\n"); - return -1; - } - 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->pending_pts = 0; - offset += IVTV_DECODER_OFFSET; - break; - default: - /* shouldn't happen */ - return -1; - } - - /* if this is the start of the DMA then fill in the magic cookie */ - 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); - write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); - } - else { - s->pending_backup = read_enc(offset); - write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); - } - s->pending_offset = offset; - } - - bytes_needed = size; - if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { - /* The size for the Y samples needs to be rounded upwards to a - multiple of the buf_size. The UV samples then start in the - next buffer. */ - bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); - bytes_needed += UVsize; - } - - IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n", - ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); - - rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); - if (rc < 0) { /* Insufficient buffers */ - IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", - bytes_needed, s->name); - return -1; - } - if (rc && !s->buffers_stolen && test_bit(IVTV_F_S_APPL_IO, &s->s_flags)) { - IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); - IVTV_WARN("Cause: the application is not reading fast enough.\n"); - } - s->buffers_stolen = rc; - - /* 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_entry(buf, &s->q_predma.list, list) { - if (skip_bufs-- > 0) - continue; - s->sg_pending[idx].dst = buf->dma_handle; - s->sg_pending[idx].src = offset; - s->sg_pending[idx].size = s->buf_size; - buf->bytesused = min(size, s->buf_size); - buf->dma_xfer_cnt = s->dma_xfer_cnt; - - s->q_predma.bytesused += buf->bytesused; - size -= buf->bytesused; - offset += s->buf_size; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - - if (size == 0) { /* YUV */ - /* process the UV section */ - offset = UVoffset; - size = UVsize; - } - idx++; - } - s->sg_pending_size = idx; - return 0; -} - -static void dma_post(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_buffer *buf = NULL; - struct list_head *p; - u32 offset; - __le32 *u32buf; - int x = 0; - - IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", - s->name, s->dma_offset); - list_for_each(p, &s->q_dma.list) { - buf = list_entry(p, struct ivtv_buffer, list); - u32buf = (__le32 *)buf->buf; - - /* Sync Buffer */ - ivtv_buf_sync_for_cpu(s, buf); - - if (x == 0 && ivtv_use_dma(s)) { - offset = s->dma_last_offset; - if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) - { - for (offset = 0; offset < 64; offset++) { - if (u32buf[offset] == DMA_MAGIC_COOKIE) { - break; - } - } - offset *= 4; - if (offset == 256) { - IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); - offset = s->dma_last_offset; - } - if (s->dma_last_offset != offset) - IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); - s->dma_last_offset = offset; - } - if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || - s->type == IVTV_DEC_STREAM_TYPE_VBI)) { - write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); - } - else { - write_enc_sync(0, s->dma_offset); - } - if (offset) { - buf->bytesused -= offset; - memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); - } - *u32buf = cpu_to_le32(s->dma_backup); - } - x++; - /* 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) - buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP; - } - if (buf) - buf->bytesused += s->dma_last_offset; - if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { - list_for_each_entry(buf, &s->q_dma.list, list) { - /* Parse and Groom VBI Data */ - s->q_dma.bytesused -= buf->bytesused; - ivtv_process_vbi_data(itv, buf, 0, s->type); - s->q_dma.bytesused += buf->bytesused; - } - if (s->fh == NULL) { - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); - return; - } - } - ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); - if (s->fh) - wake_up(&s->waitq); -} - -void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) -{ - struct ivtv *itv = s->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - struct yuv_frame_info *f = &yi->new_frame_info[frame]; - struct ivtv_buffer *buf; - u32 y_size = 720 * ((f->src_h + 31) & ~31); - u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; - int y_done = 0; - int bytes_written = 0; - unsigned long flags = 0; - int idx = 0; - - IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - - /* Insert buffer block for YUV if needed */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { - if (yi->blanking_dmaptr) { - s->sg_pending[idx].src = yi->blanking_dmaptr; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = 720 * 16; - } - offset += 720 * 16; - idx++; - } - - list_for_each_entry(buf, &s->q_predma.list, list) { - /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && - (bytes_written + buf->bytesused) >= y_size) { - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = y_size - bytes_written; - offset = uv_offset; - if (s->sg_pending[idx].size != buf->bytesused) { - idx++; - s->sg_pending[idx].src = - buf->dma_handle + s->sg_pending[idx - 1].size; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = - buf->bytesused - s->sg_pending[idx - 1].size; - offset += s->sg_pending[idx].size; - } - y_done = 1; - } else { - 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; - - /* Sync SG buffers */ - ivtv_buf_sync_for_device(s, buf); - idx++; - } - s->sg_pending_size = idx; - - /* Sync Hardware SG List of buffers */ - ivtv_stream_sync_for_device(s); - if (lock) - spin_lock_irqsave(&itv->dma_reg_lock, flags); - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { - ivtv_dma_dec_start(s); - } - else { - set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); - } - if (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); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); - add_timer(&itv->dma_timer); -} - -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); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); - add_timer(&itv->dma_timer); -} - -/* start the encoder DMA */ -static void ivtv_dma_enc_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - int i; - - IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name); - - if (s->q_predma.bytesused) - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); - - if (ivtv_use_dma(s)) - 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. - - VBI DMA is a second class citizen compared to MPEG and mixing them together - will confuse the firmware (the end of a VBI DMA is seen as the end of a - MPEG DMA, thus effectively dropping an MPEG frame). So instead we make - 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_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->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]; - } - 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_vbi->name); - } - - s->dma_xfer_cnt++; - memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_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)) { - 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 { - 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; - } -} - -static void ivtv_dma_dec_start(struct ivtv_stream *s) -{ - struct ivtv *itv = s->itv; - - 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_host_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); - 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; -} - -static void ivtv_irq_dma_read(struct ivtv *itv) -{ - struct ivtv_stream *s = NULL; - struct ivtv_buffer *buf; - int hw_stream_type = 0; - - IVTV_DEBUG_HI_IRQ("DEC DMA READ\n"); - - del_timer(&itv->dma_timer); - - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) - return; - - if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { - 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) { - /* 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. - Just retrying the current segment is not sufficient. */ - s->sg_processed = 0; - itv->dma_retries++; - } - } - 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); - - /* 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. - I think we can do this part ourselves but would have to - fully calculate xfer info ourselves and not use interrupts - */ - ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, - hw_stream_type); - - /* Free last DMA call */ - while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { - ivtv_buf_sync_for_cpu(s, buf); - ivtv_enqueue(s, buf, &s->q_free); - } - wake_up(&s->waitq); - } - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_dma_complete(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); - IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream); - - del_timer(&itv->dma_timer); - - if (itv->cur_dma_stream < 0) - return; - - s = &itv->streams[itv->cur_dma_stream]; - ivtv_stream_sync_for_cpu(s); - - if (data[0] & 0x18) { - 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); - 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. - Just retrying the current segment is not sufficient. */ - s->sg_processed = 0; - itv->dma_retries++; - } - } - if (s->sg_processed < s->sg_processing_size) { - /* DMA next buffer */ - ivtv_dma_enc_start_xfer(s); - return; - } - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - dma_post(s); - if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - dma_post(s); - } - s->sg_processing_size = 0; - s->sg_processed = 0; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_pio_complete(struct ivtv *itv) -{ - struct ivtv_stream *s; - - if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS) { - itv->cur_pio_stream = -1; - return; - } - s = &itv->streams[itv->cur_pio_stream]; - IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name); - clear_bit(IVTV_F_I_PIO, &itv->i_flags); - itv->cur_pio_stream = -1; - dma_post(s); - if (s->type == IVTV_ENC_STREAM_TYPE_MPG) - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 0); - else if (s->type == IVTV_ENC_STREAM_TYPE_YUV) - ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 1); - else if (s->type == IVTV_ENC_STREAM_TYPE_PCM) - 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)) { - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - dma_post(s); - } - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_dma_err(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - u32 status; - - del_timer(&itv->dma_timer); - - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, 2, data); - status = read_reg(IVTV_REG_DMASTATUS); - IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], - status, itv->cur_dma_stream); - /* - * We do *not* write back to the IVTV_REG_DMASTATUS register to - * clear the error status, if either the encoder write (0x02) or - * decoder read (0x01) bus master DMA operation do not indicate - * completed. We can race with the DMA engine, which may have - * transitioned to completed status *after* we read the register. - * Setting a IVTV_REG_DMASTATUS flag back to "busy" status, after the - * DMA engine has completed, will cause the DMA engine to stop working. - */ - status &= 0x3; - if (status == 0x3) - write_reg(status, 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]; - - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { - /* retry */ - /* - * FIXME - handle cases of DMA error similar to - * encoder below, except conditioned on status & 0x1 - */ - ivtv_dma_dec_start(s); - return; - } else { - if ((status & 0x2) == 0) { - /* - * CX2341x Bus Master DMA write is ongoing. - * Reset the timer and let it complete. - */ - itv->dma_timer.expires = - jiffies + msecs_to_jiffies(600); - add_timer(&itv->dma_timer); - return; - } - - if (itv->dma_retries < 3) { - /* - * CX2341x Bus Master DMA write has ended. - * Retry the write, starting with the first - * xfer segment. Just retrying the current - * segment is not sufficient. - */ - s->sg_processed = 0; - itv->dma_retries++; - ivtv_dma_enc_start_xfer(s); - return; - } - /* Too many retries, give up on this one */ - } - - } - 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; - wake_up(&itv->dma_waitq); -} - -static void ivtv_irq_enc_start_cap(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* Get DMA destination and size arguments from card */ - ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, 7, data); - IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); - - if (data[0] > 2 || data[1] == 0 || data[2] == 0) { - IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", - data[0], data[1], data[2]); - return; - } - s = &itv->streams[ivtv_stream_map[data[0]]]; - if (!stream_enc_dma_append(s, data)) { - set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); - } -} - -static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); - s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - - if (!stream_enc_dma_append(s, data)) - set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); -} - -static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; - - IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n"); - if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && - !stream_enc_dma_append(s, data)) { - set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags); - } -} - -static void ivtv_irq_dec_data_req(struct ivtv *itv) -{ - u32 data[CX2341X_MBOX_MAX_DATA]; - struct ivtv_stream *s; - - /* YUV or MPG */ - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 2, data); - itv->dma_data_req_size = - 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); - itv->dma_data_req_offset = data[1]; - if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) - ivtv_yuv_frame_complete(itv); - s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - } - else { - ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, 3, data); - itv->dma_data_req_size = min_t(u32, data[2], 0x10000); - itv->dma_data_req_offset = data[1]; - s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; - } - IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, - itv->dma_data_req_offset, itv->dma_data_req_size); - if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { - set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - } - else { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - ivtv_yuv_setup_stream_frame(itv); - clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); - ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); - ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); - } -} - -static void ivtv_irq_vsync(struct ivtv *itv) -{ - /* The vsync interrupt is unusual in that it won't clear until - * the end of the first line for the current field, at which - * point it clears itself. This can result in repeated vsync - * interrupts, or a missed vsync. Read some of the registers - * to determine the line being displayed and ensure we handle - * one vsync per frame. - */ - unsigned int frame = read_reg(IVTV_REG_DEC_LINE_FIELD) & 1; - struct yuv_playback_info *yi = &itv->yuv_info; - int last_dma_frame = atomic_read(&yi->next_dma_frame); - struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; - - if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - - if (((frame ^ f->sync_field) == 0 && - ((itv->last_vsync_field & 1) ^ f->sync_field)) || - (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { - int next_dma_frame = last_dma_frame; - - if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { - write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); - write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; - atomic_set(&yi->next_dma_frame, next_dma_frame); - yi->fields_lapsed = -1; - yi->running = 1; - } - } - } - if (frame != (itv->last_vsync_field & 1)) { - static const struct v4l2_event evtop = { - .type = V4L2_EVENT_VSYNC, - .u.vsync.field = V4L2_FIELD_TOP, - }; - static const struct v4l2_event evbottom = { - .type = V4L2_EVENT_VSYNC, - .u.vsync.field = V4L2_FIELD_BOTTOM, - }; - struct ivtv_stream *s = ivtv_get_output_stream(itv); - - itv->last_vsync_field += 1; - if (frame == 0) { - clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); - clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - else { - set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); - } - if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { - set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); - wake_up(&itv->event_waitq); - if (s) - wake_up(&s->waitq); - } - if (s && s->vdev) - v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom); - wake_up(&itv->vsync_waitq); - - /* Send VBI to saa7127 */ - if (frame && (itv->output_mode == OUT_PASSTHROUGH || - test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) || - test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) || - test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) { - set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); - set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); - } - - /* Check if we need to update the yuv registers */ - if (yi->running && (yi->yuv_forced_update || f->update)) { - if (!f->update) { - last_dma_frame = - (u8)(atomic_read(&yi->next_dma_frame) - - 1) % IVTV_YUV_BUFFERS; - f = &yi->new_frame_info[last_dma_frame]; - } - - if (f->src_w) { - yi->update_frame = last_dma_frame; - f->update = 0; - yi->yuv_forced_update = 0; - set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); - set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); - } - } - - yi->fields_lapsed++; - } -} - -#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT) - -irqreturn_t ivtv_irq_handler(int irq, void *dev_id) -{ - struct ivtv *itv = (struct ivtv *)dev_id; - u32 combo; - u32 stat; - int i; - u8 vsync_force = 0; - - spin_lock(&itv->dma_reg_lock); - /* get contents of irq status register */ - stat = read_reg(IVTV_REG_IRQSTATUS); - - combo = ~itv->irqmask & stat; - - /* Clear out IRQ */ - if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); - - if (0 == combo) { - /* The vsync interrupt is unusual and clears itself. If we - * took too long, we may have missed it. Do some checks - */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - /* vsync is enabled, see if we're in a new field */ - if ((itv->last_vsync_field & 1) != - (read_reg(IVTV_REG_DEC_LINE_FIELD) & 1)) { - /* New field, looks like we missed it */ - IVTV_DEBUG_YUV("VSync interrupt missed %d\n", - read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16); - vsync_force = 1; - } - } - - if (!vsync_force) { - /* No Vsync expected, wasn't for us */ - spin_unlock(&itv->dma_reg_lock); - return IRQ_NONE; - } - } - - /* Exclude interrupts noted below from the output, otherwise the log is flooded with - these messages */ - if (combo & ~0xff6d0400) - IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); - - if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { - IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n"); - } - - if (combo & IVTV_IRQ_DMA_READ) { - ivtv_irq_dma_read(itv); - } - - if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { - ivtv_irq_enc_dma_complete(itv); - } - - if (combo & IVTV_IRQ_ENC_PIO_COMPLETE) { - ivtv_irq_enc_pio_complete(itv); - } - - if (combo & IVTV_IRQ_DMA_ERR) { - ivtv_irq_dma_err(itv); - } - - if (combo & IVTV_IRQ_ENC_START_CAP) { - ivtv_irq_enc_start_cap(itv); - } - - if (combo & IVTV_IRQ_ENC_VBI_CAP) { - ivtv_irq_enc_vbi_cap(itv); - } - - if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { - ivtv_irq_dec_vbi_reinsert(itv); - } - - if (combo & IVTV_IRQ_ENC_EOS) { - IVTV_DEBUG_IRQ("ENC EOS\n"); - set_bit(IVTV_F_I_EOS, &itv->i_flags); - wake_up(&itv->eos_waitq); - } - - if (combo & IVTV_IRQ_DEC_DATA_REQ) { - ivtv_irq_dec_data_req(itv); - } - - /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ - if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { - ivtv_irq_vsync(itv); - } - - if (combo & IVTV_IRQ_ENC_VIM_RST) { - IVTV_DEBUG_IRQ("VIM RST\n"); - /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ - } - - if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { - IVTV_DEBUG_INFO("Stereo mode changed\n"); - } - - 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; - struct ivtv_stream *s = &itv->streams[idx]; - - if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) - continue; - if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_dec_start(s); - else - ivtv_dma_enc_start(s); - break; - } - - if (i == IVTV_MAX_STREAMS && - test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) - ivtv_udma_start(itv); - } - - 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; - struct ivtv_stream *s = &itv->streams[idx]; - - if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags)) - continue; - if (s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type < IVTV_DEC_STREAM_TYPE_MPG) - ivtv_dma_enc_start(s); - break; - } - } - - if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) { - queue_kthread_work(&itv->irq_worker, &itv->irq_work); - } - - spin_unlock(&itv->dma_reg_lock); - - /* If we've just handled a 'forced' vsync, it's safest to say it - * wasn't ours. Another device may have triggered it at just - * the right time. - */ - return vsync_force ? IRQ_NONE : IRQ_HANDLED; -} - -void ivtv_unfinished_dma(unsigned long arg) -{ - struct ivtv *itv = (struct ivtv *)arg; - - if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) - return; - IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); - - write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); - clear_bit(IVTV_F_I_UDMA, &itv->i_flags); - clear_bit(IVTV_F_I_DMA, &itv->i_flags); - itv->cur_dma_stream = -1; - wake_up(&itv->dma_waitq); -} |