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

📄 ivtv-yuv.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	yi->reg_2838 = read_reg(0x02838);	yi->reg_283c = read_reg(0x0283c);	yi->reg_2840 = read_reg(0x02840);	yi->reg_2844 = read_reg(0x02844);	yi->reg_2848 = read_reg(0x02848);	yi->reg_2854 = read_reg(0x02854);	yi->reg_285c = read_reg(0x0285c);	yi->reg_2864 = read_reg(0x02864);	yi->reg_2870 = read_reg(0x02870);	yi->reg_2874 = read_reg(0x02874);	yi->reg_2898 = read_reg(0x02898);	yi->reg_2890 = read_reg(0x02890);	yi->reg_289c = read_reg(0x0289c);	yi->reg_2918 = read_reg(0x02918);	yi->reg_291c = read_reg(0x0291c);	yi->reg_2920 = read_reg(0x02920);	yi->reg_2924 = read_reg(0x02924);	yi->reg_2928 = read_reg(0x02928);	yi->reg_292c = read_reg(0x0292c);	yi->reg_2930 = read_reg(0x02930);	yi->reg_2934 = read_reg(0x02934);	yi->reg_2938 = read_reg(0x02938);	yi->reg_293c = read_reg(0x0293c);	yi->reg_2940 = read_reg(0x02940);	yi->reg_2944 = read_reg(0x02944);	yi->reg_2948 = read_reg(0x02948);	yi->reg_294c = read_reg(0x0294c);	yi->reg_2950 = read_reg(0x02950);	yi->reg_2954 = read_reg(0x02954);	yi->reg_2958 = read_reg(0x02958);	yi->reg_295c = read_reg(0x0295c);	yi->reg_2960 = read_reg(0x02960);	yi->reg_2964 = read_reg(0x02964);	yi->reg_2968 = read_reg(0x02968);	yi->reg_296c = read_reg(0x0296c);	yi->reg_2970 = read_reg(0x02970);	yi->v_filter_1 = -1;	yi->v_filter_2 = -1;	yi->h_filter = -1;	/* Set some valid size info */	yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;	yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;	/* Bit 2 of reg 2878 indicates current decoder output format	   0 : NTSC    1 : PAL */	if (read_reg(0x2878) & 4)		yi->decode_height = 576;	else		yi->decode_height = 480;	if (!itv->osd_info) {		yi->osd_vis_w = 720 - yi->osd_x_offset;		yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;	} else {		/* If no visible size set, assume full size */		if (!yi->osd_vis_w)			yi->osd_vis_w = 720 - yi->osd_x_offset;		if (!yi->osd_vis_h) {			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {			/* If output video standard has changed, requested height may			   not be legal */			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",					yi->osd_vis_h + yi->osd_y_offset,					yi->decode_height);			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;		}	}	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL|__GFP_NOWARN);	if (yi->blanking_ptr) {		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);	} else {		yi->blanking_dmaptr = 0;		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");	}	/* Enable YUV decoder output */	write_reg_sync(0x01, IVTV_REG_VDM);	set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);	atomic_set(&yi->next_dma_frame, 0);}/* Get next available yuv buffer on PVR350 */static void ivtv_yuv_next_free(struct ivtv *itv){	int draw, display;	struct yuv_playback_info *yi = &itv->yuv_info;	if (atomic_read(&yi->next_dma_frame) == -1)		ivtv_yuv_init(itv);	draw = atomic_read(&yi->next_fill_frame);	display = atomic_read(&yi->next_dma_frame);	if (display > draw)		display -= IVTV_YUV_BUFFERS;	if (draw - display >= yi->max_frames_buffered)		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;	else		yi->new_frame_info[draw].update = 0;	yi->draw_frame = draw;}/* Set up frame according to ivtv_dma_frame parameters */static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args){	struct yuv_playback_info *yi = &itv->yuv_info;	u8 frame = yi->draw_frame;	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;	struct yuv_frame_info *nf = &yi->new_frame_info[frame];	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];	int lace_threshold = yi->lace_threshold;	/* Preserve old update flag in case we're overwriting a queued frame */	int update = nf->update;	/* Take a snapshot of the yuv coordinate information */	nf->src_x = args->src.left;	nf->src_y = args->src.top;	nf->src_w = args->src.width;	nf->src_h = args->src.height;	nf->dst_x = args->dst.left;	nf->dst_y = args->dst.top;	nf->dst_w = args->dst.width;	nf->dst_h = args->dst.height;	nf->tru_x = args->dst.left;	nf->tru_w = args->src_width;	nf->tru_h = args->src_height;	/* Are we going to offset the Y plane */	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;	nf->update = 0;	nf->interlaced_y = 0;	nf->interlaced_uv = 0;	nf->delay = 0;	nf->sync_field = 0;	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;	if (lace_threshold < 0)		lace_threshold = yi->decode_height - 1;	/* Work out the lace settings */	switch (nf->lace_mode) {	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */		nf->interlaced = 0;		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))			nf->interlaced_y = 0;		else			nf->interlaced_y = 1;		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))			nf->interlaced_uv = 0;		else			nf->interlaced_uv = 1;		break;	case IVTV_YUV_MODE_AUTO:		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {			nf->interlaced = 0;			if ((nf->tru_h < 512) ||			    (nf->tru_h > 576 && nf->tru_h < 1021) ||			    (nf->tru_w > 720 && nf->tru_h < 1021))				nf->interlaced_y = 0;			else				nf->interlaced_y = 1;			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))				nf->interlaced_uv = 0;			else				nf->interlaced_uv = 1;		} else {			nf->interlaced = 1;			nf->interlaced_y = 1;			nf->interlaced_uv = 1;		}		break;	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */	default:		nf->interlaced = 1;		nf->interlaced_y = 1;		nf->interlaced_uv = 1;		break;	}	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {		yi->old_frame_info_args = *nf;		nf->update = 1;		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);	}	nf->update |= update;	nf->sync_field = yi->lace_sync_field;	nf->delay = nf->sync_field != of->sync_field;}/* Frame is complete & ready for display */void ivtv_yuv_frame_complete(struct ivtv *itv){	atomic_set(&itv->yuv_info.next_fill_frame,			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);}static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args){	DEFINE_WAIT(wait);	int rc = 0;	int got_sig = 0;	/* DMA the frame */	mutex_lock(&itv->udma.lock);	if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {		mutex_unlock(&itv->udma.lock);		return rc;	}	ivtv_udma_prepare(itv);	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);	/* if no UDMA is pending and no UDMA is in progress, then the DMA	   is finished */	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {		/* don't interrupt if the DMA is in progress but break off		   a still pending DMA. */		got_sig = signal_pending(current);		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))			break;		got_sig = 0;		schedule();	}	finish_wait(&itv->dma_waitq, &wait);	/* Unmap Last DMA Xfer */	ivtv_udma_unmap(itv);	if (got_sig) {		IVTV_DEBUG_INFO("User stopped YUV UDMA\n");		mutex_unlock(&itv->udma.lock);		return -EINTR;	}	ivtv_yuv_frame_complete(itv);	mutex_unlock(&itv->udma.lock);	return rc;}/* Setup frame according to V4L2 parameters */void ivtv_yuv_setup_stream_frame(struct ivtv *itv){	struct yuv_playback_info *yi = &itv->yuv_info;	struct ivtv_dma_frame dma_args;	ivtv_yuv_next_free(itv);	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */	dma_args.y_source = NULL;	dma_args.uv_source = NULL;	dma_args.src.left = 0;	dma_args.src.top = 0;	dma_args.src.width = yi->v4l2_src_w;	dma_args.src.height = yi->v4l2_src_h;	dma_args.dst = yi->main_rect;	dma_args.src_width = yi->v4l2_src_w;	dma_args.src_height = yi->v4l2_src_h;	/* ... and use the same setup routine as ivtv_yuv_prep_frame */	ivtv_yuv_setup_frame(itv, &dma_args);	if (!itv->dma_data_req_offset)		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];}/* Attempt to dma a frame from a user buffer */int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src){	struct yuv_playback_info *yi = &itv->yuv_info;	struct ivtv_dma_frame dma_args;	ivtv_yuv_setup_stream_frame(itv);	/* We only need to supply source addresses for this */	dma_args.y_source = src;	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);	return ivtv_yuv_udma_frame(itv, &dma_args);}/* IVTV_IOC_DMA_FRAME ioctl handler */int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args){/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */	ivtv_yuv_next_free(itv);	ivtv_yuv_setup_frame(itv, args);	return ivtv_yuv_udma_frame(itv, args);}void ivtv_yuv_close(struct ivtv *itv){	struct yuv_playback_info *yi = &itv->yuv_info;	int h_filter, v_filter_1, v_filter_2;	IVTV_DEBUG_YUV("ivtv_yuv_close\n");	ivtv_waitq(&itv->vsync_waitq);	yi->running = 0;	atomic_set(&yi->next_dma_frame, -1);	atomic_set(&yi->next_fill_frame, 0);	/* Reset registers we have changed so mpeg playback works */	/* If we fully restore this register, the display may remain active.	   Restore, but set one bit to blank the video. Firmware will always	   clear this bit when needed, so not a problem. */	write_reg(yi->reg_2898 | 0x01000000, 0x2898);	write_reg(yi->reg_2834, 0x02834);	write_reg(yi->reg_2838, 0x02838);	write_reg(yi->reg_283c, 0x0283c);	write_reg(yi->reg_2840, 0x02840);	write_reg(yi->reg_2844, 0x02844);	write_reg(yi->reg_2848, 0x02848);	write_reg(yi->reg_2854, 0x02854);	write_reg(yi->reg_285c, 0x0285c);	write_reg(yi->reg_2864, 0x02864);	write_reg(yi->reg_2870, 0x02870);	write_reg(yi->reg_2874, 0x02874);	write_reg(yi->reg_2890, 0x02890);	write_reg(yi->reg_289c, 0x0289c);	write_reg(yi->reg_2918, 0x02918);	write_reg(yi->reg_291c, 0x0291c);	write_reg(yi->reg_2920, 0x02920);	write_reg(yi->reg_2924, 0x02924);	write_reg(yi->reg_2928, 0x02928);	write_reg(yi->reg_292c, 0x0292c);	write_reg(yi->reg_2930, 0x02930);	write_reg(yi->reg_2934, 0x02934);	write_reg(yi->reg_2938, 0x02938);	write_reg(yi->reg_293c, 0x0293c);	write_reg(yi->reg_2940, 0x02940);	write_reg(yi->reg_2944, 0x02944);	write_reg(yi->reg_2948, 0x02948);	write_reg(yi->reg_294c, 0x0294c);	write_reg(yi->reg_2950, 0x02950);	write_reg(yi->reg_2954, 0x02954);	write_reg(yi->reg_2958, 0x02958);	write_reg(yi->reg_295c, 0x0295c);	write_reg(yi->reg_2960, 0x02960);	write_reg(yi->reg_2964, 0x02964);	write_reg(yi->reg_2968, 0x02968);	write_reg(yi->reg_296c, 0x0296c);	write_reg(yi->reg_2970, 0x02970);	/* Prepare to restore filters */	/* First the horizontal filter */	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {		/* An exact size match uses filter 0 */		h_filter = 0;	} else {		/* Figure out which filter to use */		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;		h_filter = (h_filter >> 1) + (h_filter & 1);		/* Only an exact size match can use filter 0. */		h_filter += !h_filter;	}	/* Now the vertical filter */	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {		/* An exact size match uses filter 0/1 */		v_filter_1 = 0;		v_filter_2 = 1;	} else {		/* Figure out which filter to use */		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);		/* Only an exact size match can use filter 0 */		v_filter_1 += !v_filter_1;		v_filter_2 = v_filter_1;	}	/* Now restore the filters */	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);	/* and clear a few registers */	write_reg(0, 0x02814);	write_reg(0, 0x0282c);	write_reg(0, 0x02904);	write_reg(0, 0x02910);	/* Release the blanking buffer */	if (yi->blanking_ptr) {		kfree(yi->blanking_ptr);		yi->blanking_ptr = NULL;		pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);	}	/* Invalidate the old dimension information */	yi->old_frame_info.src_w = 0;	yi->old_frame_info.src_h = 0;	yi->old_frame_info_args.src_w = 0;	yi->old_frame_info_args.src_h = 0;	/* All done. */	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);}

⌨️ 快捷键说明

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