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

📄 cx88-video.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
		return 0;	}	cx_andor(MO_AFECFG_IO, 0x1f, 0x0);	cx88_set_tvaudio(dev);	// cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);	cx_write(MO_AUDD_LNGTH, 128/8);  /* fifo size */	cx_write(MO_AUDR_LNGTH, 128/8);  /* fifo size */	cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */	return 0;}static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm){	u32 fsc8;	u32 adc_clock;	u32 vdec_clock;	u64 tmp64;	u32 bdelay,agcdelay,htotal;		dev->tvnorm = norm;	fsc8       = norm_fsc8(norm);	adc_clock  = xtal;	vdec_clock = fsc8;	dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d\n",		norm->name, fsc8, adc_clock, vdec_clock);	set_pll(dev,2,vdec_clock);		dprintk(1,"set_tvnorm: MO_INPUT_FORMAT  0x%08x [old=0x%08x]\n",		norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);	cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);#if 1	// FIXME: as-is from DScaler	dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",		norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));	cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);#endif	// MO_SCONV_REG = adc clock / video dec clock * 2^17	tmp64  = adc_clock * (u64)(1 << 17);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SCONV_REG     0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SCONV_REG));	cx_write(MO_SCONV_REG, (u32)tmp64);	// MO_SUB_STEP = 8 * fsc / video dec clock * 2^22	tmp64  = fsc8 * (u64)(1 << 22);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SUB_STEP      0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SUB_STEP));	cx_write(MO_SUB_STEP, (u32)tmp64);	// MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22	tmp64  = 4406250 * 8 * (u64)(1 << 22);	do_div(tmp64, vdec_clock);	dprintk(1,"set_tvnorm: MO_SUB_STEP_DR   0x%08x [old=0x%08x]\n",		(u32)tmp64, cx_read(MO_SUB_STEP_DR));	cx_write(MO_SUB_STEP_DR, (u32)tmp64);	// bdelay + agcdelay	bdelay   = vdec_clock * 65 / 20000000 + 21;	agcdelay = vdec_clock * 68 / 20000000 + 15;	dprintk(1,"set_tvnorm: MO_AGC_BURST     0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",		(bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);	cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);	// htotal	tmp64 = norm_htotal(norm) * (u64)vdec_clock;	do_div(tmp64, fsc8);	htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);	dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",		htotal, cx_read(MO_HTOTAL), (u32)tmp64);	cx_write(MO_HTOTAL, htotal);	// vbi stuff	cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm)   << 11) | */				 norm_vbipack(norm)));		// audio	set_tvaudio(dev);	// tell i2c chips#ifdef V4L2_I2C_CLIENTS	cx8800_call_i2c_clients(dev,VIDIOC_S_STD,&norm->id);#else	{		struct video_channel c;		memset(&c,0,sizeof(c));		c.channel = dev->input;		c.norm = VIDEO_MODE_PAL;		if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))			c.norm = VIDEO_MODE_NTSC;		if (norm->id & V4L2_STD_SECAM)			c.norm = VIDEO_MODE_SECAM;		cx8800_call_i2c_clients(dev,VIDIOCSCHAN,&c);	}#endif	// done	return 0;}static int set_scale(struct cx8800_dev *dev, unsigned int width, unsigned int height,		     enum v4l2_field field){	unsigned int swidth  = norm_swidth(dev->tvnorm);	unsigned int sheight = norm_maxh(dev->tvnorm);	u32 value;	dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,		V4L2_FIELD_HAS_TOP(field)    ? "T" : "",		V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",		dev->tvnorm->name);	if (!V4L2_FIELD_HAS_BOTH(field))		height *= 2;	// recalc H delay and scale registers	value = (width * norm_hdelay(dev->tvnorm)) / swidth;	value &= 0x3fe;	cx_write(MO_HDELAY_EVEN,  value);	cx_write(MO_HDELAY_ODD,   value);	dprintk(1,"set_scale: hdelay  0x%04x\n", value);		value = (swidth * 4096 / width) - 4096;	cx_write(MO_HSCALE_EVEN,  value);	cx_write(MO_HSCALE_ODD,   value);	dprintk(1,"set_scale: hscale  0x%04x\n", value);	cx_write(MO_HACTIVE_EVEN, width);	cx_write(MO_HACTIVE_ODD,  width);	dprintk(1,"set_scale: hactive 0x%04x\n", width);		// recalc V scale Register (delay is constant)	cx_write(MO_VDELAY_EVEN, norm_vdelay(dev->tvnorm));	cx_write(MO_VDELAY_ODD,  norm_vdelay(dev->tvnorm));	dprintk(1,"set_scale: vdelay  0x%04x\n", norm_vdelay(dev->tvnorm));		value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;	cx_write(MO_VSCALE_EVEN,  value);	cx_write(MO_VSCALE_ODD,   value);	dprintk(1,"set_scale: vscale  0x%04x\n", value);	cx_write(MO_VACTIVE_EVEN, sheight);	cx_write(MO_VACTIVE_ODD,  sheight);	dprintk(1,"set_scale: vactive 0x%04x\n", sheight);	// setup filters	value = 0;	value |= (1 << 19);        // CFILT (default)	if (V4L2_FIELD_INTERLACED == field)		value |= (1 << 3); // VINT (interlaced vertical scaling)	if (width < 385)		value |= (1 << 0); // 3-tap interpolation	if (width < 193)		value |= (1 << 1); // 5-tap interpolation	cx_write(MO_FILTER_EVEN,  value);	cx_write(MO_FILTER_ODD,   value);	dprintk(1,"set_scale: filter  0x%04x\n", value);		return 0;}static int video_mux(struct cx8800_dev *dev, unsigned int input){	dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",		input, INPUT(input)->vmux,		INPUT(input)->gpio0,INPUT(input)->gpio1,		INPUT(input)->gpio2,INPUT(input)->gpio3);	dev->input = input;	cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14);	cx_write(MO_GP0_IO, INPUT(input)->gpio0);	cx_write(MO_GP1_IO, INPUT(input)->gpio1);	cx_write(MO_GP2_IO, INPUT(input)->gpio2);	cx_write(MO_GP3_IO, INPUT(input)->gpio3);	switch (INPUT(input)->type) {	case CX88_VMUX_SVIDEO:		cx_set(MO_AFECFG_IO,    0x00000001);		cx_set(MO_INPUT_FORMAT, 0x00010010);		break;	default:		cx_clear(MO_AFECFG_IO,    0x00000001);		cx_clear(MO_INPUT_FORMAT, 0x00010010);		break;	}	return 0;}/* ------------------------------------------------------------------ */static int start_video_dma(struct cx8800_dev    *dev,			   struct cx88_dmaqueue *q,			   struct cx88_buffer   *buf){	/* setup fifo + format */	cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH21],				buf->bpl, buf->risc.dma);	set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);	cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);	/* reset counter */	cx_write(MO_VIDY_GPCNTRL,0x3);	q->count = 1;	/* enable irqs */	cx_set(MO_PCI_INTMSK, 0x00fc01);	cx_set(MO_VID_INTMSK, 0x0f0011);		/* enable capture */	cx_set(VID_CAPTURE_CONTROL,0x06);		/* start dma */	cx_set(MO_DEV_CNTRL2, (1<<5));	cx_set(MO_VID_DMACNTRL, 0x11);	return 0;}static int restart_video_queue(struct cx8800_dev    *dev,			       struct cx88_dmaqueue *q){	struct cx88_buffer *buf, *prev;	struct list_head *item;		if (!list_empty(&q->active)) {	        buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);		dprintk(2,"restart_queue [%p/%d]: restart dma\n",			buf, buf->vb.i);		start_video_dma(dev, q, buf);		list_for_each(item,&q->active) {			buf = list_entry(item, struct cx88_buffer, vb.queue);			buf->count    = q->count++;		}		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);		return 0;	}	prev = NULL;	for (;;) {		if (list_empty(&q->queued))			return 0;	        buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);		if (NULL == prev) {			list_del(&buf->vb.queue);			list_add_tail(&buf->vb.queue,&q->active);			start_video_dma(dev, q, buf);			buf->vb.state = STATE_ACTIVE;			buf->count    = q->count++;			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);			dprintk(2,"[%p/%d] restart_queue - first active\n",				buf,buf->vb.i);		} else if (prev->vb.width  == buf->vb.width  &&			   prev->vb.height == buf->vb.height &&			   prev->fmt       == buf->fmt) {			list_del(&buf->vb.queue);			list_add_tail(&buf->vb.queue,&q->active);			buf->vb.state = STATE_ACTIVE;			buf->count    = q->count++;			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);			dprintk(2,"[%p/%d] restart_queue - move to active\n",				buf,buf->vb.i);		} else {			return 0;		}		prev = buf;	}}/* ------------------------------------------------------------------ */static intbuffer_setup(struct file *file, unsigned int *count, unsigned int *size){	struct cx8800_fh *fh = file->private_data;		*size = fh->fmt->depth*fh->width*fh->height >> 3;	if (0 == *count)		*count = 32;	while (*size * *count > vid_limit * 1024 * 1024)		(*count)--;	return 0;}static intbuffer_prepare(struct file *file, struct videobuf_buffer *vb,	       enum v4l2_field field){	struct cx8800_fh   *fh  = file->private_data;	struct cx8800_dev  *dev = fh->dev;	struct cx88_buffer *buf = (struct cx88_buffer*)vb;	int rc, init_buffer = 0;	BUG_ON(NULL == fh->fmt);	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))		return -EINVAL;	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)		return -EINVAL;	if (buf->fmt       != fh->fmt    ||	    buf->vb.width  != fh->width  ||	    buf->vb.height != fh->height ||	    buf->vb.field  != field) {		buf->fmt       = fh->fmt;		buf->vb.width  = fh->width;		buf->vb.height = fh->height;		buf->vb.field  = field;		init_buffer = 1;	}	if (STATE_NEEDS_INIT == buf->vb.state) {		init_buffer = 1;		if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))			goto fail;	}	if (init_buffer) {		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;		switch (buf->vb.field) {		case V4L2_FIELD_TOP:			cx88_risc_buffer(dev->pci, &buf->risc,					 buf->vb.dma.sglist, 0, UNSET,					 buf->bpl, 0, buf->vb.height);			break;		case V4L2_FIELD_BOTTOM:			cx88_risc_buffer(dev->pci, &buf->risc,					 buf->vb.dma.sglist, UNSET, 0,					 buf->bpl, 0, buf->vb.height);			break;		case V4L2_FIELD_INTERLACED:			cx88_risc_buffer(dev->pci, &buf->risc,					 buf->vb.dma.sglist, 0, buf->bpl,					 buf->bpl, buf->bpl,					 buf->vb.height >> 1);			break;		case V4L2_FIELD_SEQ_TB:			cx88_risc_buffer(dev->pci, &buf->risc,					 buf->vb.dma.sglist,					 0, buf->bpl * (buf->vb.height >> 1),					 buf->bpl, 0,					 buf->vb.height >> 1);			break;		case V4L2_FIELD_SEQ_BT:			cx88_risc_buffer(dev->pci, &buf->risc,					 buf->vb.dma.sglist,					 buf->bpl * (buf->vb.height >> 1), 0,					 buf->bpl, 0,					 buf->vb.height >> 1);			break;		default:			BUG();		}	}	dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",		buf, buf->vb.i,		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,		(unsigned long)buf->risc.dma);	buf->vb.state = STATE_PREPARED;	return 0; fail:	cx88_free_buffer(dev->pci,buf);	return rc;}static voidbuffer_queue(struct file *file, struct videobuf_buffer *vb){	struct cx88_buffer    *buf  = (struct cx88_buffer*)vb;	struct cx88_buffer    *prev;	struct cx8800_fh      *fh   = file->private_data;	struct cx8800_dev     *dev  = fh->dev;	struct cx88_dmaqueue  *q    = &dev->vidq;	/* add jump to stopper */	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | 0x10000);	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);	if (!list_empty(&q->queued)) {		list_add_tail(&buf->vb.queue,&q->queued);		buf->vb.state = STATE_QUEUED;		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",			buf, buf->vb.i);	} else if (list_empty(&q->active)) {		list_add_tail(&buf->vb.queue,&q->active);		start_video_dma(dev, q, buf);		buf->vb.state = STATE_ACTIVE;		buf->count    = q->count++;		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);		dprintk(2,"[%p/%d] buffer_queue - first active\n",			buf, buf->vb.i);	} else {		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);		if (prev->vb.width  == buf->vb.width  &&		    prev->vb.height == buf->vb.height &&		    prev->fmt       == buf->fmt) {			list_add_tail(&buf->vb.queue,&q->active);			buf->vb.state = STATE_ACTIVE;			buf->count    = q->count++;			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);			dprintk(2,"[%p/%d] buffer_queue - append to active\n",				buf, buf->vb.i);		} else {			list_add_tail(&buf->vb.queue,&q->queued);			buf->vb.state = STATE_QUEUED;			dprintk(2,"[%p/%d] buffer_queue - first queued\n",				buf, buf->vb.i);		}	}}static void buffer_release(struct file *file, struct videobuf_buffer *vb){	struct cx88_buffer *buf = (struct cx88_buffer*)vb;	struct cx8800_fh   *fh  = file->private_data;	cx88_free_buffer(fh->dev->pci,buf);}struct videobuf_queue_ops cx8800_video_qops = {	.buf_setup    = buffer_setup,	.buf_prepare  = buffer_prepare,	.buf_queue    = buffer_queue,	.buf_release  = buffer_release,};/* ------------------------------------------------------------------ */#if 0 /* overlay support not finished yet */static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh,			  u32 *rp, struct btcx_skiplist *skips,			  u32 sync_line, int skip_even, int skip_odd){	int line,maxy,start,end,skip,nskips;	u32 ri,ra;	u32 addr;	/* sync instruction */	*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);	addr  = (unsigned long)dev->fbuf.base;	addr += dev->fbuf.fmt.bytesperline * fh->win.w.top;	addr += (fh->fmt->depth >> 3)      * fh->win.w.left;	/* scan lines */	for (maxy = -1, line = 0; line < fh->win.w.height;	     line++, addr += dev->fbuf.fmt.bytesperline) {		if ((line%2) == 0  &&  skip_even)			continue;		if ((line%2) == 1  &&  skip_odd)			continue;		/* calculate clipping */		if (line > maxy)			btcx_calc_skips(line, fh->win.w.width, &maxy,					skips, &nskips, fh->clips, fh->nclips);		/* write out risc code */		for (start = 0, skip = 0; start < fh->win.w.width; start = end) {			if (skip >= nskips) {				ri  = RISC_WRITE;				end = fh->win.w.width;			} else if (start < skips[skip].start) {				ri  = RISC_WRITE;				end = skips[skip].start;			} else {				ri  = RISC_SKIP;				end = skips[skip].end;				skip++;			}			if (RISC_WRITE == ri)				ra = addr + (fh->fmt->depth>>3)*start;			else				ra = 0;							if (0 == start)				ri |= RISC_SOL;			if (fh->win.w.width == end)				ri |= RISC_EOL;			ri |= (fh->fmt->depth>>3) * (end-start);			*(rp++)=cpu_to_le32(ri);			if (0 != ra)				*(rp++)=cpu_to_le32(ra);		}	}	kfree(skips);	return rp;}static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh,			 struct cx88_buffer *buf){	struct btcx_skiplist *skips;	u32 instructions,fields;	u32 *rp;	int rc;		/* skip list for window clipping */	if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL)))		return -ENOMEM;		fields = 0;	if (V4L2_FIELD_HAS_TOP(fh->win.field))		fields++;	if (V4L2_FIELD_HAS_BOTTOM(fh->win.field))

⌨️ 快捷键说明

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