⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ivtv-irq.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				/* 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);	}	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;	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, data);	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[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;	}	del_timer(&itv->dma_timer);	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];	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);	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 */		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;	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, 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){	struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];	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 more than two VBI buffers are pending, then	   clear the old ones and start with this new one.	   This can happen during transition stages when MPEG capturing is	   started, but the first interrupts haven't arrived yet. During	   that period VBI requests can accumulate without being able to	   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_pending_size > 2) {		struct ivtv_buffer *buf;		list_for_each_entry(buf, &s->q_predma.list, list)			ivtv_buf_sync_for_cpu(s, buf);		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 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. */	if (!stream_enc_dma_append(s, data) &&			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {		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 */	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {		itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;		itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];	}	else {		itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];		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 {		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(0x28c0) & 1;	int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");	if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&		((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||			(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {		int next_dma_frame = last_dma_frame;		if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.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) & 0x3;				atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);				itv->yuv_info.fields_lapsed = -1;			}		}	}	if (frame != (itv->last_vsync_field & 1)) {		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);		}		wake_up(&itv->vsync_waitq);		if (s)			wake_up(&s->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 ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {			if (!itv->yuv_info.new_frame_info[last_dma_frame].update)				last_dma_frame = (last_dma_frame - 1) & 3;			if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {				itv->yuv_info.update_frame = last_dma_frame;				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;				itv->yuv_info.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);			}		}		itv->yuv_info.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(0x28c0) & 1)) {				/* New field, looks like we missed it */				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>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_and_clear_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_work(itv->irq_work_queues, &itv->irq_work_queue);	}	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);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -