saa7146_hlp.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,046 行 · 第 1/2 页

C
1,046
字号
{	struct saa7146_vv *vv = dev->vv_data;	int source = vv->current_hps_source;	int sync = vv->current_hps_sync;	u32 hps_v_scale = 0, hps_v_gain  = 0, hps_ctrl = 0, hps_h_prescale = 0, hps_h_scale = 0;	/* set vertical scale */	hps_v_scale = 0; /* all bits get set by the function-call */	hps_v_gain  = 0; /* fixme: saa7146_read(dev, HPS_V_GAIN);*/	calculate_v_scale_registers(dev, field, vv->standard->v_field*2, height, &hps_v_scale, &hps_v_gain);	/* set horizontal scale */	hps_ctrl	= 0;	hps_h_prescale	= 0; /* all bits get set in the function */	hps_h_scale	= 0;	calculate_h_scale_registers(dev, vv->standard->h_pixels, width, vv->hflip, &hps_ctrl, &hps_v_gain, &hps_h_prescale, &hps_h_scale);	/* set hyo and hxo */	calculate_hxo_and_hyo(vv, &hps_h_scale, &hps_ctrl);	calculate_hps_source_and_sync(dev, source, sync, &hps_ctrl);	/* write out new register contents */	saa7146_write(dev, HPS_V_SCALE,	hps_v_scale);	saa7146_write(dev, HPS_V_GAIN,	hps_v_gain);	saa7146_write(dev, HPS_CTRL,	hps_ctrl);	saa7146_write(dev, HPS_H_PRESCALE,hps_h_prescale);	saa7146_write(dev, HPS_H_SCALE,	hps_h_scale);	/* upload shadow-ram registers */	saa7146_write(dev, MC2, (MASK_05 | MASK_06 | MASK_21 | MASK_22) );}/* calculate the new memory offsets for a desired position */static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat){	struct saa7146_vv *vv = dev->vv_data;	struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);	int b_depth = vv->ov_fmt->depth;	int b_bpl = vv->ov_fb.fmt.bytesperline;	/* The unsigned long cast is to remove a 64-bit compile warning since	   it looks like a 64-bit address is cast to a 32-bit value, even	   though the base pointer is really a 32-bit physical address that	   goes into a 32-bit DMA register.	   FIXME: might not work on some 64-bit platforms, but see the FIXME	   in struct v4l2_framebuffer (videodev2.h) for that.	 */	u32 base = (u32)(unsigned long)vv->ov_fb.base;	struct	saa7146_video_dma vdma1;	/* calculate memory offsets for picture, look if we shall top-down-flip */	vdma1.pitch	= 2*b_bpl;	if ( 0 == vv->vflip ) {		vdma1.base_even = base + (w_y * (vdma1.pitch/2)) + (w_x * (b_depth / 8));		vdma1.base_odd  = vdma1.base_even + (vdma1.pitch / 2);		vdma1.prot_addr = vdma1.base_even + (w_height * (vdma1.pitch / 2));	}	else {		vdma1.base_even = base + ((w_y+w_height) * (vdma1.pitch/2)) + (w_x * (b_depth / 8));		vdma1.base_odd  = vdma1.base_even - (vdma1.pitch / 2);		vdma1.prot_addr = vdma1.base_odd - (w_height * (vdma1.pitch / 2));	}	if (V4L2_FIELD_HAS_BOTH(field)) {	} else if (field == V4L2_FIELD_ALTERNATE) {		/* fixme */		vdma1.base_odd = vdma1.prot_addr;		vdma1.pitch /= 2;	} else if (field == V4L2_FIELD_TOP) {		vdma1.base_odd = vdma1.prot_addr;		vdma1.pitch /= 2;	} else if (field == V4L2_FIELD_BOTTOM) {		vdma1.base_odd = vdma1.base_even;		vdma1.base_even = vdma1.prot_addr;		vdma1.pitch /= 2;	}	if ( 0 != vv->vflip ) {		vdma1.pitch *= -1;	}	vdma1.base_page = sfmt->swap;	vdma1.num_line_byte = (vv->standard->v_field<<16)+vv->standard->h_pixels;	saa7146_write_out_dma(dev, 1, &vdma1);}static void saa7146_set_output_format(struct saa7146_dev *dev, unsigned long palette){	u32 clip_format = saa7146_read(dev, CLIP_FORMAT_CTRL);	/* call helper function */	calculate_output_format_register(dev,palette,&clip_format);	/* update the hps registers */	saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format);	saa7146_write(dev, MC2, (MASK_05 | MASK_21));}/* select input-source */void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync){	struct saa7146_vv *vv = dev->vv_data;	u32 hps_ctrl = 0;	/* read old state */	hps_ctrl = saa7146_read(dev, HPS_CTRL);	hps_ctrl &= ~( MASK_31 | MASK_30 | MASK_28 );	hps_ctrl |= (source << 30) | (sync << 28);	/* write back & upload register */	saa7146_write(dev, HPS_CTRL, hps_ctrl);	saa7146_write(dev, MC2, (MASK_05 | MASK_21));	vv->current_hps_source = source;	vv->current_hps_sync = sync;}EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);int saa7146_enable_overlay(struct saa7146_fh *fh){	struct saa7146_dev *dev = fh->dev;	struct saa7146_vv *vv = dev->vv_data;	saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);	saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);	saa7146_set_output_format(dev, vv->ov_fmt->trans);	saa7146_set_clipping_rect(fh);	/* enable video dma1 */	saa7146_write(dev, MC1, (MASK_06 | MASK_22));	return 0;}void saa7146_disable_overlay(struct saa7146_fh *fh){	struct saa7146_dev *dev = fh->dev;	/* disable clipping + video dma1 */	saa7146_disable_clipping(dev);	saa7146_write(dev, MC1, MASK_22);}void saa7146_write_out_dma(struct saa7146_dev* dev, int which, struct saa7146_video_dma* vdma){	int where = 0;	if( which < 1 || which > 3) {		return;	}	/* calculate starting address */	where  = (which-1)*0x18;	saa7146_write(dev, where,	vdma->base_odd);	saa7146_write(dev, where+0x04,	vdma->base_even);	saa7146_write(dev, where+0x08,	vdma->prot_addr);	saa7146_write(dev, where+0x0c,	vdma->pitch);	saa7146_write(dev, where+0x10,	vdma->base_page);	saa7146_write(dev, where+0x14,	vdma->num_line_byte);	/* upload */	saa7146_write(dev, MC2, (MASK_02<<(which-1))|(MASK_18<<(which-1)));/*	printk("vdma%d.base_even:     0x%08x\n", which,vdma->base_even);	printk("vdma%d.base_odd:      0x%08x\n", which,vdma->base_odd);	printk("vdma%d.prot_addr:     0x%08x\n", which,vdma->prot_addr);	printk("vdma%d.base_page:     0x%08x\n", which,vdma->base_page);	printk("vdma%d.pitch:         0x%08x\n", which,vdma->pitch);	printk("vdma%d.num_line_byte: 0x%08x\n", which,vdma->num_line_byte);*/}static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa7146_buf *buf){	struct saa7146_vv *vv = dev->vv_data;	struct saa7146_video_dma vdma1;	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);	int width = buf->fmt->width;	int height = buf->fmt->height;	int bytesperline = buf->fmt->bytesperline;	enum v4l2_field field = buf->fmt->field;	int depth = sfmt->depth;	DEB_CAP(("[size=%dx%d,fields=%s]\n",		width,height,v4l2_field_names[field]));	if( bytesperline != 0) {		vdma1.pitch = bytesperline*2;	} else {		vdma1.pitch = (width*depth*2)/8;	}	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);	vdma1.base_page		= buf->pt[0].dma | ME1 | sfmt->swap;	if( 0 != vv->vflip ) {		vdma1.prot_addr	= buf->pt[0].offset;		vdma1.base_even	= buf->pt[0].offset+(vdma1.pitch/2)*height;		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);	} else {		vdma1.base_even	= buf->pt[0].offset;		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);		vdma1.prot_addr	= buf->pt[0].offset+(vdma1.pitch/2)*height;	}	if (V4L2_FIELD_HAS_BOTH(field)) {	} else if (field == V4L2_FIELD_ALTERNATE) {		/* fixme */		if ( vv->last_field == V4L2_FIELD_TOP ) {			vdma1.base_odd	= vdma1.prot_addr;			vdma1.pitch /= 2;		} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {			vdma1.base_odd	= vdma1.base_even;			vdma1.base_even = vdma1.prot_addr;			vdma1.pitch /= 2;		}	} else if (field == V4L2_FIELD_TOP) {		vdma1.base_odd	= vdma1.prot_addr;		vdma1.pitch /= 2;	} else if (field == V4L2_FIELD_BOTTOM) {		vdma1.base_odd	= vdma1.base_even;		vdma1.base_even = vdma1.prot_addr;		vdma1.pitch /= 2;	}	if( 0 != vv->vflip ) {		vdma1.pitch *= -1;	}	saa7146_write_out_dma(dev, 1, &vdma1);	return 0;}static int calc_planar_422(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3){	int height = buf->fmt->height;	int width = buf->fmt->width;	vdma2->pitch	= width;	vdma3->pitch	= width;	/* fixme: look at bytesperline! */	if( 0 != vv->vflip ) {		vdma2->prot_addr	= buf->pt[1].offset;		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[1].offset;		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);		vdma3->prot_addr	= buf->pt[2].offset;		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[2].offset;		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);	} else {		vdma3->base_even	= buf->pt[2].offset;		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch/2);		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;		vdma2->base_even	= buf->pt[1].offset;		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch/2);		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;	}	return 0;}static int calc_planar_420(struct saa7146_vv *vv, struct saa7146_buf *buf, struct saa7146_video_dma *vdma2, struct saa7146_video_dma *vdma3){	int height = buf->fmt->height;	int width = buf->fmt->width;	vdma2->pitch	= width/2;	vdma3->pitch	= width/2;	if( 0 != vv->vflip ) {		vdma2->prot_addr	= buf->pt[2].offset;		vdma2->base_even	= ((vdma2->pitch/2)*height)+buf->pt[2].offset;		vdma2->base_odd		= vdma2->base_even - (vdma2->pitch/2);		vdma3->prot_addr	= buf->pt[1].offset;		vdma3->base_even	= ((vdma3->pitch/2)*height)+buf->pt[1].offset;		vdma3->base_odd		= vdma3->base_even - (vdma3->pitch/2);	} else {		vdma3->base_even	= buf->pt[2].offset;		vdma3->base_odd		= vdma3->base_even + (vdma3->pitch);		vdma3->prot_addr	= (vdma3->pitch/2)*height+buf->pt[2].offset;		vdma2->base_even	= buf->pt[1].offset;		vdma2->base_odd		= vdma2->base_even + (vdma2->pitch);		vdma2->prot_addr	= (vdma2->pitch/2)*height+buf->pt[1].offset;	}	return 0;}static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa7146_buf *buf){	struct saa7146_vv *vv = dev->vv_data;	struct saa7146_video_dma vdma1;	struct saa7146_video_dma vdma2;	struct saa7146_video_dma vdma3;	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);	int width = buf->fmt->width;	int height = buf->fmt->height;	enum v4l2_field field = buf->fmt->field;	BUG_ON(0 == buf->pt[0].dma);	BUG_ON(0 == buf->pt[1].dma);	BUG_ON(0 == buf->pt[2].dma);	DEB_CAP(("[size=%dx%d,fields=%s]\n",		width,height,v4l2_field_names[field]));	/* fixme: look at bytesperline! */	/* fixme: what happens for user space buffers here?. The offsets are	   most likely wrong, this version here only works for page-aligned	   buffers, modifications to the pagetable-functions are necessary...*/	vdma1.pitch		= width*2;	vdma1.num_line_byte	= ((vv->standard->v_field<<16) + vv->standard->h_pixels);	vdma1.base_page		= buf->pt[0].dma | ME1;	if( 0 != vv->vflip ) {		vdma1.prot_addr	= buf->pt[0].offset;		vdma1.base_even	= ((vdma1.pitch/2)*height)+buf->pt[0].offset;		vdma1.base_odd	= vdma1.base_even - (vdma1.pitch/2);	} else {		vdma1.base_even	= buf->pt[0].offset;		vdma1.base_odd	= vdma1.base_even + (vdma1.pitch/2);		vdma1.prot_addr	= (vdma1.pitch/2)*height+buf->pt[0].offset;	}	vdma2.num_line_byte	= 0; /* unused */	vdma2.base_page		= buf->pt[1].dma | ME1;	vdma3.num_line_byte	= 0; /* unused */	vdma3.base_page		= buf->pt[2].dma | ME1;	switch( sfmt->depth ) {		case 12: {			calc_planar_420(vv,buf,&vdma2,&vdma3);			break;		}		case 16: {			calc_planar_422(vv,buf,&vdma2,&vdma3);			break;		}		default: {			return -1;		}	}	if (V4L2_FIELD_HAS_BOTH(field)) {	} else if (field == V4L2_FIELD_ALTERNATE) {		/* fixme */		vdma1.base_odd	= vdma1.prot_addr;		vdma1.pitch /= 2;		vdma2.base_odd	= vdma2.prot_addr;		vdma2.pitch /= 2;		vdma3.base_odd	= vdma3.prot_addr;		vdma3.pitch /= 2;	} else if (field == V4L2_FIELD_TOP) {		vdma1.base_odd	= vdma1.prot_addr;		vdma1.pitch /= 2;		vdma2.base_odd	= vdma2.prot_addr;		vdma2.pitch /= 2;		vdma3.base_odd	= vdma3.prot_addr;		vdma3.pitch /= 2;	} else if (field == V4L2_FIELD_BOTTOM) {		vdma1.base_odd	= vdma1.base_even;		vdma1.base_even = vdma1.prot_addr;		vdma1.pitch /= 2;		vdma2.base_odd	= vdma2.base_even;		vdma2.base_even = vdma2.prot_addr;		vdma2.pitch /= 2;		vdma3.base_odd	= vdma3.base_even;		vdma3.base_even = vdma3.prot_addr;		vdma3.pitch /= 2;	}	if( 0 != vv->vflip ) {		vdma1.pitch *= -1;		vdma2.pitch *= -1;		vdma3.pitch *= -1;	}	saa7146_write_out_dma(dev, 1, &vdma1);	if( (sfmt->flags & FORMAT_BYTE_SWAP) != 0 ) {		saa7146_write_out_dma(dev, 3, &vdma2);		saa7146_write_out_dma(dev, 2, &vdma3);	} else {		saa7146_write_out_dma(dev, 2, &vdma2);		saa7146_write_out_dma(dev, 3, &vdma3);	}	return 0;}static void program_capture_engine(struct saa7146_dev *dev, int planar){	struct saa7146_vv *vv = dev->vv_data;	int count = 0;	unsigned long e_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_E_FID_A : CMD_E_FID_B;	unsigned long o_wait = vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? CMD_O_FID_A : CMD_O_FID_B;	/* wait for o_fid_a/b / e_fid_a/b toggle only if rps register 0 is not set*/	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | o_wait);	WRITE_RPS0(CMD_PAUSE | CMD_OAN | CMD_SIG0 | e_wait);	/* set rps register 0 */	WRITE_RPS0(CMD_WR_REG | (1 << 8) | (MC2/4));	WRITE_RPS0(MASK_27 | MASK_11);	/* turn on video-dma1 */	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));	WRITE_RPS0(MASK_06 | MASK_22);			/* => mask */	WRITE_RPS0(MASK_06 | MASK_22);			/* => values */	if( 0 != planar ) {		/* turn on video-dma2 */		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */		WRITE_RPS0(MASK_05 | MASK_21);			/* => values */		/* turn on video-dma3 */		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */		WRITE_RPS0(MASK_04 | MASK_20);			/* => values */	}	/* wait for o_fid_a/b / e_fid_a/b toggle */	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {		WRITE_RPS0(CMD_PAUSE | o_wait);		WRITE_RPS0(CMD_PAUSE | e_wait);	} else if ( vv->last_field == V4L2_FIELD_TOP ) {		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));		WRITE_RPS0(CMD_PAUSE | o_wait);	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {		WRITE_RPS0(CMD_PAUSE | (vv->current_hps_sync == SAA7146_HPS_SYNC_PORT_A ? MASK_10 : MASK_09));		WRITE_RPS0(CMD_PAUSE | e_wait);	}	/* turn off video-dma1 */	WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));	WRITE_RPS0(MASK_22 | MASK_06);			/* => mask */	WRITE_RPS0(MASK_22);				/* => values */	if( 0 != planar ) {		/* turn off video-dma2 */		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		WRITE_RPS0(MASK_05 | MASK_21);			/* => mask */		WRITE_RPS0(MASK_21);				/* => values */		/* turn off video-dma3 */		WRITE_RPS0(CMD_WR_REG_MASK | (MC1/4));		WRITE_RPS0(MASK_04 | MASK_20);			/* => mask */		WRITE_RPS0(MASK_20);				/* => values */	}	/* generate interrupt */	WRITE_RPS0(CMD_INTERRUPT);	/* stop */	WRITE_RPS0(CMD_STOP);}void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next){	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);	struct saa7146_vv *vv = dev->vv_data;	u32 vdma1_prot_addr;	DEB_CAP(("buf:%p, next:%p\n",buf,next));	vdma1_prot_addr = saa7146_read(dev, PROT_ADDR1);	if( 0 == vdma1_prot_addr ) {		/* clear out beginning of streaming bit (rps register 0)*/		DEB_CAP(("forcing sync to new frame\n"));		saa7146_write(dev, MC2, MASK_27 );	}	saa7146_set_window(dev, buf->fmt->width, buf->fmt->height, buf->fmt->field);	saa7146_set_output_format(dev, sfmt->trans);	saa7146_disable_clipping(dev);	if ( vv->last_field == V4L2_FIELD_INTERLACED ) {	} else if ( vv->last_field == V4L2_FIELD_TOP ) {		vv->last_field = V4L2_FIELD_BOTTOM;	} else if ( vv->last_field == V4L2_FIELD_BOTTOM ) {		vv->last_field = V4L2_FIELD_TOP;	}	if( 0 != IS_PLANAR(sfmt->trans)) {		calculate_video_dma_grab_planar(dev, buf);		program_capture_engine(dev,1);	} else {		calculate_video_dma_grab_packed(dev, buf);		program_capture_engine(dev,0);	}/*	printk("vdma%d.base_even:     0x%08x\n", 1,saa7146_read(dev,BASE_EVEN1));	printk("vdma%d.base_odd:      0x%08x\n", 1,saa7146_read(dev,BASE_ODD1));	printk("vdma%d.prot_addr:     0x%08x\n", 1,saa7146_read(dev,PROT_ADDR1));	printk("vdma%d.base_page:     0x%08x\n", 1,saa7146_read(dev,BASE_PAGE1));	printk("vdma%d.pitch:         0x%08x\n", 1,saa7146_read(dev,PITCH1));	printk("vdma%d.num_line_byte: 0x%08x\n", 1,saa7146_read(dev,NUM_LINE_BYTE1));	printk("vdma%d => vptr      : 0x%08x\n", 1,saa7146_read(dev,PCI_VDP1));*/	/* write the address of the rps-program */	saa7146_write(dev, RPS_ADDR0, dev->d_rps0.dma_handle);	/* turn on rps */	saa7146_write(dev, MC1, (MASK_12 | MASK_28));}

⌨️ 快捷键说明

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