📄 bttv.c
字号:
u32 gpiomask; u32 muxsel[8]; u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */ u32 gpiomask2; /* GPIO MUX mask */};static struct tvcard tvcards[] = { /* default */ { 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, /* MIRO */ { 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}}, /* Hauppauge */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, /* STB */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}}, /* Intel??? */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, /* Diamond DTV2000 */ { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}}, /* AVerMedia TVPhone */ { 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}}, /* Matrix Vision MV-Delta */ { 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0}}, /* Fly Video II */ { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, {0, 0xc00, 0x800, 0x400, 0xc00, 0}}, /* TurboTV */ { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}}, /* Newer Hauppauge (bt878) */ { 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4}}, /* MIRO PCTV pro */ { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}}, /* ADS Technologies Channel Surfer TV (and maybe TV+FM) */ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* AVerMedia TVCapture 98 */ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, /* Aimslab VHX */ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, /* Zoltrix TV-Max */ { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, /* Pixelview PlayTV (bt878) */ { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},};#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))static void audio(struct bttv *btv, int mode){ btaor(tvcards[btv->type].gpiomask, ~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; mode=btv->audio; break; case AUDIO_OFF: mode=AUDIO_OFF; break; case AUDIO_ON: mode=btv->audio; break; default: btv->audio&=AUDIO_MUTE; btv->audio|=mode; break; } /* if audio mute or not in H-lock, turn audio off */ if ((btv->audio&AUDIO_MUTE)#if 0 || (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))#endif ) mode=AUDIO_OFF; if ((mode == 0) && (btv->radio)) mode = 1; btaor(tvcards[btv->type].audiomux[mode], ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);}extern inline void bt848_dma(struct bttv *btv, uint state){ if (state) btor(3, BT848_GPIO_DMA_CTL); else btand(~3, BT848_GPIO_DMA_CTL);}static void bt848_cap(struct bttv *btv, uint state){ if (state) { btv->cap|=3; bt848_set_risc_jmps(btv); } else { btv->cap&=~3; bt848_set_risc_jmps(btv); }}/* 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; /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/ 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; unsigned long tv; 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) { /* printk ("bttv%d: PLL: is off\n",btv->nr); */ return 0; } printk ("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) { /* printk("bttv%d: PLL: no change required\n",btv->nr); */ return 1; } printk("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); /* Let other people run while the PLL stabilizes */ tv=jiffies+HZ/10; /* .1 seconds */ do { schedule(); } while(time_before(jiffies,tv)); for (i=0; i<10; i++) { if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK)) btwrite(0,BT848_DSTATUS); else { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; printk("ok\n"); return 1; } mdelay(10); } btv->pll.pll_current = 0; printk("oops\n"); return -1;}static void bt848_muxsel(struct bttv *btv, unsigned int input){ btaor(tvcards[btv->type].gpiomask2,~tvcards[btv->type].gpiomask2, BT848_GPIO_OUT_EN); /* This seems to get rid of some synchronization problems */ btand(~(3<<5), BT848_IFORM); mdelay(10); input %= tvcards[btv->type].video_inputs; if (input==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); } btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); audio(btv, (input!=tvcards[btv->type].tuner) ? AUDIO_EXTERN : AUDIO_TUNER); btaor(tvcards[btv->type].muxsel[input]>>4, ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);}/* * Set the registers for the size we have specified. Don't bother * trying to understand this without the BT848 manual in front of * you [AC]. * * PS: The manual is free for download in .pdf format from * www.brooktree.com - nicely done those folks. */ struct tvnorm { u32 Fsc; u16 swidth, sheight; /* scaled standard width, height */ u16 totalwidth; u8 adelay, bdelay, iform; u32 scaledtwidth; u16 hdelayx1, hactivex1; u16 vdelay; u8 vbipack;};static struct tvnorm tvnorms[] = { /* PAL-BDGHI */ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */#ifdef VIDEODAT { 35468950, 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), 1135, 186, 924, 0x20, 255},#else { 35468950, 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), 1135, 186, 924, 0x20, 255},#endif/* { 35468950, 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), 944, 186, 922, 0x20, 255},*/ /* NTSC */ { 28636363, 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), 910, 128, 910, 0x1a, 144},/* { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), 780, 122, 754, 0x1a, 144},*/#if 0 /* SECAM EAST */ { 35468950, 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), 944, 186, 922, 0x20, 255},#else /* SECAM L */ { 35468950, 924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), 1135, 186, 922, 0x20, 255},#endif /* PAL-NC */ { 28636363, 640, 576, 910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), 780, 130, 734, 0x1a, 144}, /* PAL-M */ { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), 780, 135, 754, 0x1a, 144}, /* PAL-N */ { 35468950, 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1), 944, 186, 922, 0x20, 144}, /* NTSC-Japan */ { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), 780, 135, 754, 0x16, 144},};#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))#define VBI_SPL 2044/* RISC command to write one VBI data line */#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOLstatic void make_vbitab(struct bttv *btv){ int i; unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; for (i=0; i<16; i++) { *(po++)=VBI_RISC; *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); } *(po++)=BT848_RISC_JUMP; *(po++)=virt_to_bus(btv->risc_jmp+4); *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; for (i=16; i<32; i++) { *(pe++)=VBI_RISC; *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048); } *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); *(pe++)=virt_to_bus(btv->risc_jmp+10); DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));}int fmtbppx2[16] = { 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 };int palette2fmt[] = { 0, BT848_COLOR_FMT_Y8, BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT_RGB15, BT848_COLOR_FMT_YUY2, BT848_COLOR_FMT_BtYUV, -1, -1, -1, BT848_COLOR_FMT_RAW, BT848_COLOR_FMT_YCrCb422, BT848_COLOR_FMT_YCrCb411, BT848_COLOR_FMT_YCrCb422, BT848_COLOR_FMT_YCrCb411,};#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int))static int make_rawrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf){ unsigned long line; unsigned long bpl=1024; /* bytes per line */ unsigned long vadr=(unsigned long) vbuf; *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY is 2 and without separate VBI grabbing. We'll have to handle this inside the IRQ handler ... */ for (line=0; line < 640; line++) { *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; *(ro++)=kvirt_to_bus(vadr); *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL; *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2); vadr+=bpl; } *(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16); *(re++)=btv->bus_vbi_odd; return 0;}static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf, unsigned short width, unsigned short height, unsigned short fmt){ unsigned long line, lmask; unsigned long bl, blcr, blcb, rcmd; unsigned long todo; unsigned int **rp; int inter; unsigned long cbadr, cradr; unsigned long vadr=(unsigned long) vbuf; int shift, csize; switch(fmt) { case VIDEO_PALETTE_YUV422P: csize=(width*height)>>1; shift=1; lmask=0; break; case VIDEO_PALETTE_YUV411P: csize=(width*height)>>2; shift=2; lmask=0; break; case VIDEO_PALETTE_YUV420P: csize=(width*height)>>2; shift=1; lmask=1; break; case VIDEO_PALETTE_YUV410P: csize=(width*height)>>4; shift=2; lmask=3; break; default: return -1; } cbadr=vadr+(width*height); cradr=cbadr+csize; inter = (height>btv->win.cropheight/2) ? 1 : 0; *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0; *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { if(line==height) { vadr+=csize<<1; cbadr=vadr+(width*height); cradr=cbadr+csize; } if (inter) rp= (line&1) ? &re : &ro; else rp= (line>=height) ? &re : &ro; if(line&lmask) rcmd=BT848_RISC_WRITE1S23|BT848_RISC_SOL; else rcmd=BT848_RISC_WRITE123|BT848_RISC_SOL; todo=width; while(todo) { bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); blcr=(PAGE_SIZE-((PAGE_SIZE-1)&cradr))<<shift; blcb=(PAGE_SIZE-((PAGE_SIZE-1)&cbadr))<<shift; bl=(blcr<bl) ? blcr : bl; bl=(blcb<bl) ? blcb : bl; bl=(bl>todo) ? todo : bl; blcr=bl>>shift; blcb=blcr; /* bl now containts the longest row that can be written */ todo-=bl; if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */ *((*rp)++)=rcmd|bl; *((*rp)++)=blcb|(blcr<<16); *((*rp)++)=kvirt_to_bus(vadr); vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { *((*rp)++)=kvirt_to_bus(cbadr); cbadr+=blcb; *((*rp)++)=kvirt_to_bus(cradr); cradr+=blcr; } rcmd&=~BT848_RISC_SOL; /* only the first has SOL */ } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -