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 + -
显示快捷键?