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

📄 ivtv-yuv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		window->src_h &= ~3;		window->dst_h = window->src_h / 4;		window->dst_h += window->dst_h & 1;	}	/* Check again. If there's nothing to safe to display, stop now */	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {		return IVTV_YUV_UPDATE_INVALID;	}	/* Both x offset & width are linked, so they have to be done together */	if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||	    (itv->yuv_info.old_frame_info.src_w != window->src_w) ||	    (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||	    (itv->yuv_info.old_frame_info.src_x != window->src_x) ||	    (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||	    (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;	}	if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||	    (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||	    (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||	    (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;	}	return yuv_update;}/* Update the scaling register to the requested value */void ivtv_yuv_work_handler (struct ivtv *itv){	struct yuv_frame_info window;	u32 yuv_update;	int frame = itv->yuv_info.update_frame;/*	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */	memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));	/* Update the osd pan info */	window.pan_x = itv->yuv_info.osd_x_pan;	window.pan_y = itv->yuv_info.osd_y_pan;	window.vis_w = itv->yuv_info.osd_vis_w;	window.vis_h = itv->yuv_info.osd_vis_h;	/* Calculate the display window coordinates. Exit if nothing left */	if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))		return;	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {		write_reg(0x01008080, 0x2898);	} else if (yuv_update) {		write_reg(0x00108080, 0x2898);		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)			ivtv_yuv_handle_horizontal(itv, &window);		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)			ivtv_yuv_handle_vertical(itv, &window);	}	memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));}static void ivtv_yuv_init (struct ivtv *itv){	struct yuv_playback_info *yi = &itv->yuv_info;	IVTV_DEBUG_YUV("ivtv_yuv_init\n");	/* Take a snapshot of the current register settings */	yi->reg_2834 = read_reg(0x02834);	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 output video standard has changed, requested height may			not be legal */			if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {				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);	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);}int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args){	DEFINE_WAIT(wait);	int rc = 0;	int got_sig = 0;	int frame, next_fill_frame, last_fill_frame;	int register_update = 0;	IVTV_DEBUG_INFO("yuv_prep_frame\n");	if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);	frame = atomic_read(&itv->yuv_info.next_fill_frame);	next_fill_frame = (frame + 1) & 0x3;	last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;	if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {		/* Buffers are full - Overwrite the last frame */		next_fill_frame = frame;		frame = (frame - 1) & 3;		register_update = itv->yuv_info.new_frame_info[frame].update;	}	/* Take a snapshot of the yuv coordinate information */	itv->yuv_info.new_frame_info[frame].src_x = args->src.left;	itv->yuv_info.new_frame_info[frame].src_y = args->src.top;	itv->yuv_info.new_frame_info[frame].src_w = args->src.width;	itv->yuv_info.new_frame_info[frame].src_h = args->src.height;	itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;	itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;	itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;	itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;	itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;	/* Snapshot field order */	itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;	/* Are we going to offset the Y plane */	if (args->src.height + args->src.top < 512-16)		itv->yuv_info.new_frame_info[frame].offset_y = 1;	else		itv->yuv_info.new_frame_info[frame].offset_y = 0;	/* Snapshot the osd pan info */	itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;	itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;	itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;	itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;	itv->yuv_info.new_frame_info[frame].update = 0;	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;	itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],	    sizeof (itv->yuv_info.new_frame_info[frame]))) {		memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));		itv->yuv_info.new_frame_info[frame].update = 1;/*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */	}	itv->yuv_info.new_frame_info[frame].update |= register_update;	/* Should this frame be delayed ? */	if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])		itv->yuv_info.field_delay[frame] = 1;	else		itv->yuv_info.field_delay[frame] = 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;	}	atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);	mutex_unlock(&itv->udma.lock);	return rc;}void ivtv_yuv_close(struct ivtv *itv){	int h_filter, v_filter_1, v_filter_2;	IVTV_DEBUG_YUV("ivtv_yuv_close\n");	ivtv_waitq(&itv->vsync_waitq);	atomic_set(&itv->yuv_info.next_dma_frame, -1);	atomic_set(&itv->yuv_info.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(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);	write_reg(itv->yuv_info.reg_2834, 0x02834);	write_reg(itv->yuv_info.reg_2838, 0x02838);	write_reg(itv->yuv_info.reg_283c, 0x0283c);	write_reg(itv->yuv_info.reg_2840, 0x02840);	write_reg(itv->yuv_info.reg_2844, 0x02844);	write_reg(itv->yuv_info.reg_2848, 0x02848);	write_reg(itv->yuv_info.reg_2854, 0x02854);	write_reg(itv->yuv_info.reg_285c, 0x0285c);	write_reg(itv->yuv_info.reg_2864, 0x02864);	write_reg(itv->yuv_info.reg_2870, 0x02870);	write_reg(itv->yuv_info.reg_2874, 0x02874);	write_reg(itv->yuv_info.reg_2890, 0x02890);	write_reg(itv->yuv_info.reg_289c, 0x0289c);	write_reg(itv->yuv_info.reg_2918, 0x02918);	write_reg(itv->yuv_info.reg_291c, 0x0291c);	write_reg(itv->yuv_info.reg_2920, 0x02920);	write_reg(itv->yuv_info.reg_2924, 0x02924);	write_reg(itv->yuv_info.reg_2928, 0x02928);	write_reg(itv->yuv_info.reg_292c, 0x0292c);	write_reg(itv->yuv_info.reg_2930, 0x02930);	write_reg(itv->yuv_info.reg_2934, 0x02934);	write_reg(itv->yuv_info.reg_2938, 0x02938);	write_reg(itv->yuv_info.reg_293c, 0x0293c);	write_reg(itv->yuv_info.reg_2940, 0x02940);	write_reg(itv->yuv_info.reg_2944, 0x02944);	write_reg(itv->yuv_info.reg_2948, 0x02948);	write_reg(itv->yuv_info.reg_294c, 0x0294c);	write_reg(itv->yuv_info.reg_2950, 0x02950);	write_reg(itv->yuv_info.reg_2954, 0x02954);	write_reg(itv->yuv_info.reg_2958, 0x02958);	write_reg(itv->yuv_info.reg_295c, 0x0295c);	write_reg(itv->yuv_info.reg_2960, 0x02960);	write_reg(itv->yuv_info.reg_2964, 0x02964);	write_reg(itv->yuv_info.reg_2968, 0x02968);	write_reg(itv->yuv_info.reg_296c, 0x0296c);	write_reg(itv->yuv_info.reg_2970, 0x02970);	/* Prepare to restore filters */	/* First the horizontal filter */	if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {		/* An exact size match uses filter 0 */		h_filter = 0;	}	else {		/* Figure out which filter to use */		h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;		h_filter = (h_filter >> 1) + (h_filter & 1);		/* Only an exact size match can use filter 0. */		if (h_filter < 1) h_filter = 1;	}	/* Now the vertical filter */	if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.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 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);		/* Only an exact size match can use filter 0 */		if (v_filter_1 == 0) v_filter_1 = 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 (itv->yuv_info.blanking_ptr) {		kfree (itv->yuv_info.blanking_ptr);		itv->yuv_info.blanking_ptr = NULL;		pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);	}	/* Invalidate the old dimension information */	itv->yuv_info.old_frame_info.src_w = 0;	itv->yuv_info.old_frame_info.src_h = 0;	itv->yuv_info.old_frame_info_args.src_w = 0;	itv->yuv_info.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 + -