--- linux-2.4.0-test1-ac21/drivers/char/bt848.h Sun Aug 23 22:32:25 1998 +++ linux/drivers/char/bt848.h Mon Jun 19 23:25:37 2000 @@ -336,7 +336,7 @@ -/* Bt848A and Bt849 only !! */ +/* Bt848A and higher only !! */ #define BT848_TGLB 0x080 #define BT848_TGCTRL 0x084 #define BT848_FCAP 0x0E8 --- linux-2.4.0-test1-ac21/drivers/char/bttv-driver.c Tue May 5 22:32:27 1998 +++ linux/drivers/char/bttv-driver.c Mon Jun 19 23:25:37 2000 @@ -0,0 +1,3316 @@ +/* + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999,2000 Gerd Knorr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HACKING +# include +#endif + +#include "bttv.h" +#include "tuner.h" + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + + +static void bt848_set_risc_jmps(struct bttv *btv, int state); + +int bttv_num; /* number of Bt848s in use */ +struct bttv bttvs[BTTV_MAX]; + + +/* insmod args */ +MODULE_PARM(triton1,"i"); +MODULE_PARM(radio,"1-4i"); +MODULE_PARM(bigendian,"i"); +MODULE_PARM(fieldnr,"i"); +MODULE_PARM(bttv_verbose,"i"); +MODULE_PARM(bttv_debug,"i"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM(gbufsize,"i"); + +MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); + +#if defined(__sparc__) || defined(__powerpc__) +static unsigned int bigendian=1; +#else +static unsigned int bigendian=0; +#endif +static int triton1=0; +static unsigned int radio[BTTV_MAX]; +static unsigned int fieldnr = 0; +static unsigned int gbuffers = 2; +static unsigned int gbufsize = BTTV_MAX_FBUF; +unsigned int bttv_debug = 0; +unsigned int bttv_verbose = 1; + +#define I2C_TIMING (0x7<<4) +#define I2C_DELAY 10 + +#define I2C_SET(CTRL,DATA) \ + { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } +#define I2C_GET() (btread(BT848_I2C)&1) + +#define BURSTOFFSET 76 +#define BTTV_ERRORS 5 + + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* [DaveM] I've recoded most of this so that: + * 1) It's easier to tell what is happening + * 2) It's more portable, especially for translating things + * out of vmalloc mapped areas in the kernel. + * 3) Less unnecessary translations happen. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (page_address(pte_page(pte))|(adr&(PAGE_SIZE-1))); + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + + + +/* + * Create the giant waste of buffer space we need for now + * until we get DMA to user space sorted out (probably 2.3.x) + * + * We only create this as and when someone uses mmap + */ + +static int fbuffer_alloc(struct bttv *btv) +{ + if(!btv->fbuffer) + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); + else + printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", + btv->nr); + if(!btv->fbuffer) + return -ENOBUFS; + return 0; +} + + +static int __devinit init_bttv_i2c(struct bttv *btv) +{ + /* i2c bit_adapter */ + memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter)); + memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client)); + + sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), + " #%d", btv->nr); + btv->i2c_algo.data = btv; + btv->i2c_adap.data = btv; + btv->i2c_adap.algo_data = &btv->i2c_algo; + btv->i2c_client.adapter = &btv->i2c_adap; + +#if 0 + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); +#endif + + btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap); + return btv->i2c_ok; +} + + +/* ----------------------------------------------------------------------- */ + +static void audio(struct bttv *btv, int mode, int no_irq_context) +{ + 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; + 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)) + mode=AUDIO_OFF; + if ((mode == AUDIO_TUNER) && (btv->radio)) + mode = AUDIO_RADIO; + btaor(bttv_tvcards[btv->type].audiomux[mode], + ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + if (no_irq_context) + bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); +} + + +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); +} + + +/* 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; + } + + if (bttv_verbose) + 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<100; 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; + if (bttv_verbose) + printk("ok\n"); + return 1; + } + mdelay(10); + } + btv->pll.pll_current = 0; + if (bttv_verbose) + printk("oops\n"); + return -1; +} + +static void bt848_muxsel(struct bttv *btv, unsigned int input) +{ + btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_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 %= bttv_tvcards[btv->type].video_inputs; + 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); + } + btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); + audio(btv, (input!=bttv_tvcards[btv->type].tuner) ? + AUDIO_EXTERN : AUDIO_TUNER, 1); + btaor(bttv_tvcards[btv->type].muxsel[input]>>4, + ~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); +} + + +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 */ + { 35468950, + 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + 1135, 186, 924, 0x20, 255}, + + /* NTSC */ + { 28636363, + 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), + 910, 128, 910, 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_SOL + +static void make_vbitab(struct bttv *btv) +{ + int i; + unsigned int *po=(unsigned int *) btv->vbi_odd; + unsigned int *pe=(unsigned int *) btv->vbi_even; + + if (bttv_debug > 1) + printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); + + *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; + for (i=0; i<16; i++) + { + *(po++)=cpu_to_le32(VBI_RISC); + *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); + } + *(po++)=cpu_to_le32(BT848_RISC_JUMP); + *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + + *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; + for (i=16; i<32; i++) + { + *(pe++)=cpu_to_le32(VBI_RISC); + *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); + } + *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); + *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + + if (bttv_debug > 1) + printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); +} + +static int fmtbppx2[16] = { + 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 +}; + +static 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++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(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++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); + *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); + vadr+=bpl; + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(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; + + if (bttv_debug > 1) + printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + 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>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(ro++)=0; + *(re++)=cpu_to_le32(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) ? &ro : &re; + + + 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))<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)++)=cpu_to_le32(rcmd|bl); + *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bl; + if((rcmd&(15<<28))==BT848_RISC_WRITE123) + { + *((*rp)++)=(kvirt_to_bus(cbadr)); + cbadr+=blcb; + *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); + cradr+=blcr; + } + + rcmd&=~BT848_RISC_SOL; /* only the first has SOL */ + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + return 0; +} + +static int make_vrisctab(struct bttv *btv, unsigned int *ro, + unsigned int *re, + unsigned int *vbuf, unsigned short width, + unsigned short height, unsigned short palette) +{ + unsigned long line; + unsigned long bpl; /* bytes per line */ + unsigned long bl; + unsigned long todo; + unsigned int **rp; + int inter; + unsigned long vadr=(unsigned long) vbuf; + + if (palette==VIDEO_PALETTE_RAW) + return make_rawrisctab(btv, ro, re, vbuf); + if (palette>=VIDEO_PALETTE_PLANAR) + return make_prisctab(btv, ro, re, vbuf, width, height, palette); + + if (bttv_debug > 1) + printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + for (line=0; line < (height<<(1^inter)); line++) + { + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>=height) ? &ro : &re; + + bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); + if (bpl<=bl) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bpl; + } + else + { + todo=bpl; + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=bl; + todo-=bl; + while (todo>PAGE_SIZE) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=PAGE_SIZE; + todo-=PAGE_SIZE; + } + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); + vadr+=todo; + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + return 0; +} + +static unsigned char lmaskt[8] = +{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; +static unsigned char rmaskt[8] = +{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + +static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h) +{ + unsigned char lmask, rmask, *p; + int W, l, r; + int i; + + if (bttv_debug > 1) + printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); + + /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ + if (x<0) + { + w+=x; + x=0; + } + if (y<0) + { + h+=y; + y=0; + } + if (w < 0 || h < 0) /* catch bad clips */ + return; + /* out of range data should just fall through */ + if (y+h>=625) + h=625-y; + if (x+w>=1024) + w=1024-x; + + l=x>>3; + r=(x+w-1)>>3; + W=r-l-1; + lmask=lmaskt[x&7]; + rmask=rmaskt[(x+w-1)&7]; + p=clipmap+128*y+l; + + if (W>0) + { + for (i=0; iwin.bpp is allowed here */ + bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; + bpl=btv->win.bpl; + adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; + inter=(btv->win.interlace&1)^1; + width=btv->win.width; + height=btv->win.height; + if (bttv_debug > 1) + printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); + if(width > 1023) + width = 1023; /* sanity check */ + if(height > 625) + height = 625; /* sanity check */ + ro=btv->risc_scr_odd; + re=btv->risc_scr_even; + + if (bttv_debug) + printk("bttv%d: clip: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { + /* can't clip, don't generate any risc code */ + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + } + if (ncr < 0) { /* bitmap was pased */ + memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); + } else { /* convert rectangular clips to a bitmap */ + memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ + for (i=0; iwin.x * btv->win.bpp) / bpp; + clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, + 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + /* translate bitmap to risc code */ + for (line=outofmem=0; line < (height<>inter; + rp= (line&1) ? &re : &ro; + clipline = clipmap + (y<<7); /* running pointers ... */ + lastbit = *clipline & 1; + for(x=dx=0,sx=0; x<=width && !outofmem;) { + if (0 == (x&7)) { + /* check bytes not bits if we can ... */ + if (lastbit) { + while (0xff==*clipline && xrisc_scr_odd>RISCMEM_LEN/2 - 16) + outofmem++; + if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) + outofmem++; + } + x++; + if (0 == (x&7)) + clipline++; + } + if ((!inter)||(line&1)) + adr+=bpl; + } + + vfree(clipmap); + /* outofmem flag relies on the following code to discard extra data */ + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + if (bttv_debug > 1) + printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); +} + +/* + * 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. + */ + +static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, + int odd, int width, int height) +{ + u16 vscale, hscale; + u32 xsf, sr; + u16 hdelay; + u8 crop, vtc; + int inter = (height>tvn->sheight/2) ? 0 : 1; + int off = odd ? 0x80 : 0x00; + + xsf = (width*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*width)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/height-512; + vscale=(0x10000UL-sr)&0x1fff; + crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; + +#if 0 + /* Some people say interpolation looks bad ... */ + vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); + if (width < 767) + btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + else + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); +#else + vtc = 0; + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); +#endif + + btwrite(vtc, BT848_E_VTC+off); + btwrite(hscale>>8, BT848_E_HSCALE_HI+off); + btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); + btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); + btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); + btwrite(width&0xff, BT848_E_HACTIVE_LO+off); + btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); + btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); + btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); + btwrite(crop, BT848_E_CROP+off); +} + + +static void bt848_set_geo(struct bttv *btv, + int no_irq_context) +{ + u16 ewidth, eheight, owidth, oheight; + u16 format, bswap; + struct tvnorm *tvn; + + tvn=&tvnorms[btv->win.norm]; + + btwrite(tvn->adelay, BT848_ADELAY); + btwrite(tvn->bdelay, BT848_BDELAY); + btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); + btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + + btv->pll.pll_ofreq = tvn->Fsc; + if (no_irq_context) + set_pll(btv); + + btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; + + if (0 == btv->risc_cap_odd && + 0 == btv->risc_cap_even) { + /* overlay only */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->win.width; + eheight = btv->win.height; + format = btv->win.color_fmt; + bswap = btv->fb_color_ctl; + } else if (-1 != btv->gq_grab && + 0 == btv->risc_cap_odd && + !btv->win.interlace && + btv->scr_on) { + /* odd field -> overlay, even field -> capture */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = (btv->win.color_fmt & 0xf0) | + (btv->gbuf[btv->gq_grab].fmt & 0x0f); + bswap = btv->fb_color_ctl & 0x0a; + } else { + /* capture only */ + owidth = btv->gbuf[btv->gq_grab].width; + oheight = btv->gbuf[btv->gq_grab].height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = btv->gbuf[btv->gq_grab].fmt; + bswap = 0; + } + + /* program odd + even fields */ + bt848_set_eogeo(btv, tvn, 1, owidth, oheight); + bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); + + btwrite(format, BT848_COLOR_FMT); + btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); +} + + +static int bpp2fmt[4] = { + BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 +}; + +static void bt848_set_winsize(struct bttv *btv) +{ + unsigned short format; + + if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { + /* format set by VIDIOCSPICT */ + format = palette2fmt[btv->picture.palette]; + } else { + /* use default for the given color depth */ + format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : + bpp2fmt[(btv->win.bpp-1)&3]; + } + btv->win.color_fmt = format; + if (bigendian && + format == BT848_COLOR_FMT_RGB32) { + btv->fb_color_ctl = + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else if (bigendian && + (format == BT848_COLOR_FMT_RGB16 || + format == BT848_COLOR_FMT_RGB15)) { + btv->fb_color_ctl = + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else { + btv->fb_color_ctl = 0; + } + + /* RGB8 seems to be a 9x5x5 GRB color cube starting at + * color 16. Why the h... can't they even mention this in the + * data sheet? [AC - because it's a standard format so I guess + * it never occurred to them] + * Enable dithering in this mode. + */ + + if (format==BT848_COLOR_FMT_RGB8) + btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); + else + btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); + + bt848_set_geo(btv,1); +} + +#ifdef HACKING +/* playing with kiobufs and dma-to-userspace. 2.4.x only + Yes, I know: cut+paste programming is ugly. + will fix later, this is proof-of-concept right now. */ +static int make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro, + unsigned int *re, struct kiobuf *iobuf, + unsigned short width, unsigned short height, + unsigned short palette) +{ + unsigned long bpl; /* bytes per line */ + unsigned long bl; + unsigned long todo; + unsigned long pageaddr; + unsigned int **rp; + unsigned long line,inter,offset,page; + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; + bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; + + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); + + offset = iobuf->offset; + page = 0; + pageaddr = virt_to_bus((void*)page_address(iobuf->maplist[page])); + for (line=0; line < (height<<(1^inter)); line++) + { + if (inter) + rp= (line&1) ? &re : &ro; + else + rp= (line>=height) ? &ro : &re; + + bl = PAGE_SIZE - offset; + if (bpl <= bl) { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *((*rp)++)=cpu_to_le32(pageaddr+offset); + offset+=bpl; + } else { + todo = bpl; + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); + *((*rp)++)=cpu_to_le32(pageaddr+offset); + todo -= bl; + offset = 0; + page++; + pageaddr = virt_to_bus((void*)page_address(iobuf->maplist[page])); + while (todo>PAGE_SIZE) + { + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); + *((*rp)++)=cpu_to_le32(pageaddr); + page++; + pageaddr = virt_to_bus((void*)page_address(iobuf->maplist[page])); + } + *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); + *((*rp)++)=cpu_to_le32(pageaddr); + offset += todo; + } + } + + *(ro++)=cpu_to_le32(BT848_RISC_JUMP); + *(ro++)=cpu_to_le32(btv->bus_vbi_even); + *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); + *(re++)=cpu_to_le32(btv->bus_vbi_odd); + + return 0; +} + +static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp, + struct kiobuf *iobuf) +{ + unsigned int *ro, *re; + unsigned long flags; + + if(btv->gbuf[0].stat != GBUFFER_UNUSED) + return -EBUSY; + + if(mp->height < 32 || mp->width < 32) + return -EINVAL; + if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */) + return -EINVAL; + + if(-1 == palette2fmt[mp->format]) + return -EINVAL; + + /* + * Ok load up the BT848 + */ + + ro=btv->gbuf[0].risc; + re=ro+2048; + make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format); + + if (bttv_debug) + printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n", + btv->nr,0,mp->format,mp->width,mp->height); + spin_lock_irqsave(&btv->s_lock, flags); + btv->gbuf[0].stat = GBUFFER_GRABBING; + btv->gbuf[0].fmt = palette2fmt[mp->format]; + btv->gbuf[0].width = mp->width; + btv->gbuf[0].height = mp->height; + btv->gbuf[0].ro = virt_to_bus(ro); + btv->gbuf[0].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[0].ro = 0; +#endif + + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { + btv->gq_start = 1; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } + btv->gqueue[btv->gq_in++] = 0; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + + btor(3, BT848_CAP_CTL); + btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); + return 0; +} +#endif + +/* + * Grab into virtual memory. + */ + +static int vgrab(struct bttv *btv, struct video_mmap *mp) +{ + unsigned int *ro, *re; + unsigned int *vbuf; + unsigned long flags; + + if(btv->fbuffer==NULL) + { + if(fbuffer_alloc(btv)) + return -ENOBUFS; + } + + if(mp->frame >= gbuffers || mp->frame < 0) + return -EINVAL; + if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) + return -EBUSY; + + if(mp->height < 32 || mp->width < 32) + return -EINVAL; + if (mp->format >= PALETTEFMT_MAX) + return -EINVAL; + + if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 + > gbufsize) + return -EINVAL; + if(-1 == palette2fmt[mp->format]) + return -EINVAL; + + /* + * Ok load up the BT848 + */ + + vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); + ro=btv->gbuf[mp->frame].risc; + re=ro+2048; + make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); + + if (bttv_debug) + printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", + btv->nr,mp->frame,mp->format,mp->width,mp->height); + spin_lock_irqsave(&btv->s_lock, flags); + btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; + btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; + btv->gbuf[mp->frame].width = mp->width; + btv->gbuf[mp->frame].height = mp->height; + btv->gbuf[mp->frame].ro = virt_to_bus(ro); + btv->gbuf[mp->frame].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[mp->frame].ro = 0; +#endif + + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { + btv->gq_start = 1; + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } + btv->gqueue[btv->gq_in++] = mp->frame; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + + btor(3, BT848_CAP_CTL); + btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); + return 0; +} + +static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + struct bttv *btv= (struct bttv *)v; + int q,todo; + DECLARE_WAITQUEUE(wait, current); + + /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + schedule(); + if(signal_pending(current)) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +static inline void burst(int on) +{ + tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); + tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); + tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); +} + +static void bt848_restart(struct bttv *btv) +{ + unsigned long irq_flags; + + if (bttv_verbose) + printk("bttv%d: resetting chip\n",btv->nr); + btwrite(0xfffffUL, BT848_INT_STAT); + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + + /* enforce pll reprogramming */ + btv->pll.pll_current = 0; + set_pll(btv); + + btv->errors = 0; + btv->needs_restart = 0; + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); +} + +/* + * Open a bttv card. Right now the flags stuff is just playing + */ + +static int bttv_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)dev; + int i,ret; + + ret = -EBUSY; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->user) + goto out_unlock; + + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); + ret = -ENOMEM; + if (!btv->fbuffer) + goto out_unlock; + + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + btv->gbuf[i].stat = GBUFFER_UNUSED; + + if (btv->needs_restart) + bt848_restart(btv); + burst(0); + set_pll(btv); + btv->user++; + up(&btv->lock); + return 0; + + out_unlock: + up(&btv->lock); + MOD_DEC_USE_COUNT; + return ret; +} + +static void bttv_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; + + down(&btv->lock); + btv->user--; + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->scr_on = 0; + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * A word of warning. At this point the chip + * is still capturing because its FIFO hasn't emptied + * and the DMA control operations are posted PCI + * operations. + */ + + btread(BT848_I2C); /* This fixes the PCI posting delay */ + + if (-1 != btv->gq_grab) { + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + } + + /* + * We have allowed it to drain. + */ + + if(btv->fbuffer) + rvfree((void *) btv->fbuffer, gbuffers*gbufsize); + btv->fbuffer=0; + up(&btv->lock); + MOD_DEC_USE_COUNT; +} + + +/***********************************/ +/* ioctls and supporting functions */ +/***********************************/ + +extern inline void bt848_bright(struct bttv *btv, uint bright) +{ + btwrite(bright&0xff, BT848_BRIGHT); +} + +extern inline void bt848_hue(struct bttv *btv, uint hue) +{ + btwrite(hue&0xff, BT848_HUE); +} + +extern inline void bt848_contrast(struct bttv *btv, uint cont) +{ + unsigned int conthi; + + conthi=(cont>>6)&4; + btwrite(cont&0xff, BT848_CONTRAST_LO); + btaor(conthi, ~4, BT848_E_CONTROL); + btaor(conthi, ~4, BT848_O_CONTROL); +} + +extern inline void bt848_sat_u(struct bttv *btv, unsigned long data) +{ + u32 datahi; + + datahi=(data>>7)&2; + btwrite(data&0xff, BT848_SAT_U_LO); + btaor(datahi, ~2, BT848_E_CONTROL); + btaor(datahi, ~2, BT848_O_CONTROL); +} + +static inline void bt848_sat_v(struct bttv *btv, unsigned long data) +{ + u32 datahi; + + datahi=(data>>8)&1; + btwrite(data&0xff, BT848_SAT_V_LO); + btaor(datahi, ~1, BT848_E_CONTROL); + btaor(datahi, ~1, BT848_O_CONTROL); +} + +/* + * ioctl routine + */ + + +static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; + int i,ret = 0; + + if (bttv_debug > 1) + printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = bttv_tvcards[btv->type].video_inputs; + b.audios = bttv_tvcards[btv->type].audio_inputs; + b.maxwidth = tvnorms[btv->win.norm].swidth; + b.maxheight = tvnorms[btv->win.norm].sheight; + b.minwidth = 32; + b.minheight = 32; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags=VIDEO_VC_AUDIO; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; + v.norm = btv->win.norm; + if (v.channel>=bttv_tvcards[btv->type].video_inputs) + return -EINVAL; + if(v.channel==bttv_tvcards[btv->type].tuner) + { + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + } + else if(v.channel==bttv_tvcards[btv->type].svhs) + strcpy(v.name,"S-Video"); + else + sprintf(v.name,"Composite%d",v.channel); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + + if (v.channel>bttv_tvcards[btv->type].video_inputs) + return -EINVAL; + if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) + return -EOPNOTSUPP; + + bttv_call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + bt848_muxsel(btv, v.channel); + btv->channel=v.channel; + if (btv->win.norm != v.norm) { + btv->win.norm = v.norm; + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + } + up(&btv->lock); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = btv->win.norm; + v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; + bttv_call_i2c_clients(btv,cmd,&v); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but one tuner */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only one channel has a tuner */ + if(v.tuner!=bttv_tvcards[btv->type].tuner) + return -EINVAL; + + if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC + &&v.mode!=VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + bttv_call_i2c_clients(btv,cmd,&v); + if (btv->win.norm != v.mode) { + btv->win.norm = v.mode; + down(&btv->lock); + set_pll(btv); + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + } + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->picture; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + if (p.palette > PALETTEFMT_MAX) + return -EINVAL; + down(&btv->lock); + /* We want -128 to 127 we get 0-65535 */ + bt848_bright(btv, (p.brightness>>8)-128); + /* 0-511 for the colour */ + bt848_sat_u(btv, p.colour>>7); + bt848_sat_v(btv, ((p.colour>>7)*201L)/237); + /* -128 to 127 */ + bt848_hue(btv, (p.hue>>8)-128); + /* 0-511 */ + bt848_contrast(btv, p.contrast>>7); + btv->picture = p; + up(&btv->lock); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp = NULL; + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + down(&btv->lock); + if(vw.flags || vw.width < 16 || vw.height < 16) + { + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + return -EINVAL; + } + if (btv->win.bpp < 4) + { /* adjust and align writes */ + vw.x = (vw.x + 3) & ~3; + vw.width &= ~3; + } + if (btv->needs_restart) + bt848_restart(btv); + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; + + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,0); + bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * Do any clips. + */ + if(vw.clipcount<0) { + if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) + return -ENOMEM; + if(copy_from_user(vcp, vw.clips, + VIDEO_CLIPMAP_SIZE)) { + vfree(vcp); + return -EFAULT; + } + } else if (vw.clipcount) { + if((vcp=vmalloc(sizeof(struct video_clip)* + (vw.clipcount))) == NULL) + return -ENOMEM; + if(copy_from_user(vcp,vw.clips, + sizeof(struct video_clip)* + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + } + make_clip_tab(btv, vcp, vw.clipcount); + if (vw.clipcount != 0) + vfree(vcp); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + /* Oh for a COBOL move corresponding .. */ + vw.x=btv->win.x; + vw.y=btv->win.y; + vw.width=btv->win.width; + vw.height=btv->win.height; + vw.chromakey=0; + vw.flags=0; + if(btv->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(btv->win.vidadr == 0) + return -EINVAL; + if (btv->win.width==0 || btv->win.height==0) + return -EINVAL; + spin_lock_irqsave(&btv->s_lock, irq_flags); + if (v == 1 && btv->win.vidadr != 0) + btv->scr_on = 1; + if (v == 0) + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + v.base=(void *)btv->win.vidadr; + v.height=btv->win.sheight; + v.width=btv->win.swidth; + v.depth=btv->win.depth; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; + + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=15 && v.depth!=16 && + v.depth!=24 && v.depth!=32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) + return -EINVAL; + down(&btv->lock); + if (v.base) + btv->win.vidadr=(unsigned long)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=((v.depth+7)&0x38)/8; + btv->win.depth=v.depth; + btv->win.bpl=v.bytesperline; + + /* set sefault color format */ + switch (btv->win.bpp) { + case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; + case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; + case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; + case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; + case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; + } + + if (bttv_debug) + printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl); + bt848_set_winsize(btv); + up(&btv->lock); + return 0; + } + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + case VIDIOCGFREQ: + { + unsigned long v=btv->win.freq; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: + { + unsigned long v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + btv->win.freq=v; + bttv_call_i2c_clients(btv,cmd,&v); + if (btv->type == BTTV_MIROPRO && btv->radio) + tea5757_set_freq(btv,v); + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio v; + + v=btv->audio_dev; + v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + v.flags|=VIDEO_AUDIO_MUTABLE; + strcpy(v.name,"TV"); + + v.mode = VIDEO_SOUND_MONO; + bttv_call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + + } else if (btv->audio_chip == TDA9840) { + /* begin of Horrible Hack */ + v.flags|=VIDEO_AUDIO_VOLUME; + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + v.volume = 32768; /* fixme */ + v.step = 4096; + } + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + down(&btv->lock); + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE, 1); + /* One audio source per tuner -- huh? */ + if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) { + up(&btv->lock); + return -EINVAL; + } + /* bt848_muxsel(btv,v.audio); */ + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE, 1); + + bttv_call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + unsigned int con = 0; + btor(0x180000, BT848_GPIO_OUT_EN); + if (v.mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v.mode & VIDEO_SOUND_STEREO) + con = 0x180000; + btaor(con, ~0x180000, BT848_GPIO_DATA); + + } else if (btv->type == BTTV_WINVIEW_601) { + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((v.volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + data = btread(BT848_GPIO_DATA); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<audio_dev=v; + up(&btv->lock); + return 0; + } + + case VIDIOCSYNC: + { + DECLARE_WAITQUEUE(wait, current); + + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + if (i < 0 || i >= gbuffers) + return -EINVAL; + switch (btv->gbuf[i].stat) { + case GBUFFER_UNUSED: + ret = -EINVAL; + break; + case GBUFFER_GRABBING: + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; + while(btv->gbuf[i].stat==GBUFFER_GRABBING) { + if (bttv_debug) + printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } + } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + /* fall throuth */ + case GBUFFER_DONE: + case GBUFFER_ERROR: + ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; + if (bttv_debug) + printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); + btv->gbuf[i].stat = GBUFFER_UNUSED; + } + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } + return ret; + } + + case BTTV_FIELDNR: + if(copy_to_user((void *) arg, (void *) &btv->last_field, + sizeof(btv->last_field))) + return -EFAULT; + break; + + case BTTV_PLLSET: { + struct bttv_pll_info p; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) + return -EFAULT; + down(&btv->lock); + btv->pll.pll_ifreq = p.pll_ifreq; + btv->pll.pll_ofreq = p.pll_ofreq; + btv->pll.pll_crystal = p.pll_crystal; + up(&btv->lock); + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + int ret; + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + down(&btv->lock); + ret = vgrab(btv, &vm); + up(&btv->lock); + return ret; + } + + case VIDIOCGMBUF: + { + struct video_mbuf vm; + memset(&vm, 0 , sizeof(vm)); + vm.size=gbufsize*gbuffers; + vm.frames=gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i]=i*gbufsize; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + return 0; + } + + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video=btv->video_dev.minor; + vu.vbi=btv->vbi_dev.minor; + if(btv->radio_dev.minor!=-1) + vu.radio=btv->radio_dev.minor; + else + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } + + case BTTV_BURST_ON: + { + burst(1); + return 0; + } + + case BTTV_BURST_OFF: + { + burst(0); + return 0; + } + + case BTTV_VERSION: + { + return BTTV_VERSION_CODE; + } + + case BTTV_PICNR: + { + /* return picture;*/ + return 0; + } + +#ifdef HACKING + /* playing with kiobufs and dma-to-userspace */ + case BTTV_JUST_HACKING: + { + DECLARE_WAITQUEUE(wait, current); + struct bttv_just_hacking hack; + struct kiobuf *iobuf; + int err; + + if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack))) + return -EFAULT; + printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n", + btv->nr,hack.width,hack.height,hack.format, + hack.buf,hack.len); + + /* pin down */ + err = alloc_kiovec(1,&iobuf); + if (err) + goto hack_oops; + err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len); + if (err) + goto hack_oops; + err = lock_kiovec(1,&iobuf,1); + if (err) + goto hack_oops; + + /* have a look */ + printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n", + btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length, + iobuf->locked); + printk("bttv%d: hack: pages (bus addr):",btv->nr); + for (i = 0; i < iobuf->nr_pages; i++) { + printk(" %lx", virt_to_bus((void*)page_address(iobuf->maplist[i]))); + } + printk("\n"); + + /* start capture */ + err = -EINVAL; + if (hack.height * hack.width * 2 * /* fixme: *2 */ + fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len) + goto hack_oops; + err = vgrab_kiobuf(btv,&hack,iobuf); + if (err) + goto hack_oops; + printk("bttv%d: hack: capture started\n",btv->nr); + + /* wait */ + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; + while(btv->gbuf[0].stat==GBUFFER_GRABBING) { + if (bttv_debug) + printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0); + schedule(); +#if 0 + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } +#endif + } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; + printk("bttv%d: hack: capture done\n",btv->nr); + + /* release */ + err = 0; + hack_oops: + free_kiovec(1,&iobuf); + return 0; + } +#endif + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int bttv_init_done(struct video_device *dev) +{ + return 0; +} + +/* + * This maps the vmalloced and reserved fbuffer to user space. + * + * FIXME: + * - PAGE_READONLY should suffice!? + * - remap_page_range is kind of inefficient for page by page remapping. + * But e.g. pte_alloc() does not work in modules ... :-( + */ + +static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) +{ + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + if (size>gbuffers*gbufsize) + return -EINVAL; + if (!btv->fbuffer) { + if(fbuffer_alloc(btv)) + return -EINVAL; + } + pos=(unsigned long) btv->fbuffer; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} + +static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) +{ + struct bttv *btv=(struct bttv *)dev; + int r; + + down(&btv->lock); + r=do_bttv_mmap(btv, adr, size); + up(&btv->lock); + return r; +} + + +static struct video_device bttv_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + bttv_open, + bttv_close, + bttv_read, + bttv_write, + NULL, + bttv_ioctl, + bttv_mmap, + bttv_init_done, + NULL, + 0, + -1 +}; + + +static long vbi_read(struct video_device *v, char *buf, unsigned long count, + int nonblock) +{ + struct bttv *btv=(struct bttv *)(v-2); + int q,todo; + DECLARE_WAITQUEUE(wait, current); + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if (btv->needs_restart) { + down(&btv->lock); + bt848_restart(btv); + up(&btv->lock); + } + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + schedule(); + if(signal_pending(current)) + { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +static unsigned int vbi_poll(struct video_device *dev, struct file *file, + poll_table *wait) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned int mask = 0; + + poll_wait(file, &btv->vbiq, wait); + + if (btv->vbip < VBIBUF_SIZE) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static int vbi_open(struct video_device *dev, int flags) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->needs_restart) + bt848_restart(btv); + set_pll(btv); + btv->vbip=VBIBUF_SIZE; + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->vbi_on = 1; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + up(&btv->lock); + + return 0; +} + +static void vbi_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; + + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->vbi_on = 0; + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + MOD_DEC_USE_COUNT; +} + +static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->vbi_dev.name); + b.type = ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_TELETEXT; + b.channels = 0; + b.audios = 0; + b.maxwidth = 0; + b.maxheight = 0; + b.minwidth = 0; + b.minheight = 0; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return bttv_ioctl((struct video_device *)btv,cmd,arg); + case BTTV_VBISIZE: + /* make alevt happy :-) */ + return VBIBUF_SIZE; + default: + return -EINVAL; + } +} + +static struct video_device vbi_template= +{ + "bttv vbi", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + vbi_open, + vbi_close, + vbi_read, + bttv_write, + vbi_poll, + vbi_ioctl, + NULL, /* no mmap yet */ + bttv_init_done, + NULL, + 0, + -1 +}; + + +static int radio_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)(dev-1); + unsigned long v; + + MOD_INC_USE_COUNT; + down(&btv->lock); + if (btv->user) + goto busy_unlock; + btv->user++; + + btv->radio = 1; + v = 400*16; + bttv_call_i2c_clients(btv,VIDIOCSFREQ,&v); + bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); + bt848_muxsel(btv,0); + up(&btv->lock); + + return 0; + + busy_unlock: + up(&btv->lock); + MOD_DEC_USE_COUNT; + return -EBUSY; +} + +static void radio_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)(dev-1); + + down(&btv->lock); + btv->user--; + btv->radio = 0; + up(&btv->lock); + MOD_DEC_USE_COUNT; +} + +static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct bttv *btv=(struct bttv *)(dev-1); + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability v; + strcpy(v.name,btv->video_dev.name); + v.type = VID_TYPE_TUNER; + v.channels = 1; + v.audios = 1; + /* No we don't do pictures */ + v.maxwidth = 0; + v.maxheight = 0; + v.minwidth = 0; + v.minheight = 0; + if (copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + break; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Radio"); + v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ + v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ + v.flags= 0; /* XXX */ + v.mode = 0; /* XXX */ + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only channel 0 has a tuner */ + if(v.tuner!=0 || btv->channel) + return -EINVAL; + /* XXX anything to do ??? */ + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + bttv_ioctl((struct video_device *)btv,cmd,arg); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device radio_template= +{ + "bttv radio", + VID_TYPE_TUNER, + VID_HARDWARE_BT848, + radio_open, + radio_close, + radio_read, /* just returns -EINVAL */ + bttv_write, /* just returns -EINVAL */ + NULL, /* no poll */ + radio_ioctl, + NULL, /* no mmap */ + bttv_init_done, /* just returns 0 */ + NULL, + 0, + -1 +}; + + +#define TRITON_PCON 0x50 +#define TRITON_BUS_CONCURRENCY (1<<0) +#define TRITON_STREAMING (1<<1) +#define TRITON_WRITE_BURST (1<<2) +#define TRITON_PEER_CONCURRENCY (1<<3) + + +static void __devinit handle_chipset(void) +{ + struct pci_dev *dev = NULL; + + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1=BT848_INT_ETBF; + + while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) + { + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) + { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + { + printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); + triton1=BT848_INT_ETBF; + } +} + + +#if 0 +/* can tda9855.c handle this too maybe? */ +static void __devinit init_tda9840(struct bttv *btv) +{ + /* Horrible Hack */ + I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ + /* 00 - mute + 10 - mono / averaged stereo + 2a - stereo + 12 - dual A + 1a - dual AB + 16 - dual BA + 1e - dual B + 7a - external */ +} +#endif + +static void bt848_set_risc_jmps(struct bttv *btv, int flags) +{ + if (-1 == flags) { + /* defaults */ + flags = 0; + if (btv->scr_on) + flags |= 0x03; + if (btv->vbi_on) + flags |= 0x0c; + } + + if (bttv_debug > 1) + printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); + + /* Sync to start of odd field */ + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRE); + btv->risc_jmp[1]=cpu_to_le32(0); + + /* Jump to odd vbi sub */ + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); + if (flags&8) { + if (bttv_debug > 1) + printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + } + + /* Jump to odd sub */ + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); + if (0 != btv->risc_cap_odd) { + if (bttv_debug > 1) + printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + flags |= 3; + btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); + } else if (flags&2) { + if (bttv_debug > 1) + printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); + } + + + /* Sync to start of even field */ + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRO); + btv->risc_jmp[7]=cpu_to_le32(0); + + /* Jump to even vbi sub */ + btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); + if (flags&4) { + if (bttv_debug > 1) + printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + } + + /* Jump to even sub */ + btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); + if (0 != btv->risc_cap_even) { + if (bttv_debug > 1) + printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + flags |= 3; + btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); + } else if (flags&1) { + if (bttv_debug > 1) + printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); + } else { + if (bttv_debug > 1) + printk(" -----------"); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); + } + + if (btv->gq_start) { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); + } else { + btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); + } + btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); + + /* enable cpaturing and DMA */ + if (bttv_debug > 1) + printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); + btaor(flags, ~0x0f, BT848_CAP_CTL); + if (flags&0x0f) + bt848_dma(btv, 3); + else + bt848_dma(btv, 0); +} + +static int __devinit init_video_dev(struct bttv *btv) +{ + memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); + memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); + memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); + + bttv_idcard(btv); + audio(btv, AUDIO_MUTE, 1); + + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) + return -1; + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + { + video_unregister_device(&btv->video_dev); + return -1; + } + if (radio[btv->nr]) + { + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + { + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->video_dev); + return -1; + } + } + return 1; +} + +static int __devinit init_bt848(struct bttv *btv) +{ + int j; + unsigned long irq_flags; + + btv->user=0; + init_MUTEX(&btv->lock); + + /* dump current state of the gpio registers before changing them, + * might help to make a new card work */ + if (bttv_verbose >= 2) + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + btv->nr, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); + + /* reset the bt848 */ + btwrite(0, BT848_SRESET); + DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem)); + + /* not registered yet */ + btv->video_dev.minor = -1; + btv->radio_dev.minor = -1; + btv->vbi_dev.minor = -1; + + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ + btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ + btv->win.interlace=1; + btv->win.x=0; + btv->win.y=0; + btv->win.width=768; /* 640 */ + btv->win.height=576; /* 480 */ + btv->win.bpp=2; + btv->win.depth=16; + btv->win.color_fmt=BT848_COLOR_FMT_RGB16; + btv->win.bpl=1024*btv->win.bpp; + btv->win.swidth=1024; + btv->win.sheight=768; + btv->win.vidadr=0; + btv->vbi_on=0; + btv->scr_on=0; + + btv->risc_scr_odd=0; + btv->risc_scr_even=0; + btv->risc_cap_odd=0; + btv->risc_cap_even=0; + btv->risc_jmp=0; + btv->vbibuf=0; + btv->field=btv->last_field=0; + + btv->errors=0; + btv->needs_restart=0; + + /* i2c */ + btv->tuner_type=-1; + init_bttv_i2c(btv); + + if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) + return -1; + btv->vbi_odd=btv->risc_jmp+16; + btv->vbi_even=btv->vbi_odd+256; + btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); + btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); + + btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); + btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE); + if (!btv->vbibuf) + return -1; + if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) + return -1; + for (j = 0; j < gbuffers; j++) { + if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) + return -1; + } + + memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random + memory to the user */ + + btv->fbuffer=NULL; + + bt848_muxsel(btv, 1); + bt848_set_winsize(btv); + +/* btwrite(0, BT848_TDEC); */ + btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x00, BT848_CAP_CTL); + /* 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); + + /* select direct input */ + btwrite(0x00, BT848_GPIO_REG_INP); + + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, + BT848_IFORM); + + btwrite(0xd8, BT848_CONTRAST_LO); + bt848_bright(btv, 0x10); + + btwrite(0x20, BT848_E_VSCALE_HI); + btwrite(0x20, BT848_O_VSCALE_HI); + btwrite(/*BT848_ADC_SYNC_T|*/ + BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); + + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + + btv->picture.colour=254<<7; + btv->picture.brightness=128<<8; + btv->picture.hue=128<<8; + btv->picture.contrast=0xd8<<7; + + btwrite(0x00, BT848_E_SCLOOP); + btwrite(0x00, BT848_O_SCLOOP); + + /* clear interrupt status */ + btwrite(0xfffffUL, BT848_INT_STAT); + + /* set interrupt mask */ + btwrite(btv->triton1| + /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| + BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ + (fieldnr ? BT848_INT_VSYNC : 0)| + BT848_INT_GPINT| + BT848_INT_SCERR| + BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| + BT848_INT_FMTCHG|BT848_INT_HLOCK, + BT848_INT_MASK); + + make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + /* + * Now add the template and register the device unit. + */ + init_video_dev(btv); + + return 0; +} + +static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,astat; + u32 dstat; + int count,i; + struct bttv *btv; + unsigned long irq_flags; + + btv=(struct bttv *)dev_id; + count=0; + while (1) + { + /* get/clear interrupt status bits */ + stat=btread(BT848_INT_STAT); + astat=stat&btread(BT848_INT_MASK); + if (!astat) + return; + btwrite(astat,BT848_INT_STAT); + IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (astat&BT848_INT_GPINT) { + IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); + wake_up_interruptible(&btv->gpioq); + } + + if (astat&BT848_INT_FMTCHG) + { + IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); + /*btv->win.norm&= + (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ + } + if (astat&BT848_INT_VPRES) + { + IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr)); + } + if (astat&BT848_INT_VSYNC) + { + IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); + btv->field++; + } + if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { + if (bttv_verbose) + printk("bttv%d: irq:%s%s risc_count=%08x\n", + btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + btv->errors++; + if (btv->errors < BTTV_ERRORS) { + spin_lock_irqsave(&btv->s_lock, irq_flags); + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(virt_to_bus(btv->risc_jmp+2), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + } else { + if (bttv_verbose) + printk("bttv%d: aiee: error loops\n",btv->nr); + /* cancel all outstanding grab requests */ + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + if (btv->gbuf[i].stat == GBUFFER_GRABBING) + btv->gbuf[i].stat = GBUFFER_ERROR; + /* disable DMA */ + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,0); + btv->needs_restart = 1; + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + + wake_up_interruptible(&btv->vbiq); + wake_up_interruptible(&btv->capq); + } + } + if (astat&BT848_INT_RISCI) + { + if (bttv_debug > 1) + printk("bttv%d: IRQ_RISCI\n",btv->nr); + + /* captured VBI frame */ + if (stat&(1<<28)) + { + btv->vbip=0; + /* inc vbi frame count for detecting drops */ + (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++; + wake_up_interruptible(&btv->vbiq); + } + + /* captured full frame */ + if (stat&(2<<28) && btv->gq_grab != -1) + { + btv->last_field=btv->field; + if (bttv_debug) + printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; + btv->gq_grab = -1; + if (btv->gq_in != btv->gq_out) + { + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (bttv_debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + } else { + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + } + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + wake_up_interruptible(&btv->capq); + break; + } + if (stat&(8<<28)) + { + spin_lock_irqsave(&btv->s_lock, irq_flags); + btv->gq_start = 0; + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (bttv_debug) + printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + } + } + if (astat&BT848_INT_OCERR) + { + IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr)); + } + if (astat&BT848_INT_PABORT) + { + IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr)); + } + if (astat&BT848_INT_RIPERR) + { + IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr)); + } + if (astat&BT848_INT_PPERR) + { + IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr)); + } + if (astat&BT848_INT_FDSR) + { + IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr)); + } + if (astat&BT848_INT_FTRGT) + { + IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr)); + } + if (astat&BT848_INT_FBUS) + { + IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr)); + } + if (astat&BT848_INT_HLOCK) + { + if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) + audio(btv, AUDIO_ON,0); + else + audio(btv, AUDIO_OFF,0); + } + + if (astat&BT848_INT_I2CDONE) + { + IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); + } + count++; + if (count > 10) + printk (KERN_WARNING "bttv%d: irq loop %d\n", + btv->nr,count); + if (count > 20) + { + btwrite(0, BT848_INT_MASK); + printk(KERN_ERR + "bttv%d: IRQ lockup, cleared int mask\n", btv->nr); + } + } +} + + + +/* + * Scan for a Bt848 card, request the irq and map the io memory + */ + +static void __devinit bttv_remove(struct pci_dev *pci_dev) +{ + u8 command; + int j; + struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); + + /* unregister i2c_bus */ + i2c_bit_del_bus(&btv->i2c_adap); + + /* turn off all capturing, DMA and IRQs */ + btand(~15, BT848_GPIO_DMA_CTL); + + /* first disable interrupts before unmapping the memory! */ + btwrite(0, BT848_INT_MASK); + btwrite(~0x0UL,BT848_INT_STAT); + btwrite(0x0, BT848_GPIO_OUT_EN); + + /* disable PCI bus-mastering */ + pci_read_config_byte(btv->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command&=~PCI_COMMAND_MASTER; + pci_write_config_byte(btv->dev, PCI_COMMAND, command); + + /* unmap and free memory */ + for (j = 0; j < gbuffers; j++) + if (btv->gbuf[j].risc) + kfree(btv->gbuf[j].risc); + if (btv->gbuf) + kfree((void *) btv->gbuf); + + if (btv->risc_scr_odd) + kfree((void *) btv->risc_scr_odd); + + if (btv->risc_scr_even) + kfree((void *) btv->risc_scr_even); + + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); + if (btv->risc_jmp) + kfree((void *) btv->risc_jmp); + + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); + if (btv->vbibuf) + vfree((void *) btv->vbibuf); + + free_irq(btv->irq,btv); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); + if (btv->bt848_mem) + iounmap(btv->bt848_mem); + + if(btv->video_dev.minor!=-1) + video_unregister_device(&btv->video_dev); + if(btv->vbi_dev.minor!=-1) + video_unregister_device(&btv->vbi_dev); + if (radio[btv->nr] && btv->radio_dev.minor != -1) + video_unregister_device(&btv->radio_dev); + + release_mem_region(btv->bt848_adr, + pci_resource_len(btv->dev,0)); + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + btv->shutdown=1; + wake_up(&btv->gpioq); + + return; +} + + +static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) +{ + int result; + unsigned char command; + struct bttv *btv; +#if defined(__powerpc__) + unsigned int cmd; +#endif + + printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); + + btv=&bttvs[bttv_num]; + btv->dev=dev; + btv->nr = bttv_num; + btv->bt848_mem=NULL; + btv->vbibuf=NULL; + btv->risc_jmp=NULL; + btv->vbi_odd=NULL; + btv->vbi_even=NULL; + init_waitqueue_head(&btv->vbiq); + init_waitqueue_head(&btv->capq); + btv->vbip=VBIBUF_SIZE; + btv->s_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&btv->gpioq); + btv->shutdown=0; + + btv->id=dev->device; + btv->irq=dev->irq; + btv->bt848_adr=pci_resource_start(dev,0); + if (pci_enable_device(dev)) + return -EIO; + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + "bttv")) { + return -EBUSY; + } + if (btv->id >= 878) + btv->i2c_command = 0x83; + else + btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); + printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", + bttv_num,btv->id, btv->revision); + printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); + printk("irq: %d, ",btv->irq); + printk("memory: 0x%lx.\n", btv->bt848_adr); + +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif + + /* clear interrupt mask */ + btwrite(0, BT848_INT_MASK); + + result = request_irq(btv->irq, bttv_irq, + SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); + if (result==-EINVAL) + { + printk(KERN_ERR "bttv%d: Bad irq number or handler\n", + bttv_num); + goto fail; + } + if (result==-EBUSY) + { + printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); + goto fail; + } + if (result < 0) + goto fail; + + pci_set_master(dev); + + btv->triton1=triton1 ? BT848_INT_ETBF : 0; + if (triton1 && btv->id >= 878) + { + btv->triton1 = 0; + printk("bttv: Enabling 430FX compatibilty for bt878\n"); + pci_read_config_byte(dev, BT878_DEVCTRL, &command); + command|=BT878_EN_TBFX; + pci_write_config_byte(dev, BT878_DEVCTRL, command); + pci_read_config_byte(dev, BT878_DEVCTRL, &command); + if (!(command&BT878_EN_TBFX)) + { + printk("bttv: 430FX compatibility could not be enabled\n"); + free_irq(btv->irq,btv); + result = -1; + goto fail; + } + } + + PCI_SET_DRIVER_DATA(dev,btv); + + if(init_bt848(btv) < 0) { + bttv_remove(dev); + return -EIO; + } + bttv_num++; + + return 0; + + fail: + release_mem_region(pci_resource_start(btv->dev,0), + pci_resource_len(btv->dev,0)); + return result; +} + +static struct pci_device_id bttv_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); + +static struct pci_driver bttv_pci_driver = { + name: "bttv", + id_table: bttv_pci_tbl, + probe: bttv_probe, + remove: bttv_remove, +}; + +int bttv_init_module(void) +{ + bttv_num = 0; + + printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", + (BTTV_VERSION_CODE >> 16) & 0xff, + (BTTV_VERSION_CODE >> 8) & 0xff, + BTTV_VERSION_CODE & 0xff); + if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + if (bttv_verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", + gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); + + handle_chipset(); + + return pci_module_init(&bttv_pci_driver); +} + +void bttv_cleanup_module(void) +{ + pci_unregister_driver(&bttv_pci_driver); + return; +} + +module_init(bttv_init_module); +module_exit(bttv_cleanup_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.4.0-test1-ac21/drivers/char/bttv-cards.c Tue May 5 22:32:27 1998 +++ linux/drivers/char/bttv-cards.c Mon Jun 19 23:25:38 2000 @@ -0,0 +1,761 @@ +/* + bttv-cards.c -- this file has card-specific stuff + + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999,2000 Gerd Knorr + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include + +#include + +#include "bttv.h" +#include "tuner.h" + +/* fwd decl */ +static void hauppauge_eeprom(struct bttv *btv); +static void hauppauge_boot_msp34xx(struct bttv *btv); +static void init_PXC200(struct bttv *btv); +static void init_tea5757(struct bttv *btv); + +MODULE_PARM(card,"1-4i"); +MODULE_PARM(pll,"1-4i"); +MODULE_PARM(autoload,"i"); + +static unsigned int card[4] = { -1, -1, -1, -1 }; +static unsigned int pll[4] = { -1, -1, -1, -1 }; +#ifdef MODULE +static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif + +/* ----------------------------------------------------------------------- */ +/* list of card IDs for bt878+ cards */ + +static struct CARD { + unsigned id; + int cardnr; + char *name; +} cards[] __devinitdata = { + { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, + { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00021461, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, + { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, + { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, + { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV/Radio+" }, + { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, + { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, +#if 0 /* probably wrong */ + { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, +#endif + { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, + { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, + { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, + { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, + { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, + { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, + { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, + { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" }, + { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0, -1, NULL } +}; + +/* ----------------------------------------------------------------------- */ +/* array with description for bt848 / bt878 tv/grabber cards */ + +struct tvcard bttv_tvcards[] = +{ + /* 0x00 */ + { " *** UNKNOWN *** ", + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "MIRO PCTV", + 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Hauppauge old", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0,0,0,1, PLL_NONE, -1 }, + { "STB", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,1,0,0,1, PLL_NONE, -1 }, + + { "Intel", + 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Diamond DTV2000", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVerMedia TVPhone", + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "MATRIX-Vision MV-Delta", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x08 */ + { "Fly Video II", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, + { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "TurboTV", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Hauppauge new (bt878)", + 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0,0,0,1, PLL_28, -1 }, + { "MIRO PCTV pro", + 3, 1, 0, 2, 0x3004F, { 2, 3, 1, 1}, {1, 0x10011, 5, 0,10}, 0x3004F, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + { "ADS Technologies Channel Surfer TV", + 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVerMedia TVCapture 98", + 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Aimslab VHX", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Zoltrix TV-Max", + 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x10 */ + { "Pixelview PlayTV (bt878)", + 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, + { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Leadtek WinView 601", + 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, + { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "AVEC Intercapture", + 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "LifeView FlyKit w/o Tuner", + 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, + 0,0,0,0,0,0,0,1, PLL_NONE, -1 }, + + { "CEI Raffles Card", + 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Lucky Star Image World ConferenceTV", + 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I }, + { "Phoebe Tv Master + FM", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Modular Technology MM205 PCTV, bt878", + 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x18 */ + { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", + 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Terratec/Vobis TV-Boostar", + 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Newer Hauppauge WinCam (bt878)", + 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "MAXI TV Video PCI2", + 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, + 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM }, + + { "Terratec TerraTV+", + 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, + { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Imagenation PXC200", + 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "FlyVideo 98", + 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, + { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "iProTV", + 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x20 */ + { "Intel Create and Share PCI", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Terratec TerraTValue", + 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1}, + { 0x500, 0, 0x300, 0x900, 0x900},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + { "Leadtek WinFast 2000", + 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, + { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, + 1,1,1,1,1,0,0,1, PLL_28, -1 }, + { "Chronos Video Shuttle II", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + + { "Typhoon TView TV/FM Tuner", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "PixelView PlayTV pro", + 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0, + 0,0,0,0,0,0,0,1, PLL_28, -1 }, + { "TView99 CPH063", + 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1}, + { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0, + 1,1,1,1,0,0,0,1, PLL_28, -1 }, + { "Pinnacle PCTV Rave", + 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, + 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, + + /* 0x28 */ + { "STB2", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,0,1,1,1, PLL_NONE, -1 }, + { "AVerMedia TVPhone 98", + 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0,0,0,1, PLL_28, 5 }, + { "ProVideo PV951", /* pic16c54 */ + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 0,0,0,0,0,0,0,0, PLL_28, 1 }, + { "Little OnAir TV", + 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, + {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + + { "Sigma TVII-FM", + 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + { "MATRIX-Vision MV-Delta 2", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 0,0,0,0,0,0,0,0, PLL_28, -1 }, + { "Zoltrix Genie TV", + 3, 1, 0, 2, 0xbcf03f, { 2, 3, 1, 1}, + { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f}, 0, + 0,0,0,0,0,0,0,0, PLL_28, 5 }, + { "Terratec TV/Radio+", /* Radio ?? */ + 3, 1, 0, 2, 0x1f0000, { 2, 3, 1, 1}, + { 0xe2ffff, 0, 0, 0, 0xe0ffff, 0xe2ffff },0, + 0,0,0,0,0,0,0,0, PLL_35, 1 }, +}; +const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); + +/* ----------------------------------------------------------------------- */ + +static unsigned char eeprom_data[256]; + +static void __devinit bttv_dump_eeprom(struct bttv *btv,int addr) +{ + int i; + + if (bttv_verbose < 2) + return; + /* for debugging: dump eeprom to syslog */ + printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); + for (i = 0; i < 256;) { + printk(KERN_DEBUG " %02x:",i); + do { + printk(" %02x",eeprom_data[i++]); + } while (i % 16); + printk("\n"); + } +} + +static int __devinit bttv_idcard_eeprom(struct bttv *btv) +{ + unsigned id; + int i,n; + + id = (eeprom_data[252] << 24) | + (eeprom_data[253] << 16) | + (eeprom_data[254] << 8) | + (eeprom_data[255]); + if (id == 0 || id == 0xffffffff) + return -1; + + /* look for the card */ + btv->cardid = id; + for (n = -1, i = 0; cards[i].id != 0; i++) + if (cards[i].id == id) + n = i; + + if (n != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: card id: %s (0x%08x) => card=%d\n", + btv->nr,cards[n].name,id,cards[n].cardnr); + return cards[n].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n", + btv->nr, id); + printk(KERN_INFO "please mail id, board name and " + "the correct card= insmod option to " + "kraxel@goldbach.in-berlin.de\n"); + return -1; + } +} + +void __devinit bttv_idcard(struct bttv *btv) +{ + int type,eeprom = 0; + + btwrite(0, BT848_GPIO_OUT_EN); + + /* try to autodetect the card */ + /* many bt878 cards have a eeprom @ 0xa0 => read ID + and try to identify it */ + if (bttv_I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { + eeprom = 0xa0; + bttv_readee(btv,eeprom_data,0xa0); + bttv_dump_eeprom(btv,0xa0); /* DEBUG */ + type = bttv_idcard_eeprom(btv); + if (-1 != type) { + btv->type = type; + } else if (btv->id <= 849) { + /* for unknown bt848, assume old Hauppauge */ + btv->type=BTTV_HAUPPAUGE; + } + + /* STB cards have a eeprom @ 0xae (old bt848) */ + } else if (bttv_I2CRead(btv, I2C_STBEE, "eeprom")>=0) { + btv->type=BTTV_STB; + } + + /* let the user override the autodetected type */ + if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) + btv->type=card[btv->nr]; + + /* print which card config we are using */ + sprintf(btv->video_dev.name,"BT%d%s(%.23s)", + btv->id, + (btv->id==848 && btv->revision==0x12) ? "A" : "", + bttv_tvcards[btv->type].name); + printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name, + (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ? + "insmod option" : "autodetected"); + + /* board specific initialisations */ + if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { + /* auto detect tuner for MIRO cards */ + btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; + if (btv->type == BTTV_MIROPRO) { + if (bttv_verbose) + printk(KERN_INFO "Initializing TEA5757...\n"); + init_tea5757(btv); + } + } + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { + /* pick up some config infos from the eeprom */ + if (0xa0 != eeprom) { + eeprom = 0xa0; + bttv_readee(btv,eeprom_data,0xa0); + } + hauppauge_eeprom(btv); + hauppauge_boot_msp34xx(btv); + } + if (btv->type == BTTV_PXC200) + init_PXC200(btv); + + /* pll configuration */ + if (!(btv->id==848 && btv->revision==0x11)) { + /* defaults from card list */ + if (PLL_28 == bttv_tvcards[btv->type].pll) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + /* insmod options can override */ + switch (pll[btv->nr]) { + case 0: /* none */ + btv->pll.pll_crystal = 0; + btv->pll.pll_ifreq = 0; + btv->pll.pll_ofreq = 0; + break; + case 1: /* 28 MHz */ + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT0; + break; + case 2: /* 35 MHz */ + btv->pll.pll_ifreq = 35468950; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal=BT848_IFORM_XT1; + break; + } + } + + + /* tuner configuration */ + if (-1 != bttv_tvcards[btv->type].tuner_type) + btv->tuner_type = bttv_tvcards[btv->type].tuner_type; + if (btv->tuner_type != -1) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + + /* try to detect audio/fader chips */ + if (bttv_tvcards[btv->type].msp34xx && + bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { + if (autoload) + request_module("msp3400"); + } + + if (bttv_tvcards[btv->type].tda8425 && + bttv_I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { + if (autoload) + request_module("tda8425"); + } + +#if 0 + if (bttv_tvcards[btv->type].tda9840 && + I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { + init_tda9840(btv); + btv->audio_chip = TDA9840; + /* move this to a module too? */ + init_tda9840(btv); + } +#endif + + if (bttv_tvcards[btv->type].tda985x && + bttv_I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { + if (autoload) + request_module("tda985x"); + } + + if (bttv_tvcards[btv->type].tda9875 && + bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { + if (autoload) + request_module("tda9875"); + } + + if (bttv_tvcards[btv->type].tda7432 && + bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { + if (autoload) + request_module("tda7432"); + } + + if (bttv_tvcards[btv->type].tea63xx) { + if (autoload) + request_module("tea6300"); + } + + if (bttv_tvcards[btv->type].tea64xx) { + if (autoload) + request_module("tea6420"); + } + + if (bttv_tvcards[btv->type].tuner != -1) { + if (autoload) + request_module("tuner"); + } +} + + +/* ----------------------------------------------------------------------- */ +/* some hauppauge specific stuff */ + +static struct HAUPPAUGE_TUNER +{ + int id; + char *name; +} +hauppauge_tuner[] __devinitdata = +{ + { TUNER_ABSENT, "" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_ABSENT, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_ABSENT, "Philips FI1246" }, + { TUNER_ABSENT, "Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_ABSENT, "Philips FI1256 MK2" }, + { TUNER_ABSENT, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_ABSENT, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_ABSENT, "Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_ABSENT, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_ABSENT, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_ABSENT, "Temic 4039FR5" }, + { TUNER_ABSENT, "Philips FQ1216 ME" }, + { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Temic 4006FN5" }, + { TUNER_ABSENT, "Temic 4009FR5" }, + { TUNER_ABSENT, "Temic 4046FM5" }, +}; + +static void __devinit hauppauge_eeprom(struct bttv *btv) +{ + if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) + { + btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; + if (bttv_verbose) + printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, + hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); + } +} + +static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) +{ + int i; + + /* reset/enable the MSP on some Hauppauge cards */ + /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ + btaor(32, ~32, BT848_GPIO_OUT_EN); + btaor(0, ~32, BT848_GPIO_DATA); + udelay(2500); + btaor(32, ~32, BT848_GPIO_DATA); + + if (bttv_verbose) + printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); + + /* look if the msp3400 driver is already registered */ + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] != NULL && + btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { + return; + } + } + + /* if not: look for the chip ... */ + if (bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx")) { + /* ... if found re-register to trigger a i2c bus rescan, */ + /* this time with the msp34xx chip activated */ + i2c_bit_del_bus(&btv->i2c_adap); + i2c_bit_add_bus(&btv->i2c_adap); + } +} + + +/* ----------------------------------------------------------------------- */ +/* Imagenation L-Model PXC200 Framegrabber */ +/* This is basically the same procedure as + * used by Alessandro Rubini in his pxc200 + * driver, but using BTTV functions */ +static void __devinit init_PXC200(struct bttv *btv) +{ + static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x00 }; + int i,tmp; + + /* Initialise GPIO-connevted stuff */ + btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ + btwrite(0,BT848_GPIO_DATA); + udelay(3); + btwrite(1<<13,BT848_GPIO_DATA); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + btwrite(0,BT848_GPIO_OUT_EN); + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); + + /* Initialise MAX517 DAC */ + printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + bttv_I2CWrite(btv,0x5E,0,0x80,1); + + /* Initialise 12C508 PIC */ + /* The I2CWrite and I2CRead commmands are actually to the + * same chips - but the R/W bit is included in the address + * argument so the numbers are different */ + + printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + + for (i = 0; i < sizeof(vals)/sizeof(int); i++) { + tmp=bttv_I2CWrite(btv,0x1E,vals[i],0,1); + printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n", + tmp,bttv_I2CRead(btv,0x1F,NULL)); + } + printk(KERN_INFO "PXC200 Initialised.\n"); +} + +/* ----------------------------------------------------------------------- */ +/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */ +/* + * Copyright (c) 1999 Csaba Halasz + * This code is placed under the terms of the GNU General Public License + * + * Brutally hacked by Dan Sheridan djs52 8/3/00 + */ + +/* bus bits on the GPIO port */ +#define TEA_WE 6 +#define TEA_DATA 9 +#define TEA_CLK 8 +#define TEA_MOST 7 + +#define BUS_LOW(bit) btand(~(1<> TEA_##bit) & 1) + +/* TEA5757 register bits */ +#define TEA_FREQ 0:14 +#define TEA_BUFFER 15:15 + +#define TEA_SIGNAL_STRENGTH 16:17 + +#define TEA_PORT1 18:18 +#define TEA_PORT0 19:19 + +#define TEA_BAND 20:21 +#define TEA_BAND_FM 0 +#define TEA_BAND_MW 1 +#define TEA_BAND_LW 2 +#define TEA_BAND_SW 3 + +#define TEA_MONO 22:22 +#define TEA_ALLOW_STEREO 0 +#define TEA_FORCE_MONO 1 + +#define TEA_SEARCH_DIRECTION 23:23 +#define TEA_SEARCH_DOWN 0 +#define TEA_SEARCH_UP 1 + +#define TEA_STATUS 24:24 +#define TEA_STATUS_TUNED 0 +#define TEA_STATUS_SEARCHING 1 + +/* Low-level stuff */ +static int tea_read(struct bttv *btv) +{ + int value = 0; + long timeout; + int i; + + /* better safe than sorry */ + btaor((1< + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#define __NO_VERSION__ 1 + +#include +#include +#include + +#include + +#include "bttv.h" +#include "tuner.h" + + +EXPORT_SYMBOL(bttv_get_cardinfo); +EXPORT_SYMBOL(bttv_get_id); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); + +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) +{ + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].type; + *cardid = bttvs[card].cardid; + return 0; +} + +int bttv_get_id(unsigned int card) +{ + printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); + if (card >= bttv_num) { + return -1; + } + return bttvs[card].type; +} + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + btaor(data, ~mask, BT848_GPIO_OUT_EN); + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + if(btv->shutdown) { + return -ENODEV; + } + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + *data = btread(BT848_GPIO_DATA); + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + btaor(data & mask, ~mask, BT848_GPIO_DATA); + return 0; +} + +wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + if (bttvs[card].shutdown) { + return NULL; + } + return &btv->gpioq; +} + + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ + +static void bttv_bit_setscl(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static void bttv_bit_setsda(void *data, int state) +{ + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); +} + +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} + +static int bttv_bit_getsda(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; +} + +static void bttv_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void bttv_dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +static int attach_inform(struct i2c_client *client) +{ + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] == NULL || + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = client; + break; + } + } + if (btv->tuner_type != -1) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (bttv_verbose) + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + if (bttv_verbose) + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL != btv->i2c_clients[i] && + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = NULL; + break; + } + } + return 0; +} + +void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == btv->i2c_clients[i]) + continue; + if (NULL == btv->i2c_clients[i]->driver->command) + continue; + btv->i2c_clients[i]->driver->command( + btv->i2c_clients[i],cmd,arg); + } +} + +struct i2c_algo_bit_data bttv_i2c_algo_template = { + NULL, + bttv_bit_setsda, + bttv_bit_setscl, + bttv_bit_getsda, + bttv_bit_getscl, + 10, 10, 100, +}; + +struct i2c_adapter bttv_i2c_adap_template = { + "bt848", + I2C_HW_B_BT848, + NULL, + NULL, + bttv_inc_use, + bttv_dec_use, + attach_inform, + detach_inform, + NULL, +}; + +struct i2c_client bttv_i2c_client_template = { + "bttv internal", + -1, + 0, + 0, + NULL, + NULL +}; + + +/* read I2C */ +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +{ + unsigned char buffer = 0; + + if (0 != btv->i2c_ok) + return -1; + if (bttv_verbose && NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) { + if (bttv_verbose) + printk("not found\n"); + } else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->nr,addr); + return -1; + } + if (bttv_verbose && NULL != probe_for) + printk("found\n"); + return buffer; +} + +/* write I2C */ +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) +{ + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + if (0 != btv->i2c_ok) + return -1; + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; +} + +/* read EEPROM content */ +void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr) +{ + int i; + + if (bttv_I2CWrite(btv, addr, 0, -1, 0)<0) { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + btv->i2c_client.addr = addr >> 1; + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + } +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ --- linux-2.4.0-test1-ac21/drivers/char/bttv.h Sun Jun 18 20:41:12 2000 +++ linux/drivers/char/bttv.h Mon Jun 19 23:25:38 2000 @@ -21,7 +21,7 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,31) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,34) #ifndef PCI_GET_DRIVER_DATA # define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) @@ -37,6 +37,109 @@ #include "audiochip.h" #include "bt848.h" +#ifdef __KERNEL__ + +/* fwd decl */ +struct bttv; + + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_UNKNOWN 0x00 +#define BTTV_MIRO 0x01 +#define BTTV_HAUPPAUGE 0x02 +#define BTTV_STB 0x03 +#define BTTV_INTEL 0x04 +#define BTTV_DIAMOND 0x05 +#define BTTV_AVERMEDIA 0x06 +#define BTTV_MATRIX_VISION 0x07 +#define BTTV_FLYVIDEO 0x08 +#define BTTV_TURBOTV 0x09 +#define BTTV_HAUPPAUGE878 0x0a +#define BTTV_MIROPRO 0x0b +#define BTTV_ADSTECH_TV 0x0c +#define BTTV_AVERMEDIA98 0x0d +#define BTTV_VHX 0x0e +#define BTTV_ZOLTRIX 0x0f +#define BTTV_PIXVIEWPLAYTV 0x10 +#define BTTV_WINVIEW_601 0x11 +#define BTTV_AVEC_INTERCAP 0x12 +#define BTTV_LIFE_FLYKIT 0x13 +#define BTTV_CEI_RAFFLES 0x14 +#define BTTV_CONFERENCETV 0x15 +#define BTTV_PHOEBE_TVMAS 0x16 +#define BTTV_MODTEC_205 0x17 +#define BTTV_MAGICTVIEW061 0x18 +#define BTTV_VOBIS_BOOSTAR 0x19 +#define BTTV_HAUPPAUG_WCAM 0x1a +#define BTTV_MAXI 0x1b +#define BTTV_TERRATV 0x1c +#define BTTV_PXC200 0x1d +#define BTTV_FLYVIDEO_98 0x1e +#define BTTV_IPROTV 0x1f +#define BTTV_INTEL_C_S_PCI 0x20 +#define BTTV_TERRATVALUE 0x21 +#define BTTV_WINFAST2000 0x22 +#define BTTV_CHRONOS_VS2 0x23 +#define BTTV_TYPHOON_TVIEW 0x24 +#define BTTV_PXELVWPLTVPRO 0x25 +#define BTTV_MAGICTVIEW063 0x26 +#define BTTV_PINNACLERAVE 0x27 +#define BTTV_STB2 0x28 +#define BTTV_AVPHONE98 0x29 +#define BTTV_PV951 0x2a +#define BTTV_ONAIR_TV 0x2b +#define BTTV_SIGMA_TVII_FM 0x2c +#define BTTV_MATRIX_VISION2 0x2d +#define BTTV_ZOLTRIX_GENIE 0x2e +#define BTTV_TERRATVRADIO 0x2f + +struct tvcard +{ + char *name; + int video_inputs; + int audio_inputs; + int tuner; + int svhs; + u32 gpiomask; + u32 muxsel[8]; + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* look for these i2c audio chips */ + int msp34xx:1; + int tda8425:1; + int tda9840:1; + int tda985x:1; + int tea63xx:1; + int tea64xx:1; + int tda7432:1; + int tda9875:1; + + /* other settings */ + int pll; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + int tuner_type; +}; + +extern struct tvcard bttv_tvcards[]; +extern const int bttv_num_tvcards; + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); + + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ +/* interface for gpio access by other modules */ + /* returns card type + card ID (for bt878-based ones) for possible values see lines below beginning with #define BTTV_UNKNOWN returns negative value if error ocurred @@ -62,8 +165,8 @@ (data & mask) | (current_GPDATA_value & ~mask) returns negative value if error ocurred */ -extern int bttv_write_gpio(unsigned int card, - unsigned long mask, unsigned long data); +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); /* returns pointer to task queue which can be used as parameter to interruptible_sleep_on @@ -76,6 +179,29 @@ */ extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); +/* i2c */ +struct i2c_algo_bit_data bttv_i2c_algo_template; +struct i2c_adapter bttv_i2c_adap_template; +struct i2c_client bttv_i2c_client_template; +void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; + +/* Anybody who uses more than four? */ +#define BTTV_MAX 4 +extern int bttv_num; /* number of Bt848s in use */ +extern struct bttv bttvs[BTTV_MAX]; + #ifndef O_NONCAP #define O_NONCAP O_TRUNC @@ -89,8 +215,6 @@ #define BTTV_MAX_FBUF 0x208000 #define I2C_CLIENTS_MAX 8 -#ifdef __KERNEL__ - struct bttv_window { int x, y; @@ -238,56 +362,6 @@ #define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int) #define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) -#define BTTV_UNKNOWN 0x00 -#define BTTV_MIRO 0x01 -#define BTTV_HAUPPAUGE 0x02 -#define BTTV_STB 0x03 -#define BTTV_INTEL 0x04 -#define BTTV_DIAMOND 0x05 -#define BTTV_AVERMEDIA 0x06 -#define BTTV_MATRIX_VISION 0x07 -#define BTTV_FLYVIDEO 0x08 -#define BTTV_TURBOTV 0x09 -#define BTTV_HAUPPAUGE878 0x0a -#define BTTV_MIROPRO 0x0b -#define BTTV_ADSTECH_TV 0x0c -#define BTTV_AVERMEDIA98 0x0d -#define BTTV_VHX 0x0e -#define BTTV_ZOLTRIX 0x0f -#define BTTV_PIXVIEWPLAYTV 0x10 -#define BTTV_WINVIEW_601 0x11 -#define BTTV_AVEC_INTERCAP 0x12 -#define BTTV_LIFE_FLYKIT 0x13 -#define BTTV_CEI_RAFFLES 0x14 -#define BTTV_CONFERENCETV 0x15 -#define BTTV_PHOEBE_TVMAS 0x16 -#define BTTV_MODTEC_205 0x17 -#define BTTV_MAGICTVIEW061 0x18 -#define BTTV_VOBIS_BOOSTAR 0x19 -#define BTTV_HAUPPAUG_WCAM 0x1a -#define BTTV_MAXI 0x1b -#define BTTV_TERRATV 0x1c -#define BTTV_PXC200 0x1d -#define BTTV_FLYVIDEO_98 0x1e -#define BTTV_IPROTV 0x1f -#define BTTV_INTEL_C_S_PCI 0x20 -#define BTTV_TERRATVALUE 0x21 -#define BTTV_WINFAST2000 0x22 -#define BTTV_CHRONOS_VS2 0x23 -#define BTTV_TYPHOON_TVIEW 0x24 -#define BTTV_PXELVWPLTVPRO 0x25 -#define BTTV_MAGICTVIEW063 0x26 -#define BTTV_PINNACLERAVE 0x27 -#define BTTV_STB2 0x28 -#define BTTV_AVPHONE98 0x29 -#define BTTV_PV951 0x2a -#define BTTV_ONAIR_TV 0x2b -#define BTTV_SIGMA_TVII_FM 0x2c - -#define PLL_NONE 0 -#define PLL_28 1 -#define PLL_35 2 - #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 #define AUDIO_EXTERN 0x02 @@ -306,7 +380,7 @@ #define I2C_TDA7432 0x8a #define I2C_TDA8425 0x82 #define I2C_TDA9840 0x84 -#define I2C_TDA9850 0xb6 +#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ #define I2C_TDA9875 0xb0 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae @@ -327,6 +401,15 @@ #define WINVIEW_PT2254_CLK 0x40 #define WINVIEW_PT2254_DATA 0x20 #define WINVIEW_PT2254_STROBE 0x80 + +struct bttv_just_hacking { + int height,width; /* size */ + unsigned int format; /* should be VIDEO_PALETTE_* */ + long buf; + int len; +}; + +#define BTTV_JUST_HACKING _IOR('v' , BASE_VIDIOCPRIVATE+31,struct bttv_just_hacking) #endif --- linux-2.4.0-test1-ac21/drivers/char/msp3400.c Sun Jun 18 11:16:35 2000 +++ linux/drivers/char/msp3400.c Mon Jun 19 23:25:38 2000 @@ -679,10 +679,10 @@ #endif exit_mm(current); - exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); + current->fs->umask = 0; strcpy(current->comm,"msp3400"); msp->thread = current; @@ -931,10 +931,10 @@ #endif exit_mm(current); - exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); + current->fs->umask = 0; strcpy(current->comm,"msp3410 [auto]"); msp->thread = current; @@ -1255,6 +1255,7 @@ if (client->adapter->inc_use) client->adapter->inc_use(client->adapter); + MOD_INC_USE_COUNT; return 0; } @@ -1265,6 +1266,7 @@ if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); + MOD_DEC_USE_COUNT; return 0; } @@ -1275,7 +1277,6 @@ } static struct file_operations msp3400c_mixer_fops = { - owner: THIS_MODULE, llseek: msp3400c_mixer_llseek, ioctl: msp3400c_mixer_ioctl, open: msp3400c_mixer_open, --- linux-2.4.0-test1-ac21/drivers/char/tvmixer.c Sun Jun 18 11:16:36 2000 +++ linux/drivers/char/tvmixer.c Mon Jun 19 23:25:38 2000 @@ -53,7 +53,6 @@ }; static struct file_operations tvmixer_fops = { - owner: THIS_MODULE, llseek: tvmixer_llseek, ioctl: tvmixer_ioctl, open: tvmixer_open, @@ -214,6 +213,7 @@ file->private_data = mix; if (client->adapter->inc_use) client->adapter->inc_use(client->adapter); + MOD_INC_USE_COUNT; return 0; } @@ -227,6 +227,7 @@ if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); + MOD_DEC_USE_COUNT; return 0; } --- linux-2.4.0-test1-ac21/Documentation/video4linux/bttv/Insmod-options Sun Jun 18 11:16:27 2000 +++ linux/Documentation/video4linux/bttv/Insmod-options Mon Jun 19 23:25:38 2000 @@ -10,8 +10,8 @@ 1: 28 MHz crystal installed 2: 35 MHz crystal installed triton1=0/1 for Triton1 compatibility - Triton1 is automatically recognized - but this might also help with other chipsets + Triton1 is automatically recognized + but this might also help with other chipsets bigendian=n Set the endianness of the gfx framebuffer. Default is native endian. fieldnr=0/1 Count fields. Some TV descrambling software @@ -19,14 +19,14 @@ 50 useless IRQs/sec. default is 0 (off). autoload=0/1 autoload helper modules (tuner, audio). default is 1 (on). - verbose=0/1/2 verbose level (at insmod time, while looking at - the hardware). default is 1. - debug=0/1 debug messages (for capture). + bttv_verbose=0/1/2 verbose level (at insmod time, while looking + at the hardware). default is 1. + bttv_debug=0/1 debug messages (for capture). default is 0 (off). gbuffers=2-64 number of capture buffers for mmap'ed capture. default is 2. - gbufsize=n size of capture buffers. default and - maximum value is 0x208000 (~2MB) + gbufsize= size of capture buffers. default and + maximum value is 0x208000 (~2MB) remap, card, radio and pll accept up to four comma-separated arguments (for multiple boards). --- linux-2.4.0-test1-ac21/Documentation/video4linux/bttv/CARDLIST Sun Jun 18 11:16:27 2000 +++ linux/Documentation/video4linux/bttv/CARDLIST Mon Jun 19 23:25:38 2000 @@ -44,6 +44,9 @@ card=42 - ProVideo PV951 card=43 - Little OnAir TV card=44 - Sigma TVII-FM + card=45 - MATRIX-Vision MV-Delta 2 + card=46 - Zoltrix Genie TV + card=47 - Terratec TV/Radio+ tuner.o type=0 - Temic PAL --- linux-2.4.0-test1-ac21/drivers/char/bttv.c Sun Jun 18 11:16:34 2000 +++ linux/drivers/char/bttv.c Tue May 5 22:32:27 1998 @@ -1,3998 +0,0 @@ -/* - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999,2000 Gerd Knorr - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "tuner.h" - -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ -#define MIN(a,b) (((a)>(b))?(b):(a)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - - -/* Anybody who uses more than four? */ -#define BTTV_MAX 4 -static void bt848_set_risc_jmps(struct bttv *btv, int state); - -static int bttv_num; /* number of Bt848s in use */ -static struct bttv bttvs[BTTV_MAX]; - - -/* insmod args */ -MODULE_PARM(triton1,"i"); -MODULE_PARM(radio,"1-4i"); -MODULE_PARM(card,"1-4i"); -MODULE_PARM(pll,"1-4i"); -MODULE_PARM(bigendian,"i"); -MODULE_PARM(fieldnr,"i"); -MODULE_PARM(verbose,"i"); -MODULE_PARM(debug,"i"); -MODULE_PARM(autoload,"i"); -MODULE_PARM(gbuffers,"i"); -MODULE_PARM(gbufsize,"i"); - -EXPORT_SYMBOL(bttv_get_cardinfo); -EXPORT_SYMBOL(bttv_get_id); -EXPORT_SYMBOL(bttv_gpio_enable); -EXPORT_SYMBOL(bttv_read_gpio); -EXPORT_SYMBOL(bttv_write_gpio); -EXPORT_SYMBOL(bttv_get_gpio_queue); - -MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); -MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); - -#if defined(__sparc__) || defined(__powerpc__) -static unsigned int bigendian=1; -#else -static unsigned int bigendian=0; -#endif -static int triton1=0; -static unsigned int radio[BTTV_MAX]; -static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; -static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1}; -static unsigned int fieldnr = 0; -static unsigned int verbose = 1; -static unsigned int debug = 0; -static unsigned int gbuffers = 2; -static unsigned int gbufsize = BTTV_MAX_FBUF; -#ifdef MODULE -static unsigned int autoload = 1; -#else -static unsigned int autoload = 0; -#endif - - -#define I2C_TIMING (0x7<<4) -#define I2C_DELAY 10 - -#define I2C_SET(CTRL,DATA) \ - { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } -#define I2C_GET() (btread(BT848_I2C)&1) - -#define BURSTOFFSET 76 -#define BTTV_ERRORS 5 - - -/* ----------------------------------------------------------------------- */ -/* Exported functions - for other modules which want to access the */ -/* gpio ports (IR for example) */ -/* see bttv.h for comments */ - -int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) -{ - if (card >= bttv_num) { - return -1; - } - *type = bttvs[card].type; - *cardid = bttvs[card].cardid; - return 0; -} - -int bttv_get_id(unsigned int card) -{ - printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); - if (card >= bttv_num) { - return -1; - } - return bttvs[card].type; -} - -int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - btaor(data, ~mask, BT848_GPIO_OUT_EN); - return 0; -} - -int bttv_read_gpio(unsigned int card, unsigned long *data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - - if(btv->shutdown) { - return -ENODEV; - } - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because we set direct input on init */ - *data = btread(BT848_GPIO_DATA); - return 0; -} - -int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return -EINVAL; - } - - btv = &bttvs[card]; - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because direct input is set on init */ - btaor(data & mask, ~mask, BT848_GPIO_DATA); - return 0; -} - -wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) -{ - struct bttv *btv; - - if (card >= bttv_num) { - return NULL; - } - - btv = &bttvs[card]; - if (bttvs[card].shutdown) { - return NULL; - } - return &btv->gpioq; -} - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -#define MDEBUG(x) do { } while(0) /* Debug memory management */ - -/* [DaveM] I've recoded most of this so that: - * 1) It's easier to tell what is happening - * 2) It's more portable, especially for translating things - * out of vmalloc mapped areas in the kernel. - * 3) Less unnecessary translations happen. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ - -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) - ret = (page_address(pte_page(pte))|(adr&(PAGE_SIZE-1))); - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long uvirt_to_bus(unsigned long adr) -{ - unsigned long kva, ret; - - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; -} - -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - return ret; -} - -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) -{ - unsigned long va, kva, ret; - - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} - -static void * rvmalloc(signed long size) -{ - void * mem; - unsigned long adr, page; - - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_reserve(MAP_NR(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, signed long size) -{ - unsigned long adr, page; - - if (mem) - { - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_unreserve(MAP_NR(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} - - - -/* - * Create the giant waste of buffer space we need for now - * until we get DMA to user space sorted out (probably 2.3.x) - * - * We only create this as and when someone uses mmap - */ - -static int fbuffer_alloc(struct bttv *btv) -{ - if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); - else - printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", - btv->nr); - if(!btv->fbuffer) - return -ENOBUFS; - return 0; -} - - -/* ----------------------------------------------------------------------- */ -/* I2C functions */ - -static void bttv_bit_setscl(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x02; - else - btv->i2c_state &= ~0x02; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static void bttv_bit_setsda(void *data, int state) -{ - struct bttv *btv = (struct bttv*)data; - - if (state) - btv->i2c_state |= 0x01; - else - btv->i2c_state &= ~0x01; - btwrite(btv->i2c_state, BT848_I2C); - btread(BT848_I2C); -} - -static int bttv_bit_getscl(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x02 ? 1 : 0; - return state; -} - -static int bttv_bit_getsda(void *data) -{ - struct bttv *btv = (struct bttv*)data; - int state; - - state = btread(BT848_I2C) & 0x01; - return state; -} - -static void bttv_inc_use(struct i2c_adapter *adap) -{ - MOD_INC_USE_COUNT; -} - -static void bttv_dec_use(struct i2c_adapter *adap) -{ - MOD_DEC_USE_COUNT; -} - -static void call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) -{ - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (NULL == btv->i2c_clients[i]) - continue; - if (NULL == btv->i2c_clients[i]->driver->command) - continue; - btv->i2c_clients[i]->driver->command( - btv->i2c_clients[i],cmd,arg); - } -} - -static int attach_inform(struct i2c_client *client) -{ - struct bttv *btv = (struct bttv*)client->adapter->data; - int i; - - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] == NULL || - btv->i2c_clients[i]->driver->id == client->driver->id) { - btv->i2c_clients[i] = client; - break; - } - } - if (btv->tuner_type != -1) - call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - if (verbose) - printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - struct bttv *btv = (struct bttv*)client->adapter->data; - int i; - - if (verbose) - printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (NULL != btv->i2c_clients[i] && - btv->i2c_clients[i]->driver->id == client->driver->id) { - btv->i2c_clients[i] = NULL; - break; - } - } - return 0; -} - -static struct i2c_algo_bit_data i2c_algo_template = { - NULL, - bttv_bit_setsda, - bttv_bit_setscl, - bttv_bit_getsda, - bttv_bit_getscl, - 10, 10, 100, -}; - -static struct i2c_adapter i2c_adap_template = { - "bt848", - I2C_HW_B_BT848, - NULL, - NULL, - bttv_inc_use, - bttv_dec_use, - attach_inform, - detach_inform, - NULL, -}; - -static struct i2c_client i2c_client_template = { - "bttv internal", - -1, - 0, - 0, - NULL, - NULL -}; - -static int __devinit init_bttv_i2c(struct bttv *btv) -{ - /* i2c bit_adapter */ - memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); - memcpy(&btv->i2c_algo, &i2c_algo_template, sizeof(struct i2c_algo_bit_data)); - memcpy(&btv->i2c_client, &i2c_client_template, sizeof(struct i2c_client)); - - sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), - " #%d", btv->nr); - btv->i2c_algo.data = btv; - btv->i2c_adap.data = btv; - btv->i2c_adap.algo_data = &btv->i2c_algo; - btv->i2c_client.adapter = &btv->i2c_adap; - - bttv_bit_setscl(btv,1); - bttv_bit_setsda(btv,1); - - btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap); - return btv->i2c_ok; -} - -/* read I2C */ -static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) -{ - unsigned char buffer = 0; - - if (0 != btv->i2c_ok) - return -1; - if (verbose && NULL != probe_for) - printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", - btv->nr,probe_for,addr); - btv->i2c_client.addr = addr >> 1; - if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) { - if (verbose) - printk("not found\n"); - } else - printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", - btv->nr,addr); - return -1; - } - if (verbose && NULL != probe_for) - printk("found\n"); - return buffer; -} - -/* write I2C */ -static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both) -{ - unsigned char buffer[2]; - int bytes = both ? 2 : 1; - - if (0 != btv->i2c_ok) - return -1; - btv->i2c_client.addr = addr >> 1; - buffer[0] = b1; - buffer[1] = b2; - if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) - return -1; - return 0; -} - -/* read EEPROM */ -static void __devinit readee(struct bttv *btv, unsigned char *eedata, int addr) -{ - int i; - - if (I2CWrite(btv, addr, 0, -1, 0)<0) { - printk(KERN_WARNING "bttv: readee error\n"); - return; - } - btv->i2c_client.addr = addr >> 1; - for (i=0; i<256; i+=16) { - if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { - printk(KERN_WARNING "bttv: readee error\n"); - break; - } - } -} - - -/* ----------------------------------------------------------------------- */ -/* some hauppauge specific stuff */ - -static unsigned char eeprom_data[256]; -static struct HAUPPAUGE_TUNER -{ - int id; - char *name; -} -hauppauge_tuner[] __devinitdata = -{ - { TUNER_ABSENT, "" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_ABSENT, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_ABSENT, "Philips FI1246" }, - { TUNER_ABSENT, "Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_ABSENT, "Philips FI1256 MK2" }, - { TUNER_ABSENT, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_ABSENT, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, - { TUNER_ABSENT, "Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_ABSENT, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_ABSENT, "Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_PAL, "Temic 4006FH5" }, - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_ABSENT, "Temic 4039FR5" }, - { TUNER_ABSENT, "Philips FQ1216 ME" }, - { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, - { TUNER_ABSENT, "Philips TD1536" }, - { TUNER_ABSENT, "Philips TD1536D" }, - { TUNER_ABSENT, "Philips FMR1236" }, - { TUNER_ABSENT, "Philips FI1256MP" }, - { TUNER_ABSENT, "Samsung TCPQ9091P" }, - { TUNER_ABSENT, "Temic 4006FN5" }, - { TUNER_ABSENT, "Temic 4009FR5" }, - { TUNER_ABSENT, "Temic 4046FM5" }, -}; - -static void __devinit hauppauge_eeprom(struct bttv *btv) -{ - if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) - { - btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; - if (verbose) - printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, - hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); - } -} - -static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) -{ - int i; - - /* reset/enable the MSP on some Hauppauge cards */ - /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ - btaor(32, ~32, BT848_GPIO_OUT_EN); - btaor(0, ~32, BT848_GPIO_DATA); - udelay(2500); - btaor(32, ~32, BT848_GPIO_DATA); - - if (verbose) - printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); - - /* look if the msp3400 driver is already registered */ - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (btv->i2c_clients[i] != NULL && - btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { - return; - } - } - - /* if not: look for the chip ... */ - if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) { - /* ... if found re-register to trigger a i2c bus rescan, */ - /* this time with the msp34xx chip activated */ - i2c_bit_del_bus(&btv->i2c_adap); - i2c_bit_add_bus(&btv->i2c_adap); - } -} - - -/* Imagenation L-Model PXC200 Framegrabber */ -/* This is basically the same procedure as - * used by Alessandro Rubini in his pxc200 - * driver, but using BTTV functions */ -static void __devinit init_PXC200(struct bttv *btv) -{ - static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x00 }; - int i,tmp; - - /* Initialise GPIO-connevted stuff */ - btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ - btwrite(0,BT848_GPIO_DATA); - udelay(3); - btwrite(1<<13,BT848_GPIO_DATA); - /* GPIO inputs are pulled up, so no need to drive - * reset pin any longer */ - btwrite(0,BT848_GPIO_OUT_EN); - - /* we could/should try and reset/control the AD pots? but - right now we simply turned off the crushing. Without - this the AGC drifts drifts - remember the EN is reverse logic --> - setting BT848_ADC_AGC_EN disable the AGC - tboult@eecs.lehigh.edu - */ - btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); - - /* Initialise MAX517 DAC */ - printk(KERN_INFO "Setting DAC reference voltage level ...\n"); - I2CWrite(btv,0x5E,0,0x80,1); - - /* Initialise 12C508 PIC */ - /* The I2CWrite and I2CRead commmands are actually to the - * same chips - but the R/W bit is included in the address - * argument so the numbers are different */ - - printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); - - for (i = 0; i < sizeof(vals)/sizeof(int); i++) { - tmp=I2CWrite(btv,0x1E,vals[i],0,1); - printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n", - tmp,I2CRead(btv,0x1F,NULL)); - } - printk(KERN_INFO "PXC200 Initialised.\n"); -} - -/* ----------------------------------------------------------------------- */ - -static struct CARD { - unsigned id; - int cardnr; - char *name; -} cards[] __devinitdata = { - { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, - { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" }, - { 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" }, - { 0x1200bd11, BTTV_PINNACLERAVE, "Pinnacle PCTV Rave" }, - { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, - { 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" }, - { 0x18501851, BTTV_CHRONOS_VS2, "Chronos Video Shuttle II" }, - { 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" }, - { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, - { 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" }, - { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" }, - { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master" }, - { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" }, - { 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0, -1, NULL } -}; - -struct tvcard -{ - char *name; - int video_inputs; - int audio_inputs; - int tuner; - int svhs; - u32 gpiomask; - u32 muxsel[8]; - u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ - u32 gpiomask2; /* GPIO MUX mask */ - - /* look for these i2c audio chips */ - int msp34xx:1; - int tda8425:1; - int tda9840:1; - int tda985x:1; - int tea63xx:1; - int tea64xx:1; - int tda7432:1; - int tda9875:1; - - /* other settings */ - int pll; - int tuner_type; -}; - -static struct tvcard tvcards[] = -{ - /* 0x00 */ - { " *** UNKNOWN *** ", - 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "MIRO PCTV", - 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Hauppauge old", - 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0,0,0,1, PLL_NONE, -1 }, - { "STB", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, - 0,1,1,1,1,0,0,1, PLL_NONE, -1 }, - - { "Intel", - 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Diamond DTV2000", - 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVerMedia TVPhone", - 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "MATRIX-Vision MV-Delta", - 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x08 */ - { "Fly Video II", - 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, - { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "TurboTV", - 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Hauppauge new (bt878)", - 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,0,1,0,0,0,1, PLL_28, -1 }, - { "MIRO PCTV pro", - 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - { "ADS Technologies Channel Surfer TV", - 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVerMedia TVCapture 98", - 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Aimslab VHX", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Zoltrix TV-Max", - 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x10 */ - { "Pixelview PlayTV (bt878)", - 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, - { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Leadtek WinView 601", - 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, - { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "AVEC Intercapture", - 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "LifeView FlyKit w/o Tuner", - 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, - 0,0,0,0,0,0,0,1, PLL_NONE, -1 }, - - { "CEI Raffles Card", - 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Lucky Star Image World ConferenceTV", - 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I }, - { "Phoebe Tv Master + FM", - 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Modular Technology MM205 PCTV, bt878", - 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x18 */ - { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)", - 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Terratec/Vobis TV-Boostar", - 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Newer Hauppauge WinCam (bt878)", - 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "MAXI TV Video PCI2", - 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, - 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM }, - - { "Terratec TerraTV+", - 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, - { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Imagenation PXC200", - 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "FlyVideo 98", - 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, - { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "iProTV", - 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x20 */ - { "Intel Create and Share PCI", - 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Terratec TerraTValue", - 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1}, - { 0x500, 0, 0x300, 0x900, 0x900},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - { "Leadtek WinFast 2000", - 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, - { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, - 1,1,1,1,1,0,0,1, PLL_28, -1 }, - { "Chronos Video Shuttle II", - 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - - { "Typhoon TView TV/FM Tuner", - 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "PixelView PlayTV pro", - 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, - { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0, - 0,0,0,0,0,0,0,1, PLL_28, -1 }, - { "TView99 CPH063", - 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1}, - { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0, - 1,1,1,1,0,0,0,1, PLL_28, -1 }, - { "Pinnacle PCTV Rave", - 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0, - 1,1,1,1,0,0,0,1, PLL_NONE, -1 }, - - /* 0x28 */ - { "STB2", - 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, - 0,1,1,1,0,1,1,1, PLL_NONE, -1 }, - { "AVerMedia TVPhone 98", - 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, - 1,1,1,1,0,0,0,1, PLL_28, 5 }, - { "ProVideo PV951", /* pic16c54 */ - 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, - 0,0,0,0,0,0,0,0, PLL_28, 1 }, - { "Little OnAir TV", - 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, - {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, - 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, - - { "Sigma TVII-FM", - 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, - 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, -}; -#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) - -static void __devinit dump_eeprom(struct bttv *btv,int addr) -{ - int i; - - if (verbose < 2) - return; - /* for debugging: dump eeprom to syslog */ - printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); - for (i = 0; i < 256;) { - printk(KERN_DEBUG " %02x:",i); - do { - printk(" %02x",eeprom_data[i++]); - } while (i % 16); - printk("\n"); - } -} - -static int __devinit idcard_eeprom(struct bttv *btv) -{ - unsigned id; - int i,n; - - id = (eeprom_data[252] << 24) | - (eeprom_data[253] << 16) | - (eeprom_data[254] << 8) | - (eeprom_data[255]); - if (id == 0 || id == 0xffffffff) - return -1; - - /* look for the card */ - btv->cardid = id; - for (n = -1, i = 0; cards[i].id != 0; i++) - if (cards[i].id == id) - n = i; - - if (n != -1) { - /* found it */ - printk(KERN_INFO "bttv%d: id: %s (0x%08x)\n", - btv->nr,cards[n].name,id); - if (verbose) - printk(KERN_INFO "bttv%d: => card=%d (%s)\n", - btv->nr,cards[n].cardnr, - tvcards[cards[n].cardnr].name); - return cards[n].cardnr; - } else { - /* 404 */ - printk(KERN_INFO "bttv%d: id: unknown (0x%08x)\n", - btv->nr, id); - printk(KERN_INFO "please mail id, board name and " - "the correct card= insmod option to " - "kraxel@goldbach.in-berlin.de\n"); - return -1; - } -} - -/* ----------------------------------------------------------------------- */ - -static void audio(struct bttv *btv, int mode, int no_irq_context) -{ - 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)) - mode=AUDIO_OFF; - if ((mode == AUDIO_TUNER) && (btv->radio)) - mode = AUDIO_RADIO; - btaor(tvcards[btv->type].audiomux[mode], - ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA); - if (no_irq_context) - call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); -} - - -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); -} - - -/* 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; - } - - if (verbose) - 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<100; 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; - if (verbose) - printk("ok\n"); - return 1; - } - mdelay(10); - } - btv->pll.pll_current = 0; - if (verbose) - 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, 1); - btaor(tvcards[btv->type].muxsel[input]>>4, - ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); -} - - -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 */ - { 35468950, - 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 924, 0x20, 255}, - - /* NTSC */ - { 28636363, - 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 910, 128, 910, 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_SOL - -static void make_vbitab(struct bttv *btv) -{ - int i; - unsigned int *po=(unsigned int *) btv->vbi_odd; - unsigned int *pe=(unsigned int *) btv->vbi_even; - - if (debug > 1) - printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", - btv->nr,virt_to_bus(po), virt_to_bus(pe)); - - *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; - for (i=0; i<16; i++) - { - *(po++)=cpu_to_le32(VBI_RISC); - *(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); - } - *(po++)=cpu_to_le32(BT848_RISC_JUMP); - *(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - - *(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0; - for (i=16; i<32; i++) - { - *(pe++)=cpu_to_le32(VBI_RISC); - *(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048)); - } - *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); - *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - - if (debug > 1) - printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", - btv->nr,virt_to_bus(po), virt_to_bus(pe)); -} - -static int fmtbppx2[16] = { - 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 -}; - -static 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++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(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++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); - *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); - vadr+=bpl; - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(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; - - if (debug > 1) - printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - 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>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); - *(ro++)=0; - *(re++)=cpu_to_le32(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) ? &ro : &re; - - - 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))<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)++)=cpu_to_le32(rcmd|bl); - *((*rp)++)=cpu_to_le32(blcb|(blcr<<16)); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bl; - if((rcmd&(15<<28))==BT848_RISC_WRITE123) - { - *((*rp)++)=(kvirt_to_bus(cbadr)); - cbadr+=blcb; - *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); - cradr+=blcr; - } - - rcmd&=~BT848_RISC_SOL; /* only the first has SOL */ - } - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (debug > 1) - printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - return 0; -} - -static int make_vrisctab(struct bttv *btv, unsigned int *ro, - unsigned int *re, - unsigned int *vbuf, unsigned short width, - unsigned short height, unsigned short palette) -{ - unsigned long line; - unsigned long bpl; /* bytes per line */ - unsigned long bl; - unsigned long todo; - unsigned int **rp; - int inter; - unsigned long vadr=(unsigned long) vbuf; - - if (palette==VIDEO_PALETTE_RAW) - return make_rawrisctab(btv, ro, re, vbuf); - if (palette>=VIDEO_PALETTE_PLANAR) - return make_prisctab(btv, ro, re, vbuf, width, height, palette); - - if (debug > 1) - printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; - bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - for (line=0; line < (height<<(1^inter)); line++) - { - if (inter) - rp= (line&1) ? &re : &ro; - else - rp= (line>=height) ? &ro : &re; - - bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); - if (bpl<=bl) - { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bpl; - } - else - { - todo=bpl; - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=bl; - todo-=bl; - while (todo>PAGE_SIZE) - { - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=PAGE_SIZE; - todo-=PAGE_SIZE; - } - *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo); - *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); - vadr+=todo; - } - } - - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (debug > 1) - printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - return 0; -} - -static unsigned char lmaskt[8] = -{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; -static unsigned char rmaskt[8] = -{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; - -static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h) -{ - unsigned char lmask, rmask, *p; - int W, l, r; - int i; - - if (debug > 1) - printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); - - /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ - if (x<0) - { - w+=x; - x=0; - } - if (y<0) - { - h+=y; - y=0; - } - if (w < 0 || h < 0) /* catch bad clips */ - return; - /* out of range data should just fall through */ - if (y+h>=625) - h=625-y; - if (x+w>=1024) - w=1024-x; - - l=x>>3; - r=(x+w-1)>>3; - W=r-l-1; - lmask=lmaskt[x&7]; - rmask=rmaskt[(x+w-1)&7]; - p=clipmap+128*y+l; - - if (W>0) - { - for (i=0; iwin.bpp is allowed here */ - bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; - bpl=btv->win.bpl; - adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; - inter=(btv->win.interlace&1)^1; - width=btv->win.width; - height=btv->win.height; - if (debug > 1) - printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", - btv->nr,btv->picture.palette,width,height,bpl,bpp); - if(width > 1023) - width = 1023; /* sanity check */ - if(height > 625) - height = 625; /* sanity check */ - ro=btv->risc_scr_odd; - re=btv->risc_scr_even; - - if (debug) - printk("bttv%d: clip: ro=%08lx re=%08lx\n", - btv->nr,virt_to_bus(ro), virt_to_bus(re)); - - if ((clipmap=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) { - /* can't clip, don't generate any risc code */ - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - } - if (ncr < 0) { /* bitmap was pased */ - memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); - } else { /* convert rectangular clips to a bitmap */ - memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ - for (i=0; iwin.x * btv->win.bpp) / bpp; - clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, - 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(ro++)=cpu_to_le32(0); - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(re++)=cpu_to_le32(0); - - /* translate bitmap to risc code */ - for (line=outofmem=0; line < (height<>inter; - rp= (line&1) ? &re : &ro; - clipline = clipmap + (y<<7); /* running pointers ... */ - lastbit = *clipline & 1; - for(x=dx=0,sx=0; x<=width && !outofmem;) { - if (0 == (x&7)) { - /* check bytes not bits if we can ... */ - if (lastbit) { - while (0xff==*clipline && xrisc_scr_odd>RISCMEM_LEN/2 - 16) - outofmem++; - if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) - outofmem++; - } - x++; - if (0 == (x&7)) - clipline++; - } - if ((!inter)||(line&1)) - adr+=bpl; - } - - vfree(clipmap); - /* outofmem flag relies on the following code to discard extra data */ - *(ro++)=cpu_to_le32(BT848_RISC_JUMP); - *(ro++)=cpu_to_le32(btv->bus_vbi_even); - *(re++)=cpu_to_le32(BT848_RISC_JUMP); - *(re++)=cpu_to_le32(btv->bus_vbi_odd); - - if (debug > 1) - printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", - btv->nr,btv->picture.palette,width,height,bpl,bpp); -} - -/* - * 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. - */ - -static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn, - int odd, int width, int height) -{ - u16 vscale, hscale; - u32 xsf, sr; - u16 hdelay; - u8 crop, vtc; - int inter = (height>tvn->sheight/2) ? 0 : 1; - int off = odd ? 0x80 : 0x00; - - xsf = (width*tvn->scaledtwidth)/tvn->swidth; - hscale = ((tvn->totalwidth*4096UL)/xsf-4096); - hdelay = tvn->hdelayx1; - hdelay = (hdelay*width)/tvn->swidth; - hdelay &= 0x3fe; - sr=((tvn->sheight>>inter)*512)/height-512; - vscale=(0x10000UL-sr)&0x1fff; - crop=((width>>8)&0x03)|((hdelay>>6)&0x0c)| - ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); - vscale |= inter ? (BT848_VSCALE_INT<<8) : 0; - -#if 0 - /* Some people say interpolation looks bad ... */ - vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); - if (width < 767) - btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - else - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); -#else - vtc = 0; - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); -#endif - - btwrite(vtc, BT848_E_VTC+off); - btwrite(hscale>>8, BT848_E_HSCALE_HI+off); - btwrite(hscale&0xff, BT848_E_HSCALE_LO+off); - btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); - btwrite(vscale&0xff, BT848_E_VSCALE_LO+off); - btwrite(width&0xff, BT848_E_HACTIVE_LO+off); - btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off); - btwrite(tvn->sheight&0xff, BT848_E_VACTIVE_LO+off); - btwrite(tvn->vdelay&0xff, BT848_E_VDELAY_LO+off); - btwrite(crop, BT848_E_CROP+off); -} - - -static void bt848_set_geo(struct bttv *btv, - int no_irq_context) -{ - u16 ewidth, eheight, owidth, oheight; - u16 format, bswap; - struct tvnorm *tvn; - - tvn=&tvnorms[btv->win.norm]; - - btwrite(tvn->adelay, BT848_ADELAY); - btwrite(tvn->bdelay, BT848_BDELAY); - btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); - btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE); - btwrite(1, BT848_VBI_PACK_DEL); - - btv->pll.pll_ofreq = tvn->Fsc; - if (no_irq_context) - set_pll(btv); - - btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; - - if (0 == btv->risc_cap_odd && - 0 == btv->risc_cap_even) { - /* overlay only */ - owidth = btv->win.width; - oheight = btv->win.height; - ewidth = btv->win.width; - eheight = btv->win.height; - format = btv->win.color_fmt; - bswap = btv->fb_color_ctl; - } else if (-1 != btv->gq_grab && - 0 == btv->risc_cap_odd && - !btv->win.interlace && - btv->scr_on) { - /* odd field -> overlay, even field -> capture */ - owidth = btv->win.width; - oheight = btv->win.height; - ewidth = btv->gbuf[btv->gq_grab].width; - eheight = btv->gbuf[btv->gq_grab].height; - format = (btv->win.color_fmt & 0xf0) | - (btv->gbuf[btv->gq_grab].fmt & 0x0f); - bswap = btv->fb_color_ctl & 0x0a; - } else { - /* capture only */ - owidth = btv->gbuf[btv->gq_grab].width; - oheight = btv->gbuf[btv->gq_grab].height; - ewidth = btv->gbuf[btv->gq_grab].width; - eheight = btv->gbuf[btv->gq_grab].height; - format = btv->gbuf[btv->gq_grab].fmt; - bswap = 0; - } - - /* program odd + even fields */ - bt848_set_eogeo(btv, tvn, 1, owidth, oheight); - bt848_set_eogeo(btv, tvn, 0, ewidth, eheight); - - btwrite(format, BT848_COLOR_FMT); - btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); -} - - -static int bpp2fmt[4] = { - BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, - BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 -}; - -static void bt848_set_winsize(struct bttv *btv) -{ - unsigned short format; - - if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { - /* format set by VIDIOCSPICT */ - format = palette2fmt[btv->picture.palette]; - } else { - /* use default for the given color depth */ - format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : - bpp2fmt[(btv->win.bpp-1)&3]; - } - btv->win.color_fmt = format; - if (bigendian && - format == BT848_COLOR_FMT_RGB32) { - btv->fb_color_ctl = - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN; - } else if (bigendian && - (format == BT848_COLOR_FMT_RGB16 || - format == BT848_COLOR_FMT_RGB15)) { - btv->fb_color_ctl = - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN; - } else { - btv->fb_color_ctl = 0; - } - - /* RGB8 seems to be a 9x5x5 GRB color cube starting at - * color 16. Why the h... can't they even mention this in the - * data sheet? [AC - because it's a standard format so I guess - * it never occurred to them] - * Enable dithering in this mode. - */ - - if (format==BT848_COLOR_FMT_RGB8) - btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - else - btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - - bt848_set_geo(btv,1); -} - - -/* - * Grab into virtual memory. - */ - -static int vgrab(struct bttv *btv, struct video_mmap *mp) -{ - unsigned int *ro, *re; - unsigned int *vbuf; - unsigned long flags; - - if(btv->fbuffer==NULL) - { - if(fbuffer_alloc(btv)) - return -ENOBUFS; - } - - if(mp->frame >= gbuffers || mp->frame < 0) - return -EINVAL; - if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) - return -EBUSY; - - if(mp->height < 32 || mp->width < 32) - return -EINVAL; - if (mp->format >= PALETTEFMT_MAX) - return -EINVAL; - - if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 - > gbufsize) - return -EINVAL; - if(-1 == palette2fmt[mp->format]) - return -EINVAL; - - /* - * Ok load up the BT848 - */ - - vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); - ro=btv->gbuf[mp->frame].risc; - re=ro+2048; - make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); - - if (debug) - printk("bttv%d: cap vgrab: queue %d (%d:%dx%d)\n", - btv->nr,mp->frame,mp->format,mp->width,mp->height); - spin_lock_irqsave(&btv->s_lock, flags); - btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; - btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; - btv->gbuf[mp->frame].width = mp->width; - btv->gbuf[mp->frame].height = mp->height; - btv->gbuf[mp->frame].ro = virt_to_bus(ro); - btv->gbuf[mp->frame].re = virt_to_bus(re); - -#if 1 - if (mp->height <= tvnorms[btv->win.norm].sheight/2 && - mp->format != VIDEO_PALETTE_RAW) - btv->gbuf[mp->frame].ro = 0; -#endif - - if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { - btv->gq_start = 1; - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); - } - btv->gqueue[btv->gq_in++] = mp->frame; - btv->gq_in = btv->gq_in % MAX_GBUFFERS; - - btor(3, BT848_CAP_CTL); - btor(3, BT848_GPIO_DMA_CTL); - spin_unlock_irqrestore(&btv->s_lock, flags); - return 0; -} - - -static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock) -{ - struct bttv *btv= (struct bttv *)v; - int q,todo; - DECLARE_WAITQUEUE(wait, current); - - /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ - todo=count; - while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) - { - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) - return -EFAULT; - todo-=q; - buf+=q; - - add_wait_queue(&btv->vbiq, &wait); - current->state = TASK_INTERRUPTIBLE; - if (todo && q==VBIBUF_SIZE-btv->vbip) - { - if(nonblock) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(count==todo) - return -EWOULDBLOCK; - return count-todo; - } - schedule(); - if(signal_pending(current)) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - - if(todo==count) - return -EINTR; - else - return count-todo; - } - } - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - } - if (todo) - { - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) - return -EFAULT; - btv->vbip+=todo; - } - return count; -} - -static inline void burst(int on) -{ - tvnorms[0].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); - tvnorms[0].hdelayx1 = 186 - (on?BURSTOFFSET :0); - tvnorms[2].scaledtwidth = 1135 - (on?BURSTOFFSET-2:0); - tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0); -} - -static void bt848_restart(struct bttv *btv) -{ - unsigned long irq_flags; - - if (verbose) - printk("bttv%d: resetting chip\n",btv->nr); - btwrite(0xfffffUL, BT848_INT_STAT); - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(0, BT848_SRESET); - btwrite(virt_to_bus(btv->risc_jmp+2), - BT848_RISC_STRT_ADD); - - /* enforce pll reprogramming */ - btv->pll.pll_current = 0; - set_pll(btv); - - btv->errors = 0; - btv->needs_restart = 0; - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_geo(btv,0); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); -} - -/* - * Open a bttv card. Right now the flags stuff is just playing - */ - -static int bttv_open(struct video_device *dev, int flags) -{ - struct bttv *btv = (struct bttv *)dev; - int i,ret; - - ret = -EBUSY; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->user) - goto out_unlock; - - btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); - ret = -ENOMEM; - if (!btv->fbuffer) - goto out_unlock; - - btv->gq_in = 0; - btv->gq_out = 0; - btv->gq_grab = -1; - for (i = 0; i < gbuffers; i++) - btv->gbuf[i].stat = GBUFFER_UNUSED; - - if (btv->needs_restart) - bt848_restart(btv); - burst(0); - set_pll(btv); - btv->user++; - up(&btv->lock); - return 0; - - out_unlock: - up(&btv->lock); - MOD_DEC_USE_COUNT; - return ret; -} - -static void bttv_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)dev; - unsigned long irq_flags; - - down(&btv->lock); - btv->user--; - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->scr_on = 0; - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * A word of warning. At this point the chip - * is still capturing because its FIFO hasn't emptied - * and the DMA control operations are posted PCI - * operations. - */ - - btread(BT848_I2C); /* This fixes the PCI posting delay */ - - if (-1 != btv->gq_grab) { - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); /* Wait 1/10th of a second */ - } - - /* - * We have allowed it to drain. - */ - - if(btv->fbuffer) - rvfree((void *) btv->fbuffer, gbuffers*gbufsize); - btv->fbuffer=0; - up(&btv->lock); - MOD_DEC_USE_COUNT; -} - - -/***********************************/ -/* ioctls and supporting functions */ -/***********************************/ - -extern inline void bt848_bright(struct bttv *btv, uint bright) -{ - btwrite(bright&0xff, BT848_BRIGHT); -} - -extern inline void bt848_hue(struct bttv *btv, uint hue) -{ - btwrite(hue&0xff, BT848_HUE); -} - -extern inline void bt848_contrast(struct bttv *btv, uint cont) -{ - unsigned int conthi; - - conthi=(cont>>6)&4; - btwrite(cont&0xff, BT848_CONTRAST_LO); - btaor(conthi, ~4, BT848_E_CONTROL); - btaor(conthi, ~4, BT848_O_CONTROL); -} - -extern inline void bt848_sat_u(struct bttv *btv, unsigned long data) -{ - u32 datahi; - - datahi=(data>>7)&2; - btwrite(data&0xff, BT848_SAT_U_LO); - btaor(datahi, ~2, BT848_E_CONTROL); - btaor(datahi, ~2, BT848_O_CONTROL); -} - -static inline void bt848_sat_v(struct bttv *btv, unsigned long data) -{ - u32 datahi; - - datahi=(data>>8)&1; - btwrite(data&0xff, BT848_SAT_V_LO); - btaor(datahi, ~1, BT848_E_CONTROL); - btaor(datahi, ~1, BT848_O_CONTROL); -} - -/* - * ioctl routine - */ - - -static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)dev; - unsigned long irq_flags; - int i,ret = 0; - - if (debug > 1) - printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name,btv->video_dev.name); - b.type = VID_TYPE_CAPTURE| - ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; - b.channels = tvcards[btv->type].video_inputs; - b.audios = tvcards[btv->type].audio_inputs; - b.maxwidth = tvnorms[btv->win.norm].swidth; - b.maxheight = tvnorms[btv->win.norm].sheight; - b.minwidth = 32; - b.minheight = 32; - if(copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags=VIDEO_VC_AUDIO; - v.tuners=0; - v.type=VIDEO_TYPE_CAMERA; - v.norm = btv->win.norm; - if (v.channel>=tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.channel==tvcards[btv->type].tuner) - { - strcpy(v.name,"Television"); - v.flags|=VIDEO_VC_TUNER; - v.type=VIDEO_TYPE_TV; - v.tuners=1; - } - else if(v.channel==tvcards[btv->type].svhs) - strcpy(v.name,"S-Video"); - else - sprintf(v.name,"Composite%d",v.channel); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* - * Each channel has 1 tuner - */ - case VIDIOCSCHAN: - { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - - if (v.channel>tvcards[btv->type].video_inputs) - return -EINVAL; - if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) - return -EOPNOTSUPP; - - call_i2c_clients(btv,cmd,&v); - down(&btv->lock); - bt848_muxsel(btv, v.channel); - btv->channel=v.channel; - if (btv->win.norm != v.norm) { - btv->win.norm = v.norm; - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - } - up(&btv->lock); - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Television"); - v.rangelow=0; - v.rangehigh=0xFFFFFFFF; - v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v.mode = btv->win.norm; - v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - call_i2c_clients(btv,cmd,&v); - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* We have but one tuner */ - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* Only one channel has a tuner */ - if(v.tuner!=tvcards[btv->type].tuner) - return -EINVAL; - - if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC - &&v.mode!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - call_i2c_clients(btv,cmd,&v); - if (btv->win.norm != v.mode) { - btv->win.norm = v.mode; - down(&btv->lock); - set_pll(btv); - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - } - return 0; - } - case VIDIOCGPICT: - { - struct video_picture p=btv->picture; - if(copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture p; - if(copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - if (p.palette > PALETTEFMT_MAX) - return -EINVAL; - down(&btv->lock); - /* We want -128 to 127 we get 0-65535 */ - bt848_bright(btv, (p.brightness>>8)-128); - /* 0-511 for the colour */ - bt848_sat_u(btv, p.colour>>7); - bt848_sat_v(btv, ((p.colour>>7)*201L)/237); - /* -128 to 127 */ - bt848_hue(btv, (p.hue>>8)-128); - /* 0-511 */ - bt848_contrast(btv, p.contrast>>7); - btv->picture = p; - up(&btv->lock); - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp = NULL; - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - down(&btv->lock); - if(vw.flags || vw.width < 16 || vw.height < 16) - { - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->scr_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - return -EINVAL; - } - if (btv->win.bpp < 4) - { /* adjust and align writes */ - vw.x = (vw.x + 3) & ~3; - vw.width &= ~3; - } - if (btv->needs_restart) - bt848_restart(btv); - btv->win.x=vw.x; - btv->win.y=vw.y; - btv->win.width=vw.width; - btv->win.height=vw.height; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,0); - bt848_set_winsize(btv); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * Do any clips. - */ - if(vw.clipcount<0) { - if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) - return -ENOMEM; - if(copy_from_user(vcp, vw.clips, - VIDEO_CLIPMAP_SIZE)) { - vfree(vcp); - return -EFAULT; - } - } else if (vw.clipcount) { - if((vcp=vmalloc(sizeof(struct video_clip)* - (vw.clipcount))) == NULL) - return -ENOMEM; - if(copy_from_user(vcp,vw.clips, - sizeof(struct video_clip)* - vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - } - make_clip_tab(btv, vcp, vw.clipcount); - if (vw.clipcount != 0) - vfree(vcp); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - /* Oh for a COBOL move corresponding .. */ - vw.x=btv->win.x; - vw.y=btv->win.y; - vw.width=btv->win.width; - vw.height=btv->win.height; - vw.chromakey=0; - vw.flags=0; - if(btv->win.interlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - if(copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - return 0; - } - case VIDIOCCAPTURE: - { - int v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(btv->win.vidadr == 0) - return -EINVAL; - if (btv->win.width==0 || btv->win.height==0) - return -EINVAL; - spin_lock_irqsave(&btv->s_lock, irq_flags); - if (v == 1 && btv->win.vidadr != 0) - btv->scr_on = 1; - if (v == 0) - btv->scr_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - v.base=(void *)btv->win.vidadr; - v.height=btv->win.sheight; - v.width=btv->win.swidth; - v.depth=btv->win.depth; - v.bytesperline=btv->win.bpl; - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - return 0; - - } - case VIDIOCSFBUF: - { - struct video_buffer v; - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(v.depth!=8 && v.depth!=15 && v.depth!=16 && - v.depth!=24 && v.depth!=32 && v.width > 16 && - v.height > 16 && v.bytesperline > 16) - return -EINVAL; - down(&btv->lock); - if (v.base) - btv->win.vidadr=(unsigned long)v.base; - btv->win.sheight=v.height; - btv->win.swidth=v.width; - btv->win.bpp=((v.depth+7)&0x38)/8; - btv->win.depth=v.depth; - btv->win.bpl=v.bytesperline; - - /* set sefault color format */ - switch (btv->win.bpp) { - case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; - case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; - case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; - case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; - case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; - } - - if (debug) - printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", - v.base, v.width,v.height, btv->win.bpp, btv->win.bpl); - bt848_set_winsize(btv); - up(&btv->lock); - return 0; - } - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - return 0; - } - case VIDIOCGFREQ: - { - unsigned long v=btv->win.freq; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSFREQ: - { - unsigned long v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - btv->win.freq=v; - call_i2c_clients(btv,cmd,&v); - return 0; - } - - case VIDIOCGAUDIO: - { - struct video_audio v; - - v=btv->audio_dev; - v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); - v.flags|=VIDEO_AUDIO_MUTABLE; - strcpy(v.name,"TV"); - - v.mode = VIDEO_SOUND_MONO; - call_i2c_clients(btv,cmd,&v); - - if (btv->type == BTTV_TERRATV) { - v.mode = VIDEO_SOUND_MONO; - v.mode |= VIDEO_SOUND_STEREO; - v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; - - } else if (btv->audio_chip == TDA9840) { - /* begin of Horrible Hack */ - v.flags|=VIDEO_AUDIO_VOLUME; - v.mode = VIDEO_SOUND_MONO; - v.mode |= VIDEO_SOUND_STEREO; - v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; - v.volume = 32768; /* fixme */ - v.step = 4096; - } - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio v; - - if(copy_from_user(&v,arg, sizeof(v))) - return -EFAULT; - down(&btv->lock); - if(v.flags&VIDEO_AUDIO_MUTE) - audio(btv, AUDIO_MUTE, 1); - /* One audio source per tuner -- huh? */ - if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) { - up(&btv->lock); - return -EINVAL; - } - /* bt848_muxsel(btv,v.audio); */ - if(!(v.flags&VIDEO_AUDIO_MUTE)) - audio(btv, AUDIO_UNMUTE, 1); - - call_i2c_clients(btv,cmd,&v); - - if (btv->type == BTTV_TERRATV) { - unsigned int con = 0; - btor(0x180000, BT848_GPIO_OUT_EN); - if (v.mode & VIDEO_SOUND_LANG2) - con = 0x080000; - if (v.mode & VIDEO_SOUND_STEREO) - con = 0x180000; - btaor(con, ~0x180000, BT848_GPIO_DATA); - - } else if (btv->type == BTTV_WINVIEW_601) { - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((v.volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; - data = btread(BT848_GPIO_DATA); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<audio_dev=v; - up(&btv->lock); - return 0; - } - - case VIDIOCSYNC: - { - DECLARE_WAITQUEUE(wait, current); - - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - if (i < 0 || i >= gbuffers) - return -EINVAL; - switch (btv->gbuf[i].stat) { - case GBUFFER_UNUSED: - ret = -EINVAL; - break; - case GBUFFER_GRABBING: - add_wait_queue(&btv->capq, &wait); - current->state = TASK_INTERRUPTIBLE; - while(btv->gbuf[i].stat==GBUFFER_GRABBING) { - if (debug) - printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); - schedule(); - if(signal_pending(current)) { - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - return -EINTR; - } - } - remove_wait_queue(&btv->capq, &wait); - current->state = TASK_RUNNING; - /* fall throuth */ - case GBUFFER_DONE: - case GBUFFER_ERROR: - ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; - if (debug) - printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); - btv->gbuf[i].stat = GBUFFER_UNUSED; - } - if (btv->needs_restart) { - down(&btv->lock); - bt848_restart(btv); - up(&btv->lock); - } - return ret; - } - - case BTTV_FIELDNR: - if(copy_to_user((void *) arg, (void *) &btv->last_field, - sizeof(btv->last_field))) - return -EFAULT; - break; - - case BTTV_PLLSET: { - struct bttv_pll_info p; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) - return -EFAULT; - down(&btv->lock); - btv->pll.pll_ifreq = p.pll_ifreq; - btv->pll.pll_ofreq = p.pll_ofreq; - btv->pll.pll_crystal = p.pll_crystal; - up(&btv->lock); - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - int ret; - if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) - return -EFAULT; - down(&btv->lock); - ret = vgrab(btv, &vm); - up(&btv->lock); - return ret; - } - - case VIDIOCGMBUF: - { - struct video_mbuf vm; - memset(&vm, 0 , sizeof(vm)); - vm.size=gbufsize*gbuffers; - vm.frames=gbuffers; - for (i = 0; i < gbuffers; i++) - vm.offsets[i]=i*gbufsize; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - return 0; - } - - case VIDIOCGUNIT: - { - struct video_unit vu; - vu.video=btv->video_dev.minor; - vu.vbi=btv->vbi_dev.minor; - if(btv->radio_dev.minor!=-1) - vu.radio=btv->radio_dev.minor; - else - vu.radio=VIDEO_NO_UNIT; - vu.audio=VIDEO_NO_UNIT; - vu.teletext=VIDEO_NO_UNIT; - if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) - return -EFAULT; - return 0; - } - - case BTTV_BURST_ON: - { - burst(1); - return 0; - } - - case BTTV_BURST_OFF: - { - burst(0); - return 0; - } - - case BTTV_VERSION: - { - return BTTV_VERSION_CODE; - } - - case BTTV_PICNR: - { - /* return picture;*/ - return 0; - } - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int bttv_init_done(struct video_device *dev) -{ - return 0; -} - -/* - * This maps the vmalloced and reserved fbuffer to user space. - * - * FIXME: - * - PAGE_READONLY should suffice!? - * - remap_page_range is kind of inefficient for page by page remapping. - * But e.g. pte_alloc() does not work in modules ... :-( - */ - -static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) -{ - unsigned long start=(unsigned long) adr; - unsigned long page,pos; - - if (size>gbuffers*gbufsize) - return -EINVAL; - if (!btv->fbuffer) { - if(fbuffer_alloc(btv)) - return -EINVAL; - } - pos=(unsigned long) btv->fbuffer; - while (size > 0) { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; - } - return 0; -} - -static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) -{ - struct bttv *btv=(struct bttv *)dev; - int r; - - down(&btv->lock); - r=do_bttv_mmap(btv, adr, size); - up(&btv->lock); - return r; -} - - -static struct video_device bttv_template= -{ - "UNSET", - VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, - VID_HARDWARE_BT848, - bttv_open, - bttv_close, - bttv_read, - bttv_write, - NULL, - bttv_ioctl, - bttv_mmap, - bttv_init_done, - NULL, - 0, - -1 -}; - - -static long vbi_read(struct video_device *v, char *buf, unsigned long count, - int nonblock) -{ - struct bttv *btv=(struct bttv *)(v-2); - int q,todo; - DECLARE_WAITQUEUE(wait, current); - - todo=count; - while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) - { - if (btv->needs_restart) { - down(&btv->lock); - bt848_restart(btv); - up(&btv->lock); - } - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) - return -EFAULT; - todo-=q; - buf+=q; - - add_wait_queue(&btv->vbiq, &wait); - current->state = TASK_INTERRUPTIBLE; - if (todo && q==VBIBUF_SIZE-btv->vbip) - { - if(nonblock) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(count==todo) - return -EWOULDBLOCK; - return count-todo; - } - schedule(); - if(signal_pending(current)) - { - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - if(todo==count) - return -EINTR; - else - return count-todo; - } - } - remove_wait_queue(&btv->vbiq, &wait); - current->state = TASK_RUNNING; - } - if (todo) - { - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) - return -EFAULT; - btv->vbip+=todo; - } - return count; -} - -static unsigned int vbi_poll(struct video_device *dev, struct file *file, - poll_table *wait) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned int mask = 0; - - poll_wait(file, &btv->vbiq, wait); - - if (btv->vbip < VBIBUF_SIZE) - mask |= (POLLIN | POLLRDNORM); - - return mask; -} - -static int vbi_open(struct video_device *dev, int flags) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned long irq_flags; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->needs_restart) - bt848_restart(btv); - set_pll(btv); - btv->vbip=VBIBUF_SIZE; - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->vbi_on = 1; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - up(&btv->lock); - - return 0; -} - -static void vbi_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)(dev-2); - unsigned long irq_flags; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->vbi_on = 0; - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - MOD_DEC_USE_COUNT; -} - -static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability b; - strcpy(b.name,btv->vbi_dev.name); - b.type = ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | - VID_TYPE_TELETEXT; - b.channels = 0; - b.audios = 0; - b.maxwidth = 0; - b.maxheight = 0; - b.minwidth = 0; - b.minheight = 0; - if(copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - return bttv_ioctl((struct video_device *)btv,cmd,arg); - case BTTV_VBISIZE: - /* make alevt happy :-) */ - return VBIBUF_SIZE; - default: - return -EINVAL; - } -} - -static struct video_device vbi_template= -{ - "bttv vbi", - VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, - VID_HARDWARE_BT848, - vbi_open, - vbi_close, - vbi_read, - bttv_write, - vbi_poll, - vbi_ioctl, - NULL, /* no mmap yet */ - bttv_init_done, - NULL, - 0, - -1 -}; - - -static int radio_open(struct video_device *dev, int flags) -{ - struct bttv *btv = (struct bttv *)(dev-1); - unsigned long v; - - MOD_INC_USE_COUNT; - down(&btv->lock); - if (btv->user) - goto busy_unlock; - btv->user++; - - btv->radio = 1; - v = 400*16; - call_i2c_clients(btv,VIDIOCSFREQ,&v); - call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); - bt848_muxsel(btv,0); - up(&btv->lock); - - return 0; - - busy_unlock: - up(&btv->lock); - MOD_DEC_USE_COUNT; - return -EBUSY; -} - -static void radio_close(struct video_device *dev) -{ - struct bttv *btv=(struct bttv *)(dev-1); - - down(&btv->lock); - btv->user--; - btv->radio = 0; - up(&btv->lock); - MOD_DEC_USE_COUNT; -} - -static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) -{ - return -EINVAL; -} - -static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct bttv *btv=(struct bttv *)(dev-1); - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability v; - strcpy(v.name,btv->video_dev.name); - v.type = VID_TYPE_TUNER; - v.channels = 1; - v.audios = 1; - /* No we don't do pictures */ - v.maxwidth = 0; - v.maxheight = 0; - v.minwidth = 0; - v.minheight = 0; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - break; - } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Radio"); - v.rangelow=(int)(76*16); /* jp: 76.0MHz - 89.9MHz */ - v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */ - v.flags= 0; /* XXX */ - v.mode = 0; /* XXX */ - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* Only channel 0 has a tuner */ - if(v.tuner!=0 || btv->channel) - return -EINVAL; - /* XXX anything to do ??? */ - return 0; - } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - bttv_ioctl((struct video_device *)btv,cmd,arg); - break; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static struct video_device radio_template= -{ - "bttv radio", - VID_TYPE_TUNER, - VID_HARDWARE_BT848, - radio_open, - radio_close, - radio_read, /* just returns -EINVAL */ - bttv_write, /* just returns -EINVAL */ - NULL, /* no poll */ - radio_ioctl, - NULL, /* no mmap */ - bttv_init_done, /* just returns 0 */ - NULL, - 0, - -1 -}; - - -#define TRITON_PCON 0x50 -#define TRITON_BUS_CONCURRENCY (1<<0) -#define TRITON_STREAMING (1<<1) -#define TRITON_WRITE_BURST (1<<2) -#define TRITON_PEER_CONCURRENCY (1<<3) - - -static void __devinit handle_chipset(void) -{ - struct pci_dev *dev = NULL; - - /* Just in case some nut set this to something dangerous */ - if (triton1) - triton1=BT848_INT_ETBF; - - while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) - { - /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ - printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82441, dev))) - { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) - { - printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); - triton1=BT848_INT_ETBF; - } -} - - -/* can tda9855.c handle this too maybe? */ -static void __devinit init_tda9840(struct bttv *btv) -{ - /* Horrible Hack */ - I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ - /* 00 - mute - 10 - mono / averaged stereo - 2a - stereo - 12 - dual A - 1a - dual AB - 16 - dual BA - 1e - dual B - 7a - external */ -} - -/* Figure out card and tuner type */ - -static void __devinit idcard(struct bttv *btv) -{ - int type,eeprom = 0; - - btwrite(0, BT848_GPIO_OUT_EN); - - /* Default the card to the user-selected one. */ - if (card[btv->nr] >= 0 && card[btv->nr] < TVCARDS) - btv->type=card[btv->nr]; - - /* If we were asked to auto-detect, then do so! */ - if (btv->type == BTTV_UNKNOWN) { - - /* many bt878 cards have a eeprom @ 0xa0 => read ID - and try to identify it */ - if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { - eeprom = 0xa0; - readee(btv,eeprom_data,0xa0); - dump_eeprom(btv,0xa0); /* DEBUG */ - type = idcard_eeprom(btv); - if (-1 != type) { - btv->type = type; - } else if (btv->id <= 849) { - /* for unknown bt848, assume old Hauppauge */ - btv->type=BTTV_HAUPPAUGE; - } - - /* STB cards have a eeprom @ 0xae (old bt848) */ - } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { - btv->type=BTTV_STB; - } - -#if 0 - /* check for msp34xx */ - if (I2CRead(btv, 0x80, "msp3400")>=0) - btv->type = BTTV_MIROPRO; - else - btv->type = BTTV_MIRO; -#endif - } - - /* print which board we have found */ - sprintf(btv->video_dev.name,"BT%d%s(%.22s)", - btv->id, - (btv->id==848 && btv->revision==0x12) ? "A" : "", - tvcards[btv->type].name); - printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name); - - /* board specific initialisations */ - if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { - /* auto detect tuner for MIRO cards */ - btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; - } - if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { - /* pick up some config infos from the eeprom */ - if (0xa0 != eeprom) { - eeprom = 0xa0; - readee(btv,eeprom_data,0xa0); - } - hauppauge_eeprom(btv); - hauppauge_boot_msp34xx(btv); - } - if (btv->type == BTTV_PXC200) - init_PXC200(btv); - - - /* pll configuration */ - if (!(btv->id==848 && btv->revision==0x11)) { - /* defaults from card list */ - if (PLL_28 == tvcards[btv->type].pll) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - /* insmod options can override */ - switch (pll[btv->nr]) { - case 0: /* none */ - btv->pll.pll_crystal = 0; - btv->pll.pll_ifreq = 0; - btv->pll.pll_ofreq = 0; - break; - case 1: /* 28 MHz */ - btv->pll.pll_ifreq = 28636363; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal=BT848_IFORM_XT0; - break; - case 2: /* 35 MHz */ - btv->pll.pll_ifreq = 35468950; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal=BT848_IFORM_XT1; - break; - } - } - - - /* tuner configuration */ - if (-1 != tvcards[btv->type].tuner_type) - btv->tuner_type = tvcards[btv->type].tuner_type; - if (btv->tuner_type != -1) - call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - - /* try to detect audio/fader chips */ - if (tvcards[btv->type].msp34xx && - I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { - if (autoload) - request_module("msp3400"); - } - - if (tvcards[btv->type].tda8425 && - I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { - if (autoload) - request_module("tda8425"); - } - - if (tvcards[btv->type].tda9840 && - I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { - init_tda9840(btv); - btv->audio_chip = TDA9840; - /* move this to a module too? */ - init_tda9840(btv); - } - - if (tvcards[btv->type].tda985x && - I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { - if (autoload) - request_module("tda985x"); - } - - if (tvcards[btv->type].tda9875 && - I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { - if (autoload) - request_module("tda9875"); - } - - if (tvcards[btv->type].tda7432 && - I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { - if (autoload) - request_module("tda7432"); - } - - if (tvcards[btv->type].tea63xx) { - if (autoload) - request_module("tea6300"); - } - - if (tvcards[btv->type].tea64xx) { - if (autoload) - request_module("tea6420"); - } - - if (tvcards[btv->type].tuner != -1) { - if (autoload) - request_module("tuner"); - } - - audio(btv, AUDIO_MUTE, 1); -} - - -static void bt848_set_risc_jmps(struct bttv *btv, int flags) -{ - if (-1 == flags) { - /* defaults */ - flags = 0; - if (btv->scr_on) - flags |= 0x03; - if (btv->vbi_on) - flags |= 0x0c; - } - - if (debug > 1) - printk("bttv%d: set_risc_jmp %08lx:", - btv->nr,virt_to_bus(btv->risc_jmp)); - - /* Sync to start of odd field */ - btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC - |BT848_FIFO_STATUS_VRE); - btv->risc_jmp[1]=cpu_to_le32(0); - - /* Jump to odd vbi sub */ - btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); - if (flags&8) { - if (debug > 1) - printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); - btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); - } else { - if (debug > 1) - printk(" -----------"); - btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); - } - - /* Jump to odd sub */ - btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); - if (0 != btv->risc_cap_odd) { - if (debug > 1) - printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); - flags |= 3; - btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); - } else if (flags&2) { - if (debug > 1) - printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); - } else { - if (debug > 1) - printk(" -----------"); - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); - } - - - /* Sync to start of even field */ - btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC - |BT848_FIFO_STATUS_VRO); - btv->risc_jmp[7]=cpu_to_le32(0); - - /* Jump to even vbi sub */ - btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); - if (flags&4) { - if (debug > 1) - printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); - btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); - } else { - if (debug > 1) - printk(" -----------"); - btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - } - - /* Jump to even sub */ - btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); - if (0 != btv->risc_cap_even) { - if (debug > 1) - printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); - flags |= 3; - btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); - } else if (flags&1) { - if (debug > 1) - printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); - } else { - if (debug > 1) - printk(" -----------"); - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); - } - - if (btv->gq_start) { - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); - } else { - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); - } - btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); - - /* enable cpaturing and DMA */ - if (debug > 1) - printk(" flags=0x%x dma=%s\n", - flags,(flags&0x0f) ? "on" : "off"); - btaor(flags, ~0x0f, BT848_CAP_CTL); - if (flags&0x0f) - bt848_dma(btv, 3); - else - bt848_dma(btv, 0); -} - -static int __devinit init_video_dev(struct bttv *btv) -{ - memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); - memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); - memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); - - idcard(btv); - - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) - return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) - { - video_unregister_device(&btv->video_dev); - return -1; - } - if (radio[btv->nr]) - { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) - { - video_unregister_device(&btv->vbi_dev); - video_unregister_device(&btv->video_dev); - return -1; - } - } - return 1; -} - -static int __devinit init_bt848(struct bttv *btv) -{ - int j; - unsigned long irq_flags; - - btv->user=0; - init_MUTEX(&btv->lock); - - /* dump current state of the gpio registers before changing them, - * might help to make a new card work */ - if (verbose >= 2) - printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", - btv->nr, - btread(BT848_GPIO_OUT_EN), - btread(BT848_GPIO_DATA), - btread(BT848_GPIO_REG_INP)); - - /* reset the bt848 */ - btwrite(0, BT848_SRESET); - DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n", btv->nr, (unsigned long) btv->bt848_mem)); - - /* not registered yet */ - btv->video_dev.minor = -1; - btv->radio_dev.minor = -1; - btv->vbi_dev.minor = -1; - - /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ - btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ - btv->win.interlace=1; - btv->win.x=0; - btv->win.y=0; - btv->win.width=768; /* 640 */ - btv->win.height=576; /* 480 */ - btv->win.bpp=2; - btv->win.depth=16; - btv->win.color_fmt=BT848_COLOR_FMT_RGB16; - btv->win.bpl=1024*btv->win.bpp; - btv->win.swidth=1024; - btv->win.sheight=768; - btv->win.vidadr=0; - btv->vbi_on=0; - btv->scr_on=0; - - btv->risc_scr_odd=0; - btv->risc_scr_even=0; - btv->risc_cap_odd=0; - btv->risc_cap_even=0; - btv->risc_jmp=0; - btv->vbibuf=0; - btv->field=btv->last_field=0; - - btv->errors=0; - btv->needs_restart=0; - - /* i2c */ - btv->tuner_type=-1; - init_bttv_i2c(btv); - - if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) - return -1; - if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) - return -1; - if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) - return -1; - btv->vbi_odd=btv->risc_jmp+16; - btv->vbi_even=btv->vbi_odd+256; - btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); - btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); - - btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); - btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE); - if (!btv->vbibuf) - return -1; - if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) - return -1; - for (j = 0; j < gbuffers; j++) { - if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) - return -1; - } - - memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random - memory to the user */ - - btv->fbuffer=NULL; - - bt848_muxsel(btv, 1); - bt848_set_winsize(btv); - -/* btwrite(0, BT848_TDEC); */ - btwrite(0x10, BT848_COLOR_CTL); - btwrite(0x00, BT848_CAP_CTL); - /* 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); - - /* select direct input */ - btwrite(0x00, BT848_GPIO_REG_INP); - - btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, - BT848_IFORM); - - btwrite(0xd8, BT848_CONTRAST_LO); - bt848_bright(btv, 0x10); - - btwrite(0x20, BT848_E_VSCALE_HI); - btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(/*BT848_ADC_SYNC_T|*/ - BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); - - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); - - btv->picture.colour=254<<7; - btv->picture.brightness=128<<8; - btv->picture.hue=128<<8; - btv->picture.contrast=0xd8<<7; - - btwrite(0x00, BT848_E_SCLOOP); - btwrite(0x00, BT848_O_SCLOOP); - - /* clear interrupt status */ - btwrite(0xfffffUL, BT848_INT_STAT); - - /* set interrupt mask */ - btwrite(btv->triton1| - /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| - BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ - (fieldnr ? BT848_INT_VSYNC : 0)| - BT848_INT_GPINT| - BT848_INT_SCERR| - BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| - BT848_INT_FMTCHG|BT848_INT_HLOCK, - BT848_INT_MASK); - - make_vbitab(btv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - /* - * Now add the template and register the device unit. - */ - init_video_dev(btv); - - return 0; -} - -static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) -{ - u32 stat,astat; - u32 dstat; - int count,i; - struct bttv *btv; - unsigned long irq_flags; - - btv=(struct bttv *)dev_id; - count=0; - while (1) - { - /* get/clear interrupt status bits */ - stat=btread(BT848_INT_STAT); - astat=stat&btread(BT848_INT_MASK); - if (!astat) - return; - btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); - - /* get device status bits */ - dstat=btread(BT848_DSTATUS); - - if (astat&BT848_INT_GPINT) { - IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); - wake_up_interruptible(&btv->gpioq); - } - - if (astat&BT848_INT_FMTCHG) - { - IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); - /*btv->win.norm&= - (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ - } - if (astat&BT848_INT_VPRES) - { - IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr)); - } - if (astat&BT848_INT_VSYNC) - { - IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); - btv->field++; - } - if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { - if (verbose) - printk("bttv%d: irq:%s%s risc_count=%08x\n", - btv->nr, - (astat&BT848_INT_SCERR) ? " SCERR" : "", - (astat&BT848_INT_OCERR) ? " OCERR" : "", - btread(BT848_RISC_COUNT)); - btv->errors++; - if (btv->errors < BTTV_ERRORS) { - spin_lock_irqsave(&btv->s_lock, irq_flags); - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(virt_to_bus(btv->risc_jmp+2), - BT848_RISC_STRT_ADD); - bt848_set_geo(btv,0); - bt848_set_risc_jmps(btv,-1); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - } else { - if (verbose) - printk("bttv%d: aiee: error loops\n",btv->nr); - /* cancel all outstanding grab requests */ - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->gq_in = 0; - btv->gq_out = 0; - btv->gq_grab = -1; - for (i = 0; i < gbuffers; i++) - if (btv->gbuf[i].stat == GBUFFER_GRABBING) - btv->gbuf[i].stat = GBUFFER_ERROR; - /* disable DMA */ - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,0); - btv->needs_restart = 1; - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - - wake_up_interruptible(&btv->vbiq); - wake_up_interruptible(&btv->capq); - } - } - if (astat&BT848_INT_RISCI) - { - if (debug > 1) - printk("bttv%d: IRQ_RISCI\n",btv->nr); - - /* captured VBI frame */ - if (stat&(1<<28)) - { - btv->vbip=0; - /* inc vbi frame count for detecting drops */ - (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++; - wake_up_interruptible(&btv->vbiq); - } - - /* captured full frame */ - if (stat&(2<<28) && btv->gq_grab != -1) - { - btv->last_field=btv->field; - if (debug) - printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); - do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; - btv->gq_grab = -1; - if (btv->gq_in != btv->gq_out) - { - btv->gq_grab = btv->gqueue[btv->gq_out++]; - btv->gq_out = btv->gq_out % MAX_GBUFFERS; - if (debug) - printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); - btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; - btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - } else { - btv->risc_cap_odd = 0; - btv->risc_cap_even = 0; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - } - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - wake_up_interruptible(&btv->capq); - break; - } - if (stat&(8<<28)) - { - spin_lock_irqsave(&btv->s_lock, irq_flags); - btv->gq_start = 0; - btv->gq_grab = btv->gqueue[btv->gq_out++]; - btv->gq_out = btv->gq_out % MAX_GBUFFERS; - if (debug) - printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); - btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; - btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; - bt848_set_risc_jmps(btv,-1); - bt848_set_geo(btv,0); - btwrite(BT848_COLOR_CTL_GAMMA, - BT848_COLOR_CTL); - spin_unlock_irqrestore(&btv->s_lock, irq_flags); - } - } - if (astat&BT848_INT_OCERR) - { - IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr)); - } - if (astat&BT848_INT_PABORT) - { - IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr)); - } - if (astat&BT848_INT_RIPERR) - { - IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr)); - } - if (astat&BT848_INT_PPERR) - { - IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr)); - } - if (astat&BT848_INT_FDSR) - { - IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr)); - } - if (astat&BT848_INT_FTRGT) - { - IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr)); - } - if (astat&BT848_INT_FBUS) - { - IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr)); - } - if (astat&BT848_INT_HLOCK) - { - if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) - audio(btv, AUDIO_ON,0); - else - audio(btv, AUDIO_OFF,0); - } - - if (astat&BT848_INT_I2CDONE) - { - IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); - } - count++; - if (count > 10) - printk (KERN_WARNING "bttv%d: irq loop %d\n", - btv->nr,count); - if (count > 20) - { - btwrite(0, BT848_INT_MASK); - printk(KERN_ERR - "bttv%d: IRQ lockup, cleared int mask\n", btv->nr); - } - } -} - - - -/* - * Scan for a Bt848 card, request the irq and map the io memory - */ - -static void __devinit bttv_remove(struct pci_dev *pci_dev) -{ - u8 command; - int j; - struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); - - /* unregister i2c_bus */ - i2c_bit_del_bus(&btv->i2c_adap); - - /* turn off all capturing, DMA and IRQs */ - btand(~15, BT848_GPIO_DMA_CTL); - - /* first disable interrupts before unmapping the memory! */ - btwrite(0, BT848_INT_MASK); - btwrite(~0x0UL,BT848_INT_STAT); - btwrite(0x0, BT848_GPIO_OUT_EN); - - /* disable PCI bus-mastering */ - pci_read_config_byte(btv->dev, PCI_COMMAND, &command); - /* Should this be &=~ ?? */ - command&=~PCI_COMMAND_MASTER; - pci_write_config_byte(btv->dev, PCI_COMMAND, command); - - /* unmap and free memory */ - for (j = 0; j < gbuffers; j++) - if (btv->gbuf[j].risc) - kfree(btv->gbuf[j].risc); - if (btv->gbuf) - kfree((void *) btv->gbuf); - - if (btv->risc_scr_odd) - kfree((void *) btv->risc_scr_odd); - - if (btv->risc_scr_even) - kfree((void *) btv->risc_scr_even); - - DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); - if (btv->risc_jmp) - kfree((void *) btv->risc_jmp); - - DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%p.\n", btv->vbibuf)); - if (btv->vbibuf) - vfree((void *) btv->vbibuf); - - free_irq(btv->irq,btv); - DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%p.\n", btv->bt848_mem)); - if (btv->bt848_mem) - iounmap(btv->bt848_mem); - - if(btv->video_dev.minor!=-1) - video_unregister_device(&btv->video_dev); - if(btv->vbi_dev.minor!=-1) - video_unregister_device(&btv->vbi_dev); - if (radio[btv->nr] && btv->radio_dev.minor != -1) - video_unregister_device(&btv->radio_dev); - - release_mem_region(btv->bt848_adr, - pci_resource_len(btv->dev,0)); - /* wake up any waiting processes - because shutdown flag is set, no new processes (in this queue) - are expected - */ - btv->shutdown=1; - wake_up(&btv->gpioq); - - return; -} - - -static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) -{ - int result; - unsigned char command; - struct bttv *btv; -#if defined(__powerpc__) - unsigned int cmd; -#endif - - printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num); - - btv=&bttvs[bttv_num]; - btv->dev=dev; - btv->nr = bttv_num; - btv->bt848_mem=NULL; - btv->vbibuf=NULL; - btv->risc_jmp=NULL; - btv->vbi_odd=NULL; - btv->vbi_even=NULL; - init_waitqueue_head(&btv->vbiq); - init_waitqueue_head(&btv->capq); - btv->vbip=VBIBUF_SIZE; - btv->s_lock = SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&btv->gpioq); - btv->shutdown=0; - - btv->id=dev->device; - btv->irq=dev->irq; - btv->bt848_adr=pci_resource_start(dev,0); - if (pci_enable_device(dev)) - return -EIO; - if (!request_mem_region(pci_resource_start(dev,0), - pci_resource_len(dev,0), - "bttv")) { - return -EBUSY; - } - if (btv->id >= 878) - btv->i2c_command = 0x83; - else - btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); - printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", - bttv_num,btv->id, btv->revision); - printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn); - printk("irq: %d, ",btv->irq); - printk("memory: 0x%lx.\n", btv->bt848_adr); - -#if defined(__powerpc__) - /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ - /* response on cards with no firmware is not enabled by OF */ - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY ); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif - -#ifdef __sparc__ - btv->bt848_mem=(unsigned char *)btv->bt848_adr; -#else - btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); -#endif - - /* clear interrupt mask */ - btwrite(0, BT848_INT_MASK); - - result = request_irq(btv->irq, bttv_irq, - SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); - if (result==-EINVAL) - { - printk(KERN_ERR "bttv%d: Bad irq number or handler\n", - bttv_num); - goto fail; - } - if (result==-EBUSY) - { - printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq); - goto fail; - } - if (result < 0) - goto fail; - - pci_set_master(dev); - - btv->triton1=triton1 ? BT848_INT_ETBF : 0; - if (triton1 && btv->id >= 878) - { - btv->triton1 = 0; - printk("bttv: Enabling 430FX compatibilty for bt878\n"); - pci_read_config_byte(dev, BT878_DEVCTRL, &command); - command|=BT878_EN_TBFX; - pci_write_config_byte(dev, BT878_DEVCTRL, command); - pci_read_config_byte(dev, BT878_DEVCTRL, &command); - if (!(command&BT878_EN_TBFX)) - { - printk("bttv: 430FX compatibility could not be enabled\n"); - free_irq(btv->irq,btv); - result = -1; - goto fail; - } - } - - PCI_SET_DRIVER_DATA(dev,btv); - - if(init_bt848(btv) < 0) { - bttv_remove(dev); - return -EIO; - } - bttv_num++; - - return 0; - - fail: - release_mem_region(pci_resource_start(btv->dev,0), - pci_resource_len(btv->dev,0)); - return result; -} - -static struct pci_device_id bttv_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); - -static struct pci_driver bttv_pci_driver = { - name: "bttv", - id_table: bttv_pci_tbl, - probe: bttv_probe, - remove: bttv_remove, -}; - -int bttv_init_module(void) -{ - bttv_num = 0; - - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", - (BTTV_VERSION_CODE >> 16) & 0xff, - (BTTV_VERSION_CODE >> 8) & 0xff, - BTTV_VERSION_CODE & 0xff); - if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) - gbuffers = 2; - if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) - gbufsize = BTTV_MAX_FBUF; - if (verbose) - printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", - gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); - - handle_chipset(); - - return pci_module_init(&bttv_pci_driver); -} - -void bttv_cleanup_module(void) -{ - pci_unregister_driver(&bttv_pci_driver); - return; -} - -module_init(bttv_init_module); -module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */