📄 bttv-driver.c
字号:
.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 + -