bttv-driver.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页

C
2,527
字号
/* ----------------------------------------------------------------------- *//* 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 1 /* DEBUG */	if ((fh->resources & bits) != bits) {		/* trying to free ressources not allocated by us ... */		printk("bttv: BUG! (btres)\n");	}#endif	down(&btv->reslock);	fh->resources  &= ~bits;	btv->resources &= ~bits;	up(&btv->reslock);}/* ----------------------------------------------------------------------- *//* * sanity check for video framebuffer address ranges (overlay). * let's see if that address range actually belongs to some * pci display adapter. * * FIXME: stuff isn't portable.  It's also a v4l API bug, pass a * physical address in VIDIOCSFBUF isn't portable too ... */static intfind_videomem(unsigned long from, unsigned long to){#if PCI_DMA_BUS_IS_PHYS	struct pci_dev *dev = NULL;	int i,match,found;	found = 0;	dprintk(KERN_DEBUG "bttv: checking video framebuffer address"		" (%lx-%lx)\n",from,to);        pci_for_each_dev(dev) {		if (dev->class != PCI_CLASS_NOT_DEFINED_VGA &&		    dev->class >> 16 != PCI_BASE_CLASS_DISPLAY)			continue;		dprintk(KERN_DEBUG			"  pci display adapter %04x:%04x at %02x:%02x.%x\n",			dev->vendor,dev->device,dev->bus->number,			PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {			if (!(dev->resource[i].flags & IORESOURCE_MEM))				continue;			if (dev->resource[i].flags & IORESOURCE_READONLY)				continue;			match = (from >= dev->resource[i].start) &&				(to-1 <= dev->resource[i].end);			if (match)				found = 1;			dprintk(KERN_DEBUG "    memory at %08lx-%08lx%s\n",				dev->resource[i].start,				dev->resource[i].end,				match ? "  (check passed)" : "");		}	}	return found;#else	/* Hmm, the physical address passed to us is probably bogous */	dprintk(KERN_DEBUG "bttv: no overlay for this arch, sorry\n");	return 0;#endif}/* ----------------------------------------------------------------------- *//* 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 int set_pll(struct bttv *btv){        int i;        if (!btv->pll.pll_crystal)                return 0;        if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {                /* no PLL needed */                if (btv->pll.pll_current == 0)                        return 0;		vprintk("bttv%d: PLL: switching off\n",btv->nr);                btwrite(0x00,BT848_TGCTRL);                btwrite(0x00,BT848_PLL_XCI);                btv->pll.pll_current = 0;                return 0;        }        if (btv->pll.pll_ofreq == btv->pll.pll_current)                return 0;	vprintk("bttv%d: PLL: %d => %d ",btv->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 */		vprintk(".");		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(HZ/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;			vprintk(" ok\n");                        return 0;                }        }        btv->pll.pll_current = -1;	vprintk("failed\n");        return -1;}/* ----------------------------------------------------------------------- */static void bt848_bright(struct bttv *btv, int bright){	int value;	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 >> 7;	val_v   = ((color>>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->type].video_inputs)		return -EINVAL;        /* needed by RemoteVideo MX */	mask2 = bttv_tvcards[btv->type].gpiomask2;	if (mask2)		btaor(mask2,~mask2,BT848_GPIO_OUT_EN);#if 0	/* This seems to get rid of some synchronization problems */	btand(~(3<<5), BT848_IFORM);	schedule_timeout(HZ/10);#endif        	if (input==bttv_tvcards[btv->type].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->type].muxsel[input] & 3;	btaor(mux<<5, ~(3<<5), BT848_IFORM);	dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",		btv->nr,input,mux);	/* card specific hook */	if(bttv_tvcards[btv->type].muxsel_hook)		bttv_tvcards[btv->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;		btaor(bttv_tvcards[btv->type].gpiomask,	      ~bttv_tvcards[btv->type].gpiomask,BT848_GPIO_OUT_EN);	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;	}	dprintk("bttv%d: audio mux: mode=%d audio=%d\n",		btv->nr,mode,btv->audio);	mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;	val = bttv_tvcards[btv->type].audiomux[mux];	btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);	if (bttv_gpio)		bttv_gpio_tracking(btv,audio_modes[mux]);	if (!in_interrupt())		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(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);}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);		btv->pll.pll_ofreq = tvnorm->Fsc;	set_pll(btv);	return 0;}static voidset_input(struct bttv *btv, unsigned int input){	btv->input = input;	video_mux(btv,input);	audio_mux(btv,(input == bttv_tvcards[btv->type].tuner ?		       AUDIO_TUNER : AUDIO_EXTERN));	set_tvnorm(btv,btv->tvnorm);}static void init_bt848(struct bttv *btv){	int val;		btwrite(0, BT848_SRESET);	btwrite(0x00, BT848_CAP_CTL);	btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);	btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);        /* set planar and packed mode trigger points and         */        /* set rising edge of inverted GPINTR pin as irq trigger */        btwrite(BT848_GPIO_DMA_CTL_PKTP_32|                BT848_GPIO_DMA_CTL_PLTP1_16|                BT848_GPIO_DMA_CTL_PLTP23_16|                BT848_GPIO_DMA_CTL_GPINTC|                BT848_GPIO_DMA_CTL_GPINTI,                 BT848_GPIO_DMA_CTL);	val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;        btwrite(val, BT848_E_SCLOOP);        btwrite(val, BT848_O_SCLOOP);        btwrite(0x20, BT848_E_VSCALE_HI);        btwrite(0x20, BT848_O_VSCALE_HI);        btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),		BT848_ADC);	if (btv->opt_lumafilter) {		btwrite(0, BT848_E_CONTROL);		btwrite(0, BT848_O_CONTROL);	} else {		btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);		btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);	}}extern void bttv_reinit_bt848(struct bttv *btv){	unsigned long flags;	if (bttv_verbose)		printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->nr);	spin_lock_irqsave(&btv->s_lock,flags);	btv->errors=0;	bttv_set_dma(btv,0,0);	spin_unlock_irqrestore(&btv->s_lock,flags);	init_bt848(btv);        btv->pll.pll_current = -1;	set_input(btv,btv->input);}#ifdef HAVE_V4L2static int get_control(struct bttv *btv, struct v4l2_control *c){	struct video_audio va;	int i;		for (i = 0; i < BTTV_CTLS; i++)		if (bttv_ctls[i].id == c->id)			break;	if (i == BTTV_CTLS)		return -EINVAL;	if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {		memset(&va,0,sizeof(va));		bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);		if (bttv_tvcards[btv->type].audio_hook)			bttv_tvcards[btv->type].audio_hook(btv,&va,0);	}	switch (c->id) {	case V4L2_CID_BRIGHTNESS:		c->value = btv->bright;		break;	case V4L2_CID_HUE:		c->value = btv->hue;		break;	case V4L2_CID_CONTRAST:		c->value = btv->contrast;		break;	case V4L2_CID_SATURATION:		c->value = btv->saturation;		break;	case V4L2_CID_AUDIO_MUTE:		c->value =  (VIDEO_AUDIO_MUTE == va.flags) ? 1 : 0;		break;	case V4L2_CID_AUDIO_VOLUME:		c->value = va.volume;		break;	case V4L2_CID_AUDIO_BALANCE:		c->value = va.balance;		break;	case V4L2_CID_AUDIO_BASS:		c->value = va.bass;		break;	case V4L2_CID_AUDIO_TREBLE:		c->value = va.treble;		break;	case V4L2_CID_PRIVATE_CHROMA_AGC:		c->value = btv->opt_chroma_agc;		break;	case V4L2_CID_PRIVATE_COMBFILTER:		c->value = btv->opt_combfilter;		break;	case V4L2_CID_PRIVATE_LUMAFILTER:		c->value = btv->opt_lumafilter;		break;	case V4L2_CID_PRIVATE_AUTOMUTE:		c->value = btv->opt_automute;		break;	case V4L2_CID_PRIVATE_AGC_CRUSH:		c->value = btv->opt_adc_crush;		break;	default:		return -EINVAL;	}	return 0;}static int set_control(struct bttv *btv, struct v4l2_control *c){	struct video_audio va;	int i,val;	for (i = 0; i < BTTV_CTLS; i++)		if (bttv_ctls[i].id == c->id)			break;	if (i == BTTV_CTLS)		return -EINVAL;	if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) {		memset(&va,0,sizeof(va));		bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);		if (bttv_tvcards[btv->type].audio_hook)			bttv_tvcards[btv->type].audio_hook(btv,&va,0);	}	switch (c->id) {	case V4L2_CID_BRIGHTNESS:		bt848_bright(btv,c->value);		break;	case V4L2_CID_HUE:		bt848_hue(btv,c->value);		break;	case V4L2_CID_CONTRAST:		bt848_contrast(btv,c->value);

⌨️ 快捷键说明

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