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

📄 bttv-driver.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		.step          = 256,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_CONTRAST,		.name          = "Contrast",		.minimum       = 0,		.maximum       = 65535,		.step          = 128,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_SATURATION,		.name          = "Saturation",		.minimum       = 0,		.maximum       = 65535,		.step          = 128,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_HUE,		.name          = "Hue",		.minimum       = 0,		.maximum       = 65535,		.step          = 256,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},	/* --- audio --- */	{		.id            = V4L2_CID_AUDIO_MUTE,		.name          = "Mute",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_AUDIO_VOLUME,		.name          = "Volume",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 65535,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_BALANCE,		.name          = "Balance",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_BASS,		.name          = "Bass",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_AUDIO_TREBLE,		.name          = "Treble",		.minimum       = 0,		.maximum       = 65535,		.step          = 65535/100,		.default_value = 32768,		.type          = V4L2_CTRL_TYPE_INTEGER,	},	/* --- private --- */	{		.id            = V4L2_CID_PRIVATE_CHROMA_AGC,		.name          = "chroma agc",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_COMBFILTER,		.name          = "combfilter",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_AUTOMUTE,		.name          = "automute",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_LUMAFILTER,		.name          = "luma decimation filter",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_AGC_CRUSH,		.name          = "agc crush",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_VCR_HACK,		.name          = "vcr hack",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,		.name          = "whitecrush upper",		.minimum       = 0,		.maximum       = 255,		.step          = 1,		.default_value = 0xCF,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,		.name          = "whitecrush lower",		.minimum       = 0,		.maximum       = 255,		.step          = 1,		.default_value = 0x7F,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_PRIVATE_UV_RATIO,		.name          = "uv ratio",		.minimum       = 0,		.maximum       = 100,		.step          = 1,		.default_value = 50,		.type          = V4L2_CTRL_TYPE_INTEGER,	},{		.id            = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,		.name          = "full luma range",		.minimum       = 0,		.maximum       = 1,		.type          = V4L2_CTRL_TYPE_BOOLEAN,	},{		.id            = V4L2_CID_PRIVATE_CORING,		.name          = "coring",		.minimum       = 0,		.maximum       = 3,		.step          = 1,		.default_value = 0,		.type          = V4L2_CTRL_TYPE_INTEGER,	}};static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);/* ----------------------------------------------------------------------- *//* resource management                                                     */staticint check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit){	if (fh->resources & bit)		/* have it already allocated */		return 1;	/* is it free? */	down(&btv->reslock);	if (btv->resources & bit) {		/* no, someone else uses it */		up(&btv->reslock);		return 0;	}	/* it's free, grab it */	fh->resources  |= bit;	btv->resources |= bit;	up(&btv->reslock);	return 1;}staticint check_btres(struct bttv_fh *fh, int bit){	return (fh->resources & bit);}staticint locked_btres(struct bttv *btv, int bit){	return (btv->resources & bit);}staticvoid free_btres(struct bttv *btv, struct bttv_fh *fh, int bits){	if ((fh->resources & bits) != bits) {		/* trying to free ressources not allocated by us ... */		printk("bttv: BUG! (btres)\n");	}	down(&btv->reslock);	fh->resources  &= ~bits;	btv->resources &= ~bits;	up(&btv->reslock);}/* ----------------------------------------------------------------------- *//* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC          *//* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C   PLL_X = Reference pre-divider (0=1, 1=2)   PLL_C = Post divider (0=6, 1=4)   PLL_I = Integer input   PLL_F = Fractional input   F_input = 28.636363 MHz:   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0*/static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout){	unsigned char fl, fh, fi;	/* prevent overflows */	fin/=4;	fout/=4;	fout*=12;	fi=fout/fin;	fout=(fout%fin)*256;	fh=fout/fin;	fout=(fout%fin)*256;	fl=fout/fin;	btwrite(fl, BT848_PLL_F_LO);	btwrite(fh, BT848_PLL_F_HI);	btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);}static void set_pll(struct bttv *btv){	int i;	if (!btv->pll.pll_crystal)		return;	if (btv->pll.pll_ofreq == btv->pll.pll_current) {		dprintk("bttv%d: PLL: no change required\n",btv->c.nr);		return;	}	if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {		/* no PLL needed */		if (btv->pll.pll_current == 0)			return;		bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",			btv->c.nr,btv->pll.pll_ifreq);		btwrite(0x00,BT848_TGCTRL);		btwrite(0x00,BT848_PLL_XCI);		btv->pll.pll_current = 0;		return;	}	bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,		btv->pll.pll_ifreq, btv->pll.pll_ofreq);	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);	for (i=0; i<10; i++) {		/*  Let other people run while the PLL stabilizes */		bttv_printk(".");		msleep(10);		if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {			btwrite(0,BT848_DSTATUS);		} else {			btwrite(0x08,BT848_TGCTRL);			btv->pll.pll_current = btv->pll.pll_ofreq;			bttv_printk(" ok\n");			return;		}	}	btv->pll.pll_current = -1;	bttv_printk("failed\n");	return;}/* used to switch between the bt848's analog/digital video capture modes */static void bt848A_set_timing(struct bttv *btv){	int i, len;	int table_idx = bttv_tvnorms[btv->tvnorm].sram;	int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;	if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {		dprintk("bttv%d: load digital timing table (table_idx=%d)\n",			btv->c.nr,table_idx);		/* timing change...reset timing generator address */		btwrite(0x00, BT848_TGCTRL);		btwrite(0x02, BT848_TGCTRL);		btwrite(0x00, BT848_TGCTRL);		len=SRAM_Table[table_idx][0];		for(i = 1; i <= len; i++)			btwrite(SRAM_Table[table_idx][i],BT848_TGLB);		btv->pll.pll_ofreq = 27000000;		set_pll(btv);		btwrite(0x11, BT848_TGCTRL);		btwrite(0x41, BT848_DVSIF);	} else {		btv->pll.pll_ofreq = fsc;		set_pll(btv);		btwrite(0x0, BT848_DVSIF);	}}/* ----------------------------------------------------------------------- */static void bt848_bright(struct bttv *btv, int bright){	int value;	// printk("bttv: set bright: %d\n",bright); // DEBUG	btv->bright = bright;	/* We want -128 to 127 we get 0-65535 */	value = (bright >> 8) - 128;	btwrite(value & 0xff, BT848_BRIGHT);}static void bt848_hue(struct bttv *btv, int hue){	int value;	btv->hue = hue;	/* -128 to 127 */	value = (hue >> 8) - 128;	btwrite(value & 0xff, BT848_HUE);}static void bt848_contrast(struct bttv *btv, int cont){	int value,hibit;	btv->contrast = cont;	/* 0-511 */	value = (cont  >> 7);	hibit = (value >> 6) & 4;	btwrite(value & 0xff, BT848_CONTRAST_LO);	btaor(hibit, ~4, BT848_E_CONTROL);	btaor(hibit, ~4, BT848_O_CONTROL);}static void bt848_sat(struct bttv *btv, int color){	int val_u,val_v,hibits;	btv->saturation = color;	/* 0-511 for the color */	val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;	val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;	hibits  = (val_u >> 7) & 2;	hibits |= (val_v >> 8) & 1;	btwrite(val_u & 0xff, BT848_SAT_U_LO);	btwrite(val_v & 0xff, BT848_SAT_V_LO);	btaor(hibits, ~3, BT848_E_CONTROL);	btaor(hibits, ~3, BT848_O_CONTROL);}/* ----------------------------------------------------------------------- */static intvideo_mux(struct bttv *btv, unsigned int input){	int mux,mask2;	if (input >= bttv_tvcards[btv->c.type].video_inputs)		return -EINVAL;	/* needed by RemoteVideo MX */	mask2 = bttv_tvcards[btv->c.type].gpiomask2;	if (mask2)		gpio_inout(mask2,mask2);	if (input == btv->svhs)  {		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);	} else {		btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);		btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);	}	mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;	btaor(mux<<5, ~(3<<5), BT848_IFORM);	dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",		btv->c.nr,input,mux);	/* card specific hook */	if(bttv_tvcards[btv->c.type].muxsel_hook)		bttv_tvcards[btv->c.type].muxsel_hook (btv, input);	return 0;}static char *audio_modes[] = {	"audio: tuner", "audio: radio", "audio: extern",	"audio: intern", "audio: off"};static intaudio_mux(struct bttv *btv, int mode){	int val,mux,i2c_mux,signal;	gpio_inout(bttv_tvcards[btv->c.type].gpiomask,		   bttv_tvcards[btv->c.type].gpiomask);	signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;	switch (mode) {	case AUDIO_MUTE:		btv->audio |= AUDIO_MUTE;		break;	case AUDIO_UNMUTE:		btv->audio &= ~AUDIO_MUTE;		break;	case AUDIO_TUNER:	case AUDIO_RADIO:	case AUDIO_EXTERN:	case AUDIO_INTERN:		btv->audio &= AUDIO_MUTE;		btv->audio |= mode;	}	i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;	if (btv->opt_automute && !signal && !btv->radio_user)		mux = AUDIO_OFF;	val = bttv_tvcards[btv->c.type].audiomux[mux];	gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);	if (bttv_gpio)		bttv_gpio_tracking(btv,audio_modes[mux]);	if (!in_interrupt())		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));	return 0;}static voidi2c_vidiocschan(struct bttv *btv){	struct video_channel c;	memset(&c,0,sizeof(c));	c.norm    = btv->tvnorm;	c.channel = btv->input;	bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)		bttv_tda9880_setnorm(btv,c.norm);}static intset_tvnorm(struct bttv *btv, unsigned int norm){	const struct bttv_tvnorm *tvnorm;	if (norm < 0 || norm >= BTTV_TVNORMS)		return -EINVAL;	btv->tvnorm = norm;	tvnorm = &bttv_tvnorms[norm];	btwrite(tvnorm->adelay, BT848_ADELAY);	btwrite(tvnorm->bdelay, BT848_BDELAY);	btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),	      BT848_IFORM);	btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);	btwrite(1, BT848_VBI_PACK_DEL);	bt848A_set_timing(btv);	switch (btv->c.type) {	case BTTV_BOARD_VOODOOTV_FM:		bttv_tda9880_setnorm(btv,norm);		break;	}	return 0;}static voidset_input(struct bttv *btv, unsigned int input){	unsigned long flags;	btv->input = input;	if (irq_iswitch) {		spin_lock_irqsave(&btv->s_lock,flags);		if (btv->curr.frame_irq) {			/* active capture -> delayed input switch */			btv->new_input = input;		} else {			video_mux(btv,input);		}		spin_unlock_irqrestore(&btv->s_lock,flags);	} else {		video_mux(btv,input);	}	audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?		       AUDIO_TUNER : AUDIO_EXTERN));	set_tvnorm(btv,btv->tvnorm);	i2c_vidiocschan(btv);}static void init_irqreg(struct bttv *btv){	/* clear status */	btwrite(0xfffffUL, BT848_INT_STAT);	if (bttv_tvcards[btv->c.type].no_video) {		/* i2c only */		btwrite(BT848_INT_I2CDONE,			BT848_INT_MASK);

⌨️ 快捷键说明

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