From: Gerd Knorr This patch is a update for the bttv driver. It is a big one because alot of changes accumulated over time -- partly because submitting updates in the past didn't work and partly because of some extra work with merging the changes due to the i2c cleanups back into my tree. Changes: * splitted some code which can be shared with another driver into the btcx-risc module. * some new features (field rate capture support for example). * tv card list updates. * various bugfixes. * merged i2c changes back into my tree, there are some no-op changes due to this. drivers/media/video/Makefile | 1 drivers/media/video/bt848.h | 38 +- drivers/media/video/btcx-risc.c | 266 +++++++++++++++ drivers/media/video/btcx-risc.h | 33 + drivers/media/video/bttv-cards.c | 372 +++++++++++++++++----- drivers/media/video/bttv-driver.c | 635 ++++++++++++++++++++++---------------- drivers/media/video/bttv-if.c | 5 drivers/media/video/bttv-risc.c | 344 +++++++------------- drivers/media/video/bttv-vbi.c | 40 ++ drivers/media/video/bttv.h | 34 +- drivers/media/video/bttvp.h | 105 ++---- 11 files changed, 1220 insertions(+), 653 deletions(-) diff -puN drivers/media/video/bt848.h~v4l-3 drivers/media/video/bt848.h --- 25/drivers/media/video/bt848.h~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bt848.h 2003-05-17 14:09:42.000000000 -0700 @@ -204,6 +204,9 @@ #define BT848_COLOR_FMT_YCrCb411 0x99 #define BT848_COLOR_FMT_RAW 0xee +#define BT848_VTOTAL_LO 0xB0 +#define BT848_VTOTAL_HI 0xB4 + #define BT848_COLOR_CTL 0x0D8 #define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) #define BT848_COLOR_CTL_COLOR_BARS (1<<6) @@ -311,29 +314,28 @@ /* WRITE and SKIP */ /* disable which bytes of each DWORD */ -#define BT848_RISC_BYTE0 (1<<12) -#define BT848_RISC_BYTE1 (1<<13) -#define BT848_RISC_BYTE2 (1<<14) -#define BT848_RISC_BYTE3 (1<<15) -#define BT848_RISC_BYTE_ALL (0x0f<<12) +#define BT848_RISC_BYTE0 (1U<<12) +#define BT848_RISC_BYTE1 (1U<<13) +#define BT848_RISC_BYTE2 (1U<<14) +#define BT848_RISC_BYTE3 (1U<<15) +#define BT848_RISC_BYTE_ALL (0x0fU<<12) #define BT848_RISC_BYTE_NONE 0 /* cause RISCI */ -#define BT848_RISC_IRQ (1<<24) +#define BT848_RISC_IRQ (1U<<24) /* RISC command is last one in this line */ -#define BT848_RISC_EOL (1<<26) +#define BT848_RISC_EOL (1U<<26) /* RISC command is first one in this line */ -#define BT848_RISC_SOL (1<<27) - -#define BT848_RISC_WRITE (0x01<<28) -#define BT848_RISC_SKIP (0x02<<28) -#define BT848_RISC_WRITEC (0x05<<28) -#define BT848_RISC_JUMP (0x07<<28) -#define BT848_RISC_SYNC (0x08<<28) - -#define BT848_RISC_WRITE123 (0x09<<28) -#define BT848_RISC_SKIP123 (0x0a<<28) -#define BT848_RISC_WRITE1S23 (0x0b<<28) +#define BT848_RISC_SOL (1U<<27) +#define BT848_RISC_WRITE (0x01U<<28) +#define BT848_RISC_SKIP (0x02U<<28) +#define BT848_RISC_WRITEC (0x05U<<28) +#define BT848_RISC_JUMP (0x07U<<28) +#define BT848_RISC_SYNC (0x08U<<28) + +#define BT848_RISC_WRITE123 (0x09U<<28) +#define BT848_RISC_SKIP123 (0x0aU<<28) +#define BT848_RISC_WRITE1S23 (0x0bU<<28) /* Bt848A and higher only !! */ diff -puN /dev/null drivers/media/video/btcx-risc.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/media/video/btcx-risc.c 2003-05-17 14:09:42.000000000 -0700 @@ -0,0 +1,266 @@ +/* + btcx-risc.c + + bt848/bt878/cx2388x risc code generator. + + (c) 2000-03 Gerd Knorr [SuSE Labs] + + 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 "btcx-risc.h" + +MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers"); +MODULE_AUTHOR("Gerd Knorr"); +MODULE_LICENSE("GPL"); + +static unsigned int debug = 0; +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)"); + +/* ---------------------------------------------------------- */ +/* allocate/free risc memory */ + +static int memcnt; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size) +{ + u32 *cpu; + dma_addr_t dma; + + cpu = pci_alloc_consistent(pci, size, &dma); + if (NULL == cpu) + return -ENOMEM; + memset(cpu,0,size); + +#if 0 + if (risc->cpu && risc->size < size) { + /* realloc (enlarge buffer) -- copy old stuff */ + memcpy(cpu,risc->cpu,risc->size); + btcx_riscmem_free(pci,risc); + } +#else + BUG_ON(NULL != risc->cpu); +#endif + risc->cpu = cpu; + risc->dma = dma; + risc->size = size; + + if (debug) { + memcnt++; + printk("btcx: riscmem alloc size=%d [%d]\n",size,memcnt); + } + + return 0; +} + +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc) +{ + if (NULL == risc->cpu) + return; + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + memset(risc,0,sizeof(*risc)); + if (debug) { + memcnt--; + printk("btcx: riscmem free [%d]\n",memcnt); + } +} + +/* ---------------------------------------------------------- */ +/* screen overlay helpers */ + +int +btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n) +{ + if (win->left < 0) { + /* left */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = -win->left; + clips[n].c.height = win->height; + n++; + } + if (win->left + win->width > swidth) { + /* right */ + clips[n].c.left = swidth - win->left; + clips[n].c.top = 0; + clips[n].c.width = win->width - clips[n].c.left; + clips[n].c.height = win->height; + n++; + } + if (win->top < 0) { + /* top */ + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = win->width; + clips[n].c.height = -win->top; + n++; + } + if (win->top + win->height > sheight) { + /* bottom */ + clips[n].c.left = 0; + clips[n].c.top = sheight - win->top; + clips[n].c.width = win->width; + clips[n].c.height = win->height - clips[n].c.top; + n++; + } + return n; +} + +int +btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask) +{ + s32 nx,nw,dx; + unsigned int i; + + /* fixup window */ + nx = (win->left + mask) & ~mask; + nw = (win->width) & ~mask; + if (nx + nw > win->left + win->width) + nw -= mask+1; + dx = nx - win->left; + win->left = nx; + win->width = nw; + if (debug) + printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", + win->width, win->height, win->left, win->top, dx); + + /* fixup clips */ + for (i = 0; i < n; i++) { + nx = (clips[i].c.left-dx) & ~mask; + nw = (clips[i].c.width) & ~mask; + if (nx + nw < clips[i].c.left-dx + clips[i].c.width) + nw += mask+1; + clips[i].c.left = nx; + clips[i].c.width = nw; + if (debug) + printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", + clips[i].c.width, clips[i].c.height, + clips[i].c.left, clips[i].c.top); + } + return 0; +} + +void +btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) +{ + struct v4l2_clip swap; + int i,j,n; + + if (nclips < 2) + return; + for (i = nclips-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (clips[j].c.left > clips[j+1].c.left) { + swap = clips[j]; + clips[j] = clips[j+1]; + clips[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + +void +btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips) +{ + unsigned int clip,skip; + int end,maxline; + + skip=0; + maxline = 9999; + for (clip = 0; clip < nclips; clip++) { + + /* sanity checks */ + if (clips[clip].c.left + clips[clip].c.width <= 0) + continue; + if (clips[clip].c.left > (signed)width) + break; + + /* vertical range */ + if (line > clips[clip].c.top+clips[clip].c.height-1) + continue; + if (line < clips[clip].c.top) { + if (maxline > clips[clip].c.top-1) + maxline = clips[clip].c.top-1; + continue; + } + if (maxline > clips[clip].c.top+clips[clip].c.height-1) + maxline = clips[clip].c.top+clips[clip].c.height-1; + + /* horizontal range */ + if (0 == skip || clips[clip].c.left > skips[skip-1].end) { + /* new one */ + skips[skip].start = clips[clip].c.left; + if (skips[skip].start < 0) + skips[skip].start = 0; + skips[skip].end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip].end > width) + skips[skip].end = width; + skip++; + } else { + /* overlaps -- expand last one */ + end = clips[clip].c.left + clips[clip].c.width; + if (skips[skip-1].end < end) + skips[skip-1].end = end; + if (skips[skip-1].end > width) + skips[skip-1].end = width; + } + } + *nskips = skip; + *maxy = maxline; + + if (debug) { + printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); + for (skip = 0; skip < *nskips; skip++) { + printk(" %d-%d",skips[skip].start,skips[skip].end); + } + printk("\n"); + } +} + +/* ---------------------------------------------------------- */ + +EXPORT_SYMBOL(btcx_riscmem_alloc); +EXPORT_SYMBOL(btcx_riscmem_free); + +EXPORT_SYMBOL(btcx_screen_clips); +EXPORT_SYMBOL(btcx_align); +EXPORT_SYMBOL(btcx_sort_clips); +EXPORT_SYMBOL(btcx_calc_skips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -puN /dev/null drivers/media/video/btcx-risc.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/media/video/btcx-risc.h 2003-05-17 14:09:42.000000000 -0700 @@ -0,0 +1,33 @@ + +struct btcx_riscmem { + unsigned int size; + u32 *cpu; + u32 *jmp; + dma_addr_t dma; +}; + +struct btcx_skiplist { + int start; + int end; +}; + +int btcx_riscmem_alloc(struct pci_dev *pci, + struct btcx_riscmem *risc, + unsigned int size); +void btcx_riscmem_free(struct pci_dev *pci, + struct btcx_riscmem *risc); + +int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, unsigned int n); +int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, + unsigned int n, int mask); +void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); +void btcx_calc_skips(int line, int width, unsigned int *maxy, + struct btcx_skiplist *skips, unsigned int *nskips, + const struct v4l2_clip *clips, unsigned int nclips); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -puN drivers/media/video/bttv-cards.c~v4l-3 drivers/media/video/bttv-cards.c --- 25/drivers/media/video/bttv-cards.c~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv-cards.c 2003-05-17 14:09:42.000000000 -0700 @@ -21,7 +21,7 @@ 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 @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -55,32 +56,34 @@ static void winfast2000_audio(struct btt static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); +static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); static void eagle_muxsel(struct bttv *btv, unsigned int input); +static void xguard_muxsel(struct bttv *btv, unsigned int input); static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); static int tea5757_write(struct bttv *btv, int value); -int is_MM20xPCTV(unsigned char eeprom_data[256]); - +static void identify_by_eeprom(struct bttv *btv, + unsigned char eeprom_data[256]); /* config variables */ -static int triton1=0; -static int vsfx=0; -static int no_overlay=-1; -static int latency = -1; - -static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1}; -static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1}; -static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1}; +static unsigned int triton1=0; +static unsigned int vsfx=0; +static unsigned int latency = UNSET; +unsigned int no_overlay=-1; + +static unsigned int card[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; +static unsigned int pll[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; +static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET}; #ifdef MODULE static unsigned int autoload = 1; #else static unsigned int autoload = 0; #endif -static unsigned int gpiomask = -1; -static unsigned int audioall = -1; -static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 }; +static unsigned int gpiomask = UNSET; +static unsigned int audioall = UNSET; +static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET }; /* insmod options */ MODULE_PARM(triton1,"i"); @@ -153,9 +156,11 @@ static struct CARD { { 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, { 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, - { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" }, + // some cards ship with byteswapped IDs ... + { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, + { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" }, { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, { 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" }, @@ -163,6 +168,7 @@ static struct CARD { { 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, { 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, + { 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" }, { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" }, @@ -192,6 +198,23 @@ static struct CARD { { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + { 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" }, + { 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" }, + { 0x1462aa02, BTTV_PV150, "Provideo PV150A-3" }, + { 0x1463aa03, BTTV_PV150, "Provideo PV150A-4" }, + { 0x1464aa04, BTTV_PV150, "Provideo PV150B-1" }, + { 0x1465aa05, BTTV_PV150, "Provideo PV150B-2" }, + { 0x1466aa06, BTTV_PV150, "Provideo PV150B-3" }, + { 0x1467aa07, BTTV_PV150, "Provideo PV150B-4" }, + + { 0xa1550000, BTTV_IVC200, "IVC-200" }, + { 0xa1550001, BTTV_IVC200, "IVC-200" }, + { 0xa1550002, BTTV_IVC200, "IVC-200" }, + { 0xa1550003, BTTV_IVC200, "IVC-200" }, + + { 0x41424344, BTTV_GRANDTEC, "GrandTec Multi Capture" }, + { 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" }, + { 0x010115cb, BTTV_GMV1, "AG GMV1" }, { 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" }, { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, @@ -202,8 +225,11 @@ static struct CARD { { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" }, { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" }, { 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" }, - { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, + { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + // likely broken, vendor id doesn't match the other magic views ... + //{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, + { 0, -1, NULL } }; @@ -376,6 +402,7 @@ struct tvcard bttv_tvcards[] = { .muxsel = { 2, 3, 1, 1}, .audiomux = { 13, 14, 11, 7, 0, 0}, .needs_tvaudio = 1, + .msp34xx_alt = 1, .pll = PLL_28, .tuner_type = TUNER_PHILIPS_PAL, },{ @@ -613,7 +640,7 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .tuner_type = -1, },{ - .name = "Formac iProTV", + .name = "Formac iProTV, Formac ProTV I (bt848)", .video_inputs = 4, .audio_inputs = 1, .tuner = 0, @@ -763,6 +790,7 @@ struct tvcard bttv_tvcards[] = { .pll = PLL_28, .tuner_type = -1, .has_radio = 1, + .audio_hook = avermedia_tvphone_audio, },{ .name = "ProVideo PV951", /* pic16c54 */ .video_inputs = 3, @@ -904,10 +932,10 @@ struct tvcard bttv_tvcards[] = { /* ---- card 0x34 ---------------------------------- */ /* David Härdeman */ .name = "Pinnacle PCTV Studio Pro", - .video_inputs = 3, + .video_inputs = 4, .audio_inputs = 1, .tuner = 0, - .svhs = 2, + .svhs = 3, .gpiomask = 0x03000F, .muxsel = { 2, 3, 1, 1}, .audiomux = { 1, 0xd0001, 0, 0, 10}, @@ -1535,7 +1563,7 @@ struct tvcard bttv_tvcards[] = { .needs_tvaudio = 0, .pll = PLL_28, },{ - .name = "Formac ProTV II", + .name = "Formac ProTV II (bt878)", .video_inputs = 4, .audio_inputs = 1, .tuner = 0, @@ -1554,8 +1582,8 @@ struct tvcard bttv_tvcards[] = { not soldered here, though unknown wiring. Card lacks: external audio in, pci subsystem id. */ - },{ + /* ---- card 0x60 ---------------------------------- */ .name = "MachTV", .video_inputs = 3, @@ -1580,9 +1608,119 @@ struct tvcard bttv_tvcards[] = { .no_tda7432 = 1, .muxsel = { 2, 0, 1}, .pll = PLL_28, +},{ + /* Luc Van Hoeylandt */ + .name = "ProVideo PV150", /* 0x4f */ + .video_inputs = 2, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .gpiomask = 0, + .muxsel = { 2, 3 }, + .audiomux = { 0 }, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = -1, +},{ + /* Hiroshi Takekawa */ + /* This card lacks subsystem ID */ + .name = "AD-TVK503", /* 0x63 */ + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x001e8007, + .muxsel = { 2, 3, 1, 0 }, + /* Tuner, Radio, external, internal, mute, stereo */ + .audiomux = { 0x00060000, 0x000, 0x000000, 0x000000, 0x07, 0x0000 }, /* Sub: 0x00180000 */ + .needs_tvaudio = 0, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 2, + .audio_hook = adtvk503_audio, +},{ + + /* ---- card 0x64 ---------------------------------- */ + .name = "Hercules Smart TV Stereo", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .gpiomask = 0x00, + .muxsel = { 2, 3, 1, 1 }, + .needs_tvaudio = 1, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = 5, + /* Notes: + - card lacks subsystem ID + - stereo variant w/ daughter board with tda9874a @0xb0 + - Audio Routing: + always from tda9874 independent of GPIO (?) + external line in: unknown + - Other chips: em78p156elp @ 0x96 (probably IR remote control) + hef4053 (instead 4052) for unknown function + */ +},{ + .name = "Pace TV & Radio Card", + .video_inputs = 4, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + .muxsel = { 2, 3, 1, 1}, // Tuner, CVid, SVid, CVid over SVid connector + .gpiomask = 0, + .no_tda9875 = 1, + .no_tda7432 = 1, + .tuner_type = 1, + .has_radio = 1, + .pll = PLL_28, + /* Bt878, Bt832, FI1246 tuner; no pci subsystem id + only internal line out: (4pin header) RGGL + Radio must be decoded by msp3410d (not routed through)*/ + // .digital_mode = DIGITAL_MODE_CAMERA, // todo! +},{ + /* Chris Willing */ + .name = "IVC-200", + .video_inputs = 1, + .audio_inputs = 0, + .tuner = -1, + .tuner_type = -1, + .svhs = -1, + .gpiomask = 0xdf, + .muxsel = { 2 }, + .pll = PLL_28, +},{ + .name = "Grand X-Guard / Trust 814PCI", + .video_inputs = 16, + .audio_inputs = 0, + .tuner = -1, + .svhs = -1, + .tuner_type = 4, + .gpiomask2 = 0xff, + .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 }, + .muxsel_hook = xguard_muxsel, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, +},{ + + /* ---- card 0x68 ---------------------------------- */ + .name = "Nebula Electronics DigiTV", + .video_inputs = 0, + .audio_inputs = 0, + .svhs = -1, + .muxsel = { 2, 3, 1, 0}, + .needs_tvaudio = 0, + .no_msp34xx = 1, + .no_tda9875 = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = -1, }}; -const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); +const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); /* ----------------------------------------------------------------------- */ @@ -1614,19 +1752,21 @@ void __devinit bttv_idcard(struct bttv * printk(KERN_INFO "bttv%d: detected: %s [card=%d], " "PCI subsystem ID is %04x:%04x\n", btv->nr,cards[type].name,cards[type].cardnr, - btv->cardid & 0xffff, btv->cardid >> 16); + btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); btv->type = cards[type].cardnr; } else { /* 404 */ printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->nr, btv->cardid&0xffff, btv->cardid>>16); + btv->nr, btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); printk(KERN_DEBUG "please mail id, board name and " "the correct card= insmod option to kraxel@bytesex.org\n"); } } /* let the user override the autodetected type */ - if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) + if (card[btv->nr] < bttv_num_tvcards) btv->type=card[btv->nr]; /* print which card config we are using */ @@ -1636,14 +1776,14 @@ void __devinit bttv_idcard(struct bttv * bttv_tvcards[btv->type].name); printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr, btv->video_dev.name,btv->type, - (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ? - "insmod option" : "autodetected"); + card[btv->nr] < bttv_num_tvcards + ? "insmod option" : "autodetected"); /* overwrite gpio stuff ?? */ - if (-1 == audioall && -1 == audiomux[0]) + if (UNSET == audioall && UNSET == audiomux[0]) return; - if (-1 != audiomux[0]) { + if (UNSET != audiomux[0]) { gpiobits = 0; for (i = 0; i < 5; i++) { bttv_tvcards[btv->type].audiomux[i] = audiomux[i]; @@ -1655,7 +1795,7 @@ void __devinit bttv_idcard(struct bttv * bttv_tvcards[btv->type].audiomux[i] = audioall; } } - bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits; + bttv_tvcards[btv->type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", btv->nr,bttv_tvcards[btv->type].gpiomask); for (i = 0; i < 5; i++) { @@ -1669,13 +1809,22 @@ void __devinit bttv_idcard(struct bttv * */ /* Some Modular Technology cards have an eeprom, but no subsystem ID */ -int is_MM20xPCTV(unsigned char eeprom_data[256]) +void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) { - if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13)) { - printk("bttv: GET.MM20xPCTV found\n"); - return 1; // found + int type = -1; + + if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13)) + type = BTTV_MODTEC_205; + else if (0 == strncmp(eeprom_data+20,"Picolo",7)) + type = BTTV_EURESYS_PICOLO; + else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0) + type = BTTV_HAUPPAUGE; /* old bt848 */ + + if (-1 != type) { + btv->type = type; + printk("bttv%d: detected by eeprom: %s [card=%d]\n", + btv->nr, bttv_tvcards[btv->type].name, btv->type); } - return 0; } static void flyvideo_gpio(struct bttv *btv) @@ -1779,7 +1928,8 @@ static void miro_pinnacle_gpio(struct bt if (btv->type == BTTV_PINNACLE) btv->type = BTTV_PINNACLEPRO; } - printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + printk(KERN_INFO + "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", btv->nr, id+1, btv->tuner_type, !btv->has_radio ? "no" : (btv->has_matchbox ? "matchbox" : "fmtuner"), @@ -1813,13 +1963,13 @@ static void miro_pinnacle_gpio(struct bt info = "oops: unknown card"; break; } + if (-1 != msp) + btv->type = BTTV_PINNACLEPRO; printk(KERN_INFO "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", btv->nr, id, info, btv->has_radio ? "yes" : "no"); - btv->tuner_type = 33; - if (autoload) - request_module("tda9887"); - bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,&id); + btv->tuner_type = 33; + btv->pinnacle_id = id; } } @@ -1885,6 +2035,9 @@ void __devinit bttv_init_card1(struct bt case BTTV_VOODOOTV_FM: boot_msp34xx(btv,20); break; + case BTTV_AVERMEDIA98: + boot_msp34xx(btv,11); + break; case BTTV_HAUPPAUGEPVR: pvr_boot(btv); break; @@ -1897,13 +2050,8 @@ void __devinit bttv_init_card2(struct bt btv->tuner_type = -1; if (BTTV_UNKNOWN == btv->type) { - printk("bttv%d: Looking for eeprom\n",btv->nr); bttv_readee(btv,eeprom_data,0xa0); - if(is_MM20xPCTV(eeprom_data)) { - btv->type = BTTV_MODTEC_205; - printk("bttv%d: Autodetect by eeprom:(%s) [card=%d]\n", - btv->nr, bttv_tvcards[btv->type].name, btv->type); - } + identify_by_eeprom(btv,eeprom_data); } switch (btv->type) { @@ -2027,18 +2175,20 @@ void __devinit bttv_init_card2(struct bt btv->pll.pll_current = -1; /* tuner configuration (from card list / autodetect / insmod option) */ - if (-1 != bttv_tvcards[btv->type].tuner_type) - if( -1 == btv->tuner_type) + if (UNSET != bttv_tvcards[btv->type].tuner_type) + if(UNSET == btv->tuner_type) btv->tuner_type = bttv_tvcards[btv->type].tuner_type; - if (-1 != tuner[btv->nr]) + if (UNSET != tuner[btv->nr]) btv->tuner_type = tuner[btv->nr]; - if (btv->tuner_type != -1) - bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type); + if (btv->pinnacle_id != UNSET) + bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + &btv->pinnacle_id); + if (btv->tuner_type != UNSET) + bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); if (bttv_tvcards[btv->type].has_radio) btv->has_radio=1; - if (bttv_tvcards[btv->type].audio_hook) btv->audio_hook=bttv_tvcards[btv->type].audio_hook; @@ -2056,6 +2206,12 @@ void __devinit bttv_init_card2(struct bt request_module("msp3400"); } + if (bttv_tvcards[btv->type].msp34xx_alt && + bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0) { + if (autoload) + request_module("msp3400"); + } + if (!bttv_tvcards[btv->type].no_tda9875 && bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) { if (autoload) @@ -2073,7 +2229,12 @@ void __devinit bttv_init_card2(struct bt request_module("tvaudio"); } - if (bttv_tvcards[btv->type].tuner != -1) { + /* tuner modules */ + if (btv->pinnacle_id != UNSET) { + if (autoload) + request_module("tda9887"); + } + if (btv->tuner_type != UNSET) { if (autoload) request_module("tuner"); } @@ -2136,9 +2297,9 @@ hauppauge_tuner[] __devinitdata = { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, { TUNER_ABSENT, "Philips TD1536D_FH_44"}, - { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, - { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, - { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_NTSC_FM, "LG TPI8NSR01F"}, + { TUNER_LG_PAL_FM, "LG TPI8PSB01D"}, + { TUNER_LG_PAL, "LG TPI8PSB11D"}, { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, { TUNER_LG_PAL_I, "LG TAPC-I701D"} }; @@ -2147,15 +2308,17 @@ static void modtec_eeprom(struct bttv *b { if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - printk("bttv Modtec: Tuner autodetected %s\n",&eeprom_data[0x1e]); + printk("bttv Modtec: Tuner autodetected %s\n", + &eeprom_data[0x1e]); + } else { + printk("bttv Modtec: Unknown TunerString:%s\n", + &eeprom_data[0x1e]); } - else - printk("bttv Modtec: Unknown TunerString:%s\n",&eeprom_data[0x1e]); } static void __devinit hauppauge_eeprom(struct bttv *btv) { - int blk2,tuner,radio,model; + unsigned int blk2,tuner,radio,model; if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n", @@ -2169,9 +2332,8 @@ static void __devinit hauppauge_eeprom(s tuner = eeprom_data[9]; radio = eeprom_data[blk2-1] & 0x01; - if (tuner >= ARRAY_SIZE(hauppauge_tuner)) - tuner = 0; - btv->tuner_type = hauppauge_tuner[tuner].id; + if (tuner < ARRAY_SIZE(hauppauge_tuner)) + btv->tuner_type = hauppauge_tuner[tuner].id; if (radio) btv->has_radio = 1; @@ -2540,7 +2702,8 @@ static void __devinit init_PXC200(struct static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 }; - int i,tmp; + unsigned int i; + int tmp; /* Initialise GPIO-connevted stuff */ btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ @@ -2573,7 +2736,7 @@ static void __devinit init_PXC200(struct printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); - for (i = 0; i < sizeof(vals)/sizeof(int); i++) { + for (i = 0; i < ARRAY_SIZE(vals); 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)); @@ -2670,8 +2833,8 @@ int bus_in(struct bttv *btv, int bit) /* Low-level stuff */ static int tea5757_read(struct bttv *btv) { + unsigned long timeout; int value = 0; - long timeout; int i; /* better safe than sorry */ @@ -2754,12 +2917,13 @@ static int tea5757_write(struct bttv *bt void tea5757_set_freq(struct bttv *btv, unsigned short freq) { - int value; - dprintk("tea5757_set_freq %d\n",freq); tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ +#if 0 + /* breaks Miro PCTV */ value = tea5757_read(btv); - dprintk("bttv%d: tea5757 readback =0x%x\n",btv->nr,value); + dprintk("bttv%d: tea5757 readback=0x%x\n",btv->nr,value); +#endif } @@ -3051,6 +3215,38 @@ windvr_audio(struct bttv *btv, struct vi } } +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +static void +adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int con = 0xffffff; + + //btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); + + if (set) { + //btor(***, BT848_GPIO_OUT_EN); + if (v->mode & VIDEO_SOUND_LANG1) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x00180000; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_MONO) + con = 0x00060000; + if (con != 0xffffff) { + btaor(con, ~0x1e0000, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint @@ -3091,6 +3287,34 @@ static void rv605_muxsel(struct bttv *bt mdelay(1); } +// The Grandtec X-Guard framegrabber card uses two Dual 4-channel +// video multiplexers to provide up to 16 video inputs. These +// multiplexers are controlled by the lower 8 GPIO pins of the +// bt878. The multiplexers probably Pericom PI5V331Q or similar. + +// xxx0 is pin xxx of multiplexer U5, +// yyy1 is pin yyy of multiplexer U2 + +#define ENA0 0x01 +#define ENB0 0x02 +#define ENA1 0x04 +#define ENB1 0x08 + +#define IN10 0x10 +#define IN00 0x20 +#define IN11 0x40 +#define IN01 0x80 + +static void xguard_muxsel(struct bttv *btv, unsigned int input) +{ + static const int masks[] = { + ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10, + ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10, + ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11, + ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11, + }; + btwrite(masks[input%16], BT848_GPIO_DATA); +} /* ----------------------------------------------------------------------- */ /* motherboard chipset specific stuff */ @@ -3122,12 +3346,12 @@ void __devinit bttv_check_chipset(void) printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); if (pcipci_fail) { printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n"); - if (-1 == no_overlay) { + if (UNSET == no_overlay) { printk(KERN_WARNING "bttv: going to disable overlay.\n"); no_overlay = 1; } } - if (-1 != latency) + if (UNSET != latency) printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency); while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, @@ -3144,7 +3368,7 @@ int __devinit bttv_handle_chipset(struct { unsigned char command; - if (!triton1 && !vsfx && -1 == latency) + if (!triton1 && !vsfx && UNSET == latency) return 0; if (bttv_verbose) { @@ -3152,7 +3376,7 @@ int __devinit bttv_handle_chipset(struct printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr); if (vsfx && btv->id >= 878) printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->nr); - if (-1 != latency) + if (UNSET != latency) printk(KERN_INFO "bttv%d: setting pci timer to %d\n", btv->nr,latency); } @@ -3170,7 +3394,7 @@ int __devinit bttv_handle_chipset(struct command |= BT878_EN_VSFX; pci_write_config_byte(btv->dev, BT878_DEVCTRL, command); } - if (-1 != latency) + if (UNSET != latency) pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency); return 0; } diff -puN drivers/media/video/bttv-driver.c~v4l-3 drivers/media/video/bttv-driver.c --- 25/drivers/media/video/bttv-driver.c~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv-driver.c 2003-05-17 14:09:42.000000000 -0700 @@ -35,10 +35,11 @@ #include #include +#include #include "bttvp.h" -int bttv_num; /* number of Bt848s in use */ +unsigned int bttv_num; /* number of Bt848s in use */ struct bttv bttvs[BTTV_MAX]; unsigned int bttv_debug = 0; @@ -46,7 +47,7 @@ unsigned int bttv_verbose = 1; unsigned int bttv_gpio = 0; /* config variables */ -#if defined(__sparc__) || defined(__powerpc__) || defined(__hppa__) +#ifdef __BIG_ENDIAN static unsigned int bigendian=1; #else static unsigned int bigendian=0; @@ -275,9 +276,29 @@ const struct bttv_tvnorm bttv_tvnorms[] .vdelay = 0x16, .vbipack = 144, .sram = -1, + },{ + /* that one hopefully works with the strange timing + * which video recorders produce when playing a NTSC + * tape on a PAL TV ... */ + .v4l2_id = V4L2_STD_PAL_60, + .name = "PAL-60", + .Fsc = 35468950, + .swidth = 924, + .sheight = 480, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 924, + .vdelay = 0x1a, + .vbipack = 255, + .vtotal = 524, + .sram = -1, } }; -const int BTTV_TVNORMS = (sizeof(bttv_tvnorms)/sizeof(struct bttv_tvnorm)); +const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); /* ----------------------------------------------------------------------- */ /* bttv format list @@ -434,7 +455,7 @@ const struct bttv_format bttv_formats[] .flags = FORMAT_FLAGS_RAW, } }; -const int BTTV_FORMATS = (sizeof(bttv_formats)/sizeof(struct bttv_format)); +const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); /* ----------------------------------------------------------------------- */ @@ -557,7 +578,7 @@ static const struct v4l2_queryctrl bttv_ .type = V4L2_CTRL_TYPE_BOOLEAN, } }; -const int BTTV_CTLS = (sizeof(bttv_ctls)/sizeof(struct v4l2_queryctrl)); +const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1159,7 +1180,7 @@ void bttv_field_count(struct bttv *btv) static const struct bttv_format* format_by_palette(int palette) { - int i; + unsigned int i; for (i = 0; i < BTTV_FORMATS; i++) { if (-1 == bttv_formats[i].palette) @@ -1173,7 +1194,7 @@ format_by_palette(int palette) static const struct bttv_format* format_by_fourcc(int fourcc) { - int i; + unsigned int i; for (i = 0; i < BTTV_FORMATS; i++) { if (-1 == bttv_formats[i].fourcc) @@ -1195,6 +1216,7 @@ bttv_switch_overlay(struct bttv *btv, st unsigned long flags; int retval = 0; + dprintk("switch_overlay: enter [new=%p]\n",new); if (new) new->vb.state = STATE_DONE; spin_lock_irqsave(&btv->s_lock,flags); @@ -1204,8 +1226,12 @@ bttv_switch_overlay(struct bttv *btv, st spin_unlock_irqrestore(&btv->s_lock,flags); if (NULL == new) free_btres(btv,fh,RESOURCE_OVERLAY); - if (NULL != old) + if (NULL != old) { + dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); bttv_dma_free(btv, old); + kfree(old); + } + dprintk("switch_overlay: done\n"); return retval; } @@ -1214,7 +1240,7 @@ bttv_switch_overlay(struct bttv *btv, st static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf, const struct bttv_format *fmt, - int width, int height, + unsigned int width, unsigned int height, enum v4l2_field field) { int redo_dma_risc = 0; @@ -1252,13 +1278,6 @@ static int bttv_prepare_buffer(struct bt redo_dma_risc = 1; } -#if 0 - if (STATE_NEEDS_INIT == buf->vb.state) { - if (redo_dma_risc) - bttv_dma_free(btv,buf); - } -#endif - /* alloc risc memory */ if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; @@ -1334,7 +1353,7 @@ static const char *v4l1_ioctls[] = { "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*)) +#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { @@ -1365,7 +1384,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct video_tuner *v = arg; - if (-1 == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->type].tuner) return -EINVAL; if (v->tuner) /* Only tuner 0 */ return -EINVAL; @@ -1397,38 +1416,39 @@ int bttv_common_ioctls(struct bttv *btv, case VIDIOCGCHAN: { struct video_channel *v = arg; + unsigned int channel = v->channel; - if (v->channel >= bttv_tvcards[btv->type].video_inputs) + if (channel >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; v->tuners=0; v->flags = VIDEO_VC_AUDIO; v->type = VIDEO_TYPE_CAMERA; v->norm = btv->tvnorm; - if(v->channel == bttv_tvcards[btv->type].tuner) { + if (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) { + } else if (channel == bttv_tvcards[btv->type].svhs) { strcpy(v->name,"S-Video"); } else { - sprintf(v->name,"Composite%d",v->channel); + sprintf(v->name,"Composite%d",channel); } return 0; } case VIDIOCSCHAN: { struct video_channel *v = arg; + unsigned int channel = v->channel; - if (v->channel < 0 || - v->channel >= bttv_tvcards[btv->type].video_inputs) + if (channel >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; if (v->norm >= BTTV_TVNORMS) return -EINVAL; down(&btv->lock); - if (v->channel == btv->input && - v->norm == btv->tvnorm) { + if (channel == btv->input && + v->norm == btv->tvnorm) { /* nothing to do */ up(&btv->lock); return 0; @@ -1462,9 +1482,9 @@ int bttv_common_ioctls(struct bttv *btv, case VIDIOCSAUDIO: { struct video_audio *v = arg; + unsigned int audio = v->audio; - if(v->audio < 0 || - v->audio >= bttv_tvcards[btv->type].audio_inputs) + if (audio >= bttv_tvcards[btv->type].audio_inputs) return -EINVAL; down(&btv->lock); @@ -1483,11 +1503,13 @@ int bttv_common_ioctls(struct bttv *btv, case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; + unsigned int index = e->index; - if (e->index < 0 || e->index >= BTTV_TVNORMS) + if (index >= BTTV_TVNORMS) return -EINVAL; v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, bttv_tvnorms[e->index].name); + e->index = index; return 0; } case VIDIOC_G_STD: @@ -1499,7 +1521,7 @@ int bttv_common_ioctls(struct bttv *btv, case VIDIOC_S_STD: { v4l2_std_id *id = arg; - int i; + unsigned int i; for (i = 0; i < BTTV_TVNORMS; i++) if (*id & bttv_tvnorms[i].v4l2_id) @@ -1527,7 +1549,7 @@ int bttv_common_ioctls(struct bttv *btv, case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; - int n; + unsigned int n; n = i->index; if (n >= bttv_tvcards[btv->type].video_inputs) @@ -1564,9 +1586,9 @@ int bttv_common_ioctls(struct bttv *btv, } case VIDIOC_S_INPUT: { - int *i = arg; + unsigned int *i = arg; - if (*i < 0 || *i > bttv_tvcards[btv->type].video_inputs) + if (*i > bttv_tvcards[btv->type].video_inputs) return -EINVAL; down(&btv->lock); set_input(btv,*i); @@ -1579,7 +1601,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct v4l2_tuner *t = arg; - if (-1 == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1587,8 +1609,8 @@ int bttv_common_ioctls(struct bttv *btv, memset(t,0,sizeof(*t)); strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; + t->capability = V4L2_TUNER_CAP_NORM; t->rxsubchans = V4L2_TUNER_SUB_MONO; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; @@ -1599,12 +1621,15 @@ int bttv_common_ioctls(struct bttv *btv, bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,0); - if(va.mode & VIDEO_SOUND_STEREO) + if(va.mode & VIDEO_SOUND_STEREO) { + t->audmode = V4L2_TUNER_MODE_STEREO; t->rxsubchans |= V4L2_TUNER_SUB_STEREO; - if(va.mode & VIDEO_SOUND_LANG1) - t->rxsubchans |= V4L2_TUNER_SUB_LANG1; - if(va.mode & VIDEO_SOUND_LANG2) - t->rxsubchans |= V4L2_TUNER_SUB_LANG2; + } + if(va.mode & VIDEO_SOUND_LANG1) { + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_LANG1 + | V4L2_TUNER_SUB_LANG2; + } } /* FIXME: fill capability+audmode */ up(&btv->lock); @@ -1614,7 +1639,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct v4l2_tuner *t = arg; - if (-1 == bttv_tvcards[btv->type].tuner) + if (UNSET == bttv_tvcards[btv->type].tuner) return -EINVAL; if (0 != t->index) return -EINVAL; @@ -1622,6 +1647,7 @@ int bttv_common_ioctls(struct bttv *btv, { struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); + bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (t->audmode == V4L2_TUNER_MODE_MONO) va.mode = VIDEO_SOUND_MONO; else if (t->audmode == V4L2_TUNER_MODE_STEREO) @@ -1676,7 +1702,7 @@ static int verify_window(const struct bt { enum v4l2_field field; int maxw, maxh; - + if (win->w.width < 48 || win->w.height < 32) return -EINVAL; if (win->clipcount > 2048) @@ -1705,15 +1731,6 @@ static int verify_window(const struct bt if (!fixup && (win->w.width > maxw || win->w.height > maxh)) return -EINVAL; - if (1 /* depth < 4bpp */) { - /* adjust and align writes */ - int left = (win->w.left + 3) & ~3; - int width = win->w.width & ~3; - while (left + width > win->w.left + win->w.width) - width -= 4; - win->w.left = left; - win->w.width = width; - } if (win->w.width > maxw) win->w.width = maxw; if (win->w.height > maxh) @@ -1728,6 +1745,8 @@ static int setup_window(struct bttv_fh * struct v4l2_clip *clips = NULL; int n,size,retval = 0; + if (NULL == fh->ovfmt) + return -EINVAL; retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup); if (0 != retval) return retval; @@ -1735,33 +1754,50 @@ static int setup_window(struct bttv_fh * /* copy clips -- luckily v4l1 + v4l2 are binary compatible here ...*/ n = win->clipcount; - size = sizeof(struct video_clip)*(n+4); + size = sizeof(*clips)*(n+4); clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; if (n > 0) { - if (copy_from_user(clips,win->clips, - sizeof(struct v4l2_clip)*win->clipcount)) { + if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { kfree(clips); return -EFAULT; } } /* clip against screen */ if (NULL != btv->fbuf.base) - n = bttv_screen_clips(btv->fbuf.width, btv->fbuf.width, + n = btcx_screen_clips(btv->fbuf.width, btv->fbuf.width, &win->w, clips, n); - bttv_sort_clips(clips,n); + btcx_sort_clips(clips,n); + + /* 4-byte alignments */ + switch (fh->ovfmt->depth) { + case 8: + case 24: + btcx_align(&win->w, clips, n, 3); + break; + case 16: + btcx_align(&win->w, clips, n, 1); + break; + case 32: + /* no alignment fixups needed */ + break; + default: + BUG(); + } down(&fh->cap.lock); if (fh->ov.clips) kfree(fh->ov.clips); - fh->ov.clips = clips; - fh->ov.nclips = n; + fh->ov.clips = clips; + fh->ov.nclips = n; - fh->ov.w = win->w; - fh->ov.field = win->field; + fh->ov.w = win->w; + fh->ov.field = win->field; + fh->ov.setup_ok = 1; btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; + btv->init.ov.field = win->field; /* update overlay if needed */ retval = 0; @@ -1834,8 +1870,10 @@ static int bttv_g_fmt(struct bttv_fh *fh f->fmt.pix.height = fh->height; f->fmt.pix.field = fh->cap.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.sizeimage = - (fh->width * fh->height * fh->fmt->depth)/8; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: memset(&f->fmt.win,0,sizeof(struct v4l2_window)); @@ -1843,7 +1881,7 @@ static int bttv_g_fmt(struct bttv_fh *fh f->fmt.win.field = fh->ov.field; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: - bttv_vbi_fmt(fh,f); + bttv_vbi_get_fmt(fh,f); return 0; default: return -EINVAL; @@ -1858,14 +1896,11 @@ static int bttv_try_fmt(struct bttv_fh * { const struct bttv_format *fmt; enum v4l2_field field; - int maxw,maxh; + unsigned int maxw,maxh; fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; - if (0 != f->fmt.pix.bytesperline) - /* FIXME -- not implemented yet */ - return -EINVAL; /* fixup format */ maxw = bttv_tvnorms[btv->tvnorm].swidth; @@ -1880,6 +1915,7 @@ static int bttv_try_fmt(struct bttv_fh * switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: maxh = maxh/2; break; case V4L2_FIELD_INTERLACED: @@ -1887,6 +1923,7 @@ static int bttv_try_fmt(struct bttv_fh * case V4L2_FIELD_SEQ_TB: if (fmt->flags & FORMAT_FLAGS_PLANAR) return -EINVAL; + break; default: return -EINVAL; } @@ -1901,25 +1938,19 @@ static int bttv_try_fmt(struct bttv_fh * f->fmt.pix.width = maxw; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = - (fh->width * fh->height * fmt->depth)/8; + f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: return verify_window(&bttv_tvnorms[btv->tvnorm], &f->fmt.win, 1); -#if 0 case V4L2_BUF_TYPE_VBI_CAPTURE: - retval = bttv_switch_type(fh,f->type); - if (0 != retval) - return retval; - if (fh->vbi.reading || fh->vbi.streaming) - return -EBUSY; - bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]); - bttv_vbi_fmt(fh,f); + bttv_vbi_try_fmt(fh,f); return 0; -#endif default: return -EINVAL; } @@ -1947,6 +1978,7 @@ static int bttv_s_fmt(struct bttv_fh *fh down(&fh->cap.lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; + fh->cap.last = V4L2_FIELD_NONE; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; btv->init.fmt = fmt; @@ -1962,10 +1994,11 @@ static int bttv_s_fmt(struct bttv_fh *fh retval = bttv_switch_type(fh,f->type); if (0 != retval) return retval; - if (fh->vbi.reading || fh->vbi.streaming) - return -EBUSY; + if (locked_btres(fh->btv, RESOURCE_VBI)) + return -EBUSY; + bttv_vbi_try_fmt(fh,f); bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]); - bttv_vbi_fmt(fh,f); + bttv_vbi_get_fmt(fh,f); return 0; default: return -EINVAL; @@ -1978,7 +2011,7 @@ static int bttv_do_ioctl(struct inode *i struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; unsigned long flags; - int retval; + int retval = 0; if (bttv_debug > 1) { switch (_IOC_TYPE(cmd)) { @@ -2092,7 +2125,7 @@ static int bttv_do_ioctl(struct inode *i struct video_window *win = arg; struct v4l2_window w2; - w2.field = V4L2_FIELD_ANY; + w2.field = V4L2_FIELD_ANY; w2.w.left = win->x; w2.w.top = win->y; w2.w.width = win->width; @@ -2181,11 +2214,7 @@ static int bttv_do_ioctl(struct inode *i /* verify args */ if (NULL == btv->fbuf.base) return -EINVAL; - if (fh->ov.w.width <48 || - fh->ov.w.height<32 || - fh->ov.w.width >bttv_tvnorms[btv->tvnorm].swidth || - fh->ov.w.height>bttv_tvnorms[btv->tvnorm].sheight|| - NULL == fh->ovfmt) + if (!fh->ov.setup_ok) return -EINVAL; } @@ -2210,7 +2239,7 @@ static int bttv_do_ioctl(struct inode *i case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; - int i; + unsigned int i; down(&fh->cap.lock); retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize); @@ -2290,6 +2319,53 @@ static int bttv_do_ioctl(struct inode *i return retval; } + case VIDIOCGVBIFMT: + { + struct vbi_format *fmt = (void *) arg; + struct v4l2_format fmt2; + + retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); + if (0 != retval) + return retval; + bttv_vbi_get_fmt(fh, &fmt2); + + fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate; + fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line; + fmt->sample_format = VIDEO_PALETTE_RAW; + fmt->start[0] = fmt2.fmt.vbi.start[0]; + fmt->count[0] = fmt2.fmt.vbi.count[0]; + fmt->start[1] = fmt2.fmt.vbi.start[1]; + fmt->count[1] = fmt2.fmt.vbi.count[1]; + if (fmt2.fmt.vbi.flags & VBI_UNSYNC) + fmt->flags |= V4L2_VBI_UNSYNC; + if (fmt2.fmt.vbi.flags & VBI_INTERLACED) + fmt->flags |= V4L2_VBI_INTERLACED; + return 0; + } + case VIDIOCSVBIFMT: + { + struct vbi_format *fmt = (void *) arg; + struct v4l2_format fmt2; + + retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); + if (0 != retval) + return retval; + bttv_vbi_get_fmt(fh, &fmt2); + + if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate || + fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line || + fmt->sample_format != VIDEO_PALETTE_RAW || + fmt->start[0] != fmt2.fmt.vbi.start[0] || + fmt->start[1] != fmt2.fmt.vbi.start[1] || + fmt->count[0] != fmt->count[1] || + fmt->count[0] < 1 || + fmt->count[0] > 32 /* VBI_MAXLINES */) + return -EINVAL; + + bttv_vbi_setlines(fh,btv,fmt->count[0]); + return 0; + } + case BTTV_VERSION: case VIDIOCGFREQ: case VIDIOCSFREQ: @@ -2326,7 +2402,8 @@ static int bttv_do_ioctl(struct inode *i { struct v4l2_fmtdesc *f = arg; enum v4l2_buf_type type; - int i, index; + unsigned int i; + int index; type = f->type; if (V4L2_BUF_TYPE_VBI_CAPTURE == type) { @@ -2347,7 +2424,7 @@ static int bttv_do_ioctl(struct inode *i for (i = 0; i < BTTV_FORMATS; i++) { if (bttv_formats[i].fourcc != -1) index++; - if (index == f->index) + if ((unsigned int)index == f->index) break; } if (BTTV_FORMATS == i) @@ -2604,8 +2681,8 @@ static ssize_t bttv_read(struct file *fi if (fh->btv->errors) bttv_reinit_bt848(fh->btv); - dprintk("read count=%d type=%s\n", - (int)count,v4l2_type_names[fh->type]); + dprintk("bttv%d: read count=%d type=%s\n", + fh->btv->nr,(int)count,v4l2_type_names[fh->type]); switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -2628,6 +2705,7 @@ static unsigned int bttv_poll(struct fil { struct bttv_fh *fh = file->private_data; struct bttv_buffer *buf; + enum v4l2_field field; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI)) @@ -2654,7 +2732,8 @@ static unsigned int bttv_poll(struct fil up(&fh->cap.lock); return POLLERR; } - if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,fh->cap.field)) { + field = videobuf_next_field(&fh->cap); + if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf,field)) { up(&fh->cap.lock); return POLLERR; } @@ -2674,11 +2753,11 @@ static unsigned int bttv_poll(struct fil static int bttv_open(struct inode *inode, struct file *file) { - unsigned int minor = minor(inode->i_rdev); + int minor = minor(inode->i_rdev); struct bttv *btv = NULL; struct bttv_fh *fh; enum v4l2_buf_type type = 0; - int i; + unsigned int i; dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); @@ -2707,6 +2786,7 @@ static int bttv_open(struct inode *inode file->private_data = fh; *fh = btv->init; fh->type = type; + fh->ov.setup_ok = 0; videobuf_queue_init(&fh->cap, &bttv_video_qops, btv->dev, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -2720,6 +2800,8 @@ static int bttv_open(struct inode *inode i2c_vidiocschan(btv); btv->users++; + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) + bttv_vbi_setlines(fh,btv,16); bttv_field_count(btv); return 0; } @@ -2807,10 +2889,10 @@ struct video_device bttv_vbi_template = static int radio_open(struct inode *inode, struct file *file) { - unsigned int minor = minor(inode->i_rdev); + int minor = minor(inode->i_rdev); struct bttv *btv = NULL; - unsigned long v = 400*16; - int i; + u32 v = 400*16; + unsigned int i; dprintk("bttv: open minor=%d\n",minor); @@ -2934,10 +3016,10 @@ static char *irq_name[] = { "FMTCHG", "V static void bttv_print_irqbits(u32 print, u32 mark) { - int i; + unsigned int i; printk("bits:"); - for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) { + for (i = 0; i < ARRAY_SIZE(irq_name); i++) { if (print & (1 << i)) printk(" %s",irq_name[i]); if (mark & (1 << i)) @@ -2950,22 +3032,132 @@ static void bttv_print_riscaddr(struct b printk(" main: %08Lx\n", (u64)btv->main.dma); printk(" vbi : o=%08Lx e=%08Lx\n", - btv->vcurr ? (u64)btv->vcurr->top.dma : 0, - btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0); + btv->curr.vbi ? (u64)btv->curr.vbi->top.dma : 0, + btv->curr.vbi ? (u64)btv->curr.vbi->bottom.dma : 0); printk(" cap : o=%08Lx e=%08Lx\n", - btv->top ? (u64)btv->top->top.dma : 0, - btv->bottom ? (u64)btv->bottom->bottom.dma : 0); + btv->curr.top ? (u64)btv->curr.top->top.dma : 0, + btv->curr.bottom ? (u64)btv->curr.bottom->bottom.dma : 0); printk(" scr : o=%08Lx e=%08Lx\n", btv->screen ? (u64)btv->screen->top.dma : 0, btv->screen ? (u64)btv->screen->bottom.dma : 0); } +static int +bttv_irq_next_set(struct bttv *btv, struct bttv_buffer_set *set) +{ + struct bttv_buffer *item; + + memset(set,0,sizeof(*set)); + + /* vbi request ? */ + if (!list_empty(&btv->vcapture)) { + set->irqflags = 1; + set->vbi = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + } + + /* capture request ? */ + if (!list_empty(&btv->capture)) { + set->irqflags = 1; + item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); + if (V4L2_FIELD_HAS_TOP(item->vb.field)) + set->top = item; + if (V4L2_FIELD_HAS_BOTTOM(item->vb.field)) + set->bottom = item; + + /* capture request for other field ? */ + if (!V4L2_FIELD_HAS_BOTH(item->vb.field) && + (item->vb.queue.next != &btv->capture)) { + item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue); + if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { + if (NULL == set->top && + V4L2_FIELD_TOP == item->vb.field) { + set->top = item; + } + if (NULL == set->bottom && + V4L2_FIELD_BOTTOM == item->vb.field) { + set->bottom = item; + } + if (NULL != set->top && NULL != set->bottom) + set->topirq = 2; + } + } + } + + /* screen overlay ? */ + if (NULL != btv->screen) { + if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) { + if (NULL == set->top && NULL == set->bottom) { + set->top = btv->screen; + set->bottom = btv->screen; + } + } else { + if (V4L2_FIELD_TOP == btv->screen->vb.field && + NULL == set->top) { + set->top = btv->screen; + } + if (V4L2_FIELD_BOTTOM == btv->screen->vb.field && + NULL == set->bottom) { + set->bottom = btv->screen; + } + } + } + + dprintk("bttv%d: next set: top=%p bottom=%p vbi=%p " + "[screen=%p,irq=%d,%d]\n", + btv->nr,set->top, set->bottom, set->vbi, + btv->screen,set->irqflags,set->topirq); + return 0; +} + +static void +bttv_irq_wakeup_set(struct bttv *btv, struct bttv_buffer_set *wakeup, + struct bttv_buffer_set *curr, unsigned int state) +{ + struct timeval ts; + + do_gettimeofday(&ts); + + if (NULL != wakeup->vbi) { + wakeup->vbi->vb.ts = ts; + wakeup->vbi->vb.field_count = btv->field_count; + wakeup->vbi->vb.state = state; + wake_up(&wakeup->vbi->vb.done); + } + if (wakeup->top == wakeup->bottom) { + if (NULL != wakeup->top && curr->top != wakeup->top) { + if (irq_debug) + printk("bttv%d: wakeup: both=%p\n",btv->nr,wakeup->top); + wakeup->top->vb.ts = ts; + wakeup->top->vb.field_count = btv->field_count; + wakeup->top->vb.state = state; + wake_up(&wakeup->top->vb.done); + } + } else { + if (NULL != wakeup->top && curr->top != wakeup->top) { + if (irq_debug) + printk("bttv%d: wakeup: top=%p\n",btv->nr,wakeup->top); + wakeup->top->vb.ts = ts; + wakeup->top->vb.field_count = btv->field_count; + wakeup->top->vb.state = state; + wake_up(&wakeup->top->vb.done); + } + if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) { + if (irq_debug) + printk("bttv%d: wakeup: bottom=%p\n",btv->nr,wakeup->bottom); + wakeup->bottom->vb.ts = ts; + wakeup->bottom->vb.field_count = btv->field_count; + wakeup->bottom->vb.state = state; + wake_up(&wakeup->bottom->vb.done); + } + } +} + static void bttv_irq_timeout(unsigned long data) { struct bttv *btv = (struct bttv *)data; - struct bttv_buffer *o_bottom,*o_top,*o_vcurr; - struct bttv_buffer *capture; - + struct bttv_buffer_set old,new; + struct bttv_buffer *item; + if (bttv_verbose) { printk(KERN_INFO "bttv%d: timeout: risc=%08x, ", btv->nr,btread(BT848_RISC_COUNT)); @@ -2974,53 +3166,29 @@ static void bttv_irq_timeout(unsigned lo } spin_lock(&btv->s_lock); - o_top = btv->top; - o_bottom = btv->bottom; - o_vcurr = btv->vcurr; - btv->top = NULL; - btv->bottom = NULL; - btv->vcurr = NULL; /* deactivate stuff */ - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0); + memset(&new,0,sizeof(new)); + old = btv->curr; + btv->curr = new; + bttv_buffer_set_activate(btv, &new); bttv_set_dma(btv, 0, 0); - /* wake up + free */ - if (o_top == o_bottom) { - if (NULL != o_top) { - o_top->vb.state = STATE_ERROR; - wake_up(&o_top->vb.done); - } - } else { - if (NULL != o_top) { - o_top->vb.state = STATE_ERROR; - wake_up(&o_top->vb.done); - } - if (NULL != o_bottom) { - o_bottom->vb.state = STATE_ERROR; - wake_up(&o_bottom->vb.done); - } - } - if (NULL != o_vcurr) { - o_vcurr->vb.state = STATE_ERROR; - wake_up(&o_vcurr->vb.done); - } + /* wake up */ + bttv_irq_wakeup_set(btv, &old, &new, STATE_ERROR); /* cancel all outstanding capture / vbi requests */ while (!list_empty(&btv->capture)) { - capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - list_del(&capture->vb.queue); - capture->vb.state = STATE_ERROR; - wake_up(&capture->vb.done); + item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = STATE_ERROR; + wake_up(&item->vb.done); } while (!list_empty(&btv->vcapture)) { - capture = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - list_del(&capture->vb.queue); - capture->vb.state = STATE_ERROR; - wake_up(&capture->vb.done); + item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = STATE_ERROR; + wake_up(&item->vb.done); } btv->errors++; @@ -3028,131 +3196,53 @@ static void bttv_irq_timeout(unsigned lo } static void -bttv_irq_switch_fields(struct bttv *btv) +bttv_irq_wakeup_top(struct bttv *btv) { - struct bttv_buffer *o_bottom,*o_top,*o_vcurr; - struct bttv_buffer *capture; - dma_addr_t rc; - int irqflags = 0; - struct timeval ts; + struct bttv_buffer *wakeup = btv->curr.top; - spin_lock(&btv->s_lock); - o_top = btv->top; - o_bottom = btv->bottom; - o_vcurr = btv->vcurr; - btv->top = NULL; - btv->bottom = NULL; - btv->vcurr = NULL; + if (NULL == wakeup) + return; - /* vbi request ? */ - if (!list_empty(&btv->vcapture)) { - irqflags = 1; - btv->vcurr = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - list_del(&btv->vcurr->vb.queue); - } - - /* capture request ? */ - if (!list_empty(&btv->capture)) { - irqflags = 1; - capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - list_del(&capture->vb.queue); - if (V4L2_FIELD_HAS_TOP(capture->vb.field)) - btv->top = capture; - if (V4L2_FIELD_HAS_BOTTOM(capture->vb.field)) - btv->bottom = capture; + spin_lock(&btv->s_lock); + btv->curr.topirq = 0; + btv->curr.top = NULL; + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - /* capture request for other field ? */ - if (!V4L2_FIELD_HAS_BOTH(capture->vb.field) && - !list_empty(&btv->capture)) { - capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - if (!V4L2_FIELD_HAS_BOTH(capture->vb.field)) { - if (NULL == btv->top && - V4L2_FIELD_TOP == capture->vb.field) { - btv->top = capture; - list_del(&capture->vb.queue); - } - if (NULL == btv->bottom && - V4L2_FIELD_BOTTOM == capture->vb.field) { - btv->bottom = capture; - list_del(&capture->vb.queue); - } - } - } - } + do_gettimeofday(&wakeup->vb.ts); + wakeup->vb.field_count = btv->field_count; + wakeup->vb.state = STATE_DONE; + wake_up(&wakeup->vb.done); + spin_unlock(&btv->s_lock); +} - /* screen overlay ? */ - if (NULL != btv->screen) { - if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) { - if (NULL == btv->top && NULL == btv->bottom) { - btv->top = btv->screen; - btv->bottom = btv->screen; - } - } else { - if (V4L2_FIELD_TOP == btv->screen->vb.field && - NULL == btv->top) { - btv->top = btv->screen; - } - if (V4L2_FIELD_BOTTOM == btv->screen->vb.field && - NULL == btv->bottom) { - btv->bottom = btv->screen; - } - } - } +static void +bttv_irq_switch_fields(struct bttv *btv) +{ + struct bttv_buffer_set new; + struct bttv_buffer_set old; + dma_addr_t rc; - if (irq_debug) - printk(KERN_DEBUG "bttv%d: irq top=0x%08x bottom=0x%08x" - " vbi=0x%08x/0x%08x\n", btv->nr, - btv->top ? btv->top->top.dma : 0, - btv->bottom ? btv->bottom->bottom.dma : 0, - btv->vcurr ? btv->vcurr->top.dma : 0, - btv->vcurr ? btv->vcurr->bottom.dma : 0); + spin_lock(&btv->s_lock); + /* new buffer set */ + bttv_irq_next_set(btv, &new); rc = btread(BT848_RISC_COUNT); - if (rc < btv->main.dma || rc > btv->main.dma + 0x100) - printk("bttv%d: Huh? IRQ latency? main=0x%x rc=0x%x\n", - btv->nr,btv->main.dma,rc); - - /* activate new fields */ - bttv_buffer_activate(btv,btv->top,btv->bottom); - if (btv->vcurr) { - btv->vcurr->vb.state = STATE_ACTIVE; - bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->top, 0); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->bottom, 0); - } else { - bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0); - } - bttv_set_dma(btv, 0, irqflags); - - /* wake up + free */ - do_gettimeofday(&ts); - if (o_top == o_bottom) { - if (NULL != o_top && btv->top != o_top) { - o_top->vb.ts = ts; - o_top->vb.field_count = btv->field_count; - o_top->vb.state = STATE_DONE; - wake_up(&o_top->vb.done); - } - } else { - if (NULL != o_top && btv->top != o_top) { - o_top->vb.ts = ts; - o_top->vb.field_count = btv->field_count; - o_top->vb.state = STATE_DONE; - wake_up(&o_top->vb.done); - } - if (NULL != o_bottom && btv->bottom != o_bottom) { - o_bottom->vb.ts = ts; - o_bottom->vb.field_count = btv->field_count; - o_bottom->vb.state = STATE_DONE; - wake_up(&o_bottom->vb.done); - } - } - if (NULL != o_vcurr) { - o_vcurr->vb.ts = ts; - o_vcurr->vb.field_count = btv->field_count; - o_vcurr->vb.state = STATE_DONE; - wake_up(&o_vcurr->vb.done); - } + if (rc < btv->main.dma || rc > btv->main.dma + 0x100) { + if (1 /* irq_debug */) + printk("bttv%d: skipped frame. no signal? high irq latency?\n", + btv->nr); + spin_unlock(&btv->s_lock); + return; + } + + /* switch over */ + old = btv->curr; + btv->curr = new; + bttv_buffer_set_activate(btv, &new); + bttv_set_dma(btv, 0, new.irqflags); + + /* wake up finished buffers */ + bttv_irq_wakeup_set(btv, &old, &new, STATE_DONE); spin_unlock(&btv->s_lock); } @@ -3178,7 +3268,7 @@ static irqreturn_t bttv_irq(int irq, voi /* get device status bits */ dstat=btread(BT848_DSTATUS); - if (irq_debug) { + if (0 /*irq_debug*/) { printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d " "riscs=%x, riscc=%08x, ", btv->nr, count, btv->field_count, @@ -3201,7 +3291,10 @@ static irqreturn_t bttv_irq(int irq, voi if (astat & BT848_INT_GPINT) wake_up(&btv->gpioq); - + + if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) + bttv_irq_wakeup_top(btv); + if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) bttv_irq_switch_fields(btv); @@ -3308,7 +3401,8 @@ static int __devinit bttv_probe(struct p btv->timeout.data = (unsigned long)btv; btv->i2c_rc = -1; - btv->tuner_type = -1; + btv->tuner_type = UNSET; + btv->pinnacle_id = UNSET; memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template)); memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template)); @@ -3485,7 +3579,7 @@ static void __devexit bttv_remove(struct video_unregister_device(&btv->vbi_dev); /* free allocated memory */ - bttv_riscmem_free(btv->dev,&btv->main); + btcx_riscmem_free(btv->dev,&btv->main); /* free ressources */ free_irq(btv->dev->irq,btv); @@ -3519,6 +3613,7 @@ static struct pci_driver bttv_pci_driver static int bttv_init_module(void) { + int rc; bttv_num = 0; printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", @@ -3536,7 +3631,13 @@ static int bttv_init_module(void) bttv_check_chipset(); - return pci_module_init(&bttv_pci_driver); + rc = pci_module_init(&bttv_pci_driver); + if (-ENODEV == rc) { + /* plenty of people trying to use bttv for the cx2388x ... */ + if (NULL != pci_find_device(0x14f1, 0x8800, NULL)) + printk("bttv doesn't support your Conexant 2388x card.\n"); + } + return rc; } static void bttv_cleanup_module(void) diff -puN drivers/media/video/bttv.h~v4l-3 drivers/media/video/bttv.h --- 25/drivers/media/video/bttv.h~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv.h 2003-05-17 14:09:42.000000000 -0700 @@ -90,6 +90,7 @@ #define BTTV_SENSORAY311 0x49 #define BTTV_RV605 0x4a #define BTTV_WINDVR 0x4c +#define BTTV_GRANDTEC 0x4d #define BTTV_KWORLD 0x4e #define BTTV_HAUPPAUGEPVR 0x50 #define BTTV_GVBCTV5PCI 0x51 @@ -108,6 +109,11 @@ #define BTTV_PINNACLESAT 0x5e #define BTTV_FORMAC_PROTV 0x5f #define BTTV_EURESYS_PICOLO 0x61 +#define BTTV_PV150 0x62 +#define BTTV_AD_TVK503 0x63 +#define BTTV_IVC200 0x66 +#define BTTV_XGUARD 0x67 +#define BTTV_NEBULA_DIGITV 0x68 /* i2c address list */ #define I2C_TSA5522 0xc2 @@ -123,6 +129,7 @@ #define I2C_STBEE 0xae #define I2C_VHX 0xc0 #define I2C_MSP3400 0x80 +#define I2C_MSP3400_ALT 0x88 #define I2C_TEA6300 0x80 #define I2C_DPL3518 0x84 #define I2C_TDA9887 0x86 @@ -145,36 +152,37 @@ struct bttv; struct tvcard { char *name; - int video_inputs; - int audio_inputs; - int tuner; - int svhs; - int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO + unsigned int video_inputs; + unsigned int audio_inputs; + unsigned int tuner; + unsigned int svhs; + unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO u32 gpiomask; u32 muxsel[16]; u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ u32 gpiomask2; /* GPIO MUX mask */ /* i2c audio flags */ - int no_msp34xx:1; - int no_tda9875:1; - int no_tda7432:1; - int needs_tvaudio:1; + unsigned int no_msp34xx:1; + unsigned int no_tda9875:1; + unsigned int no_tda7432:1; + unsigned int needs_tvaudio:1; + unsigned int msp34xx_alt:1; /* other settings */ - int pll; + unsigned int pll; #define PLL_NONE 0 #define PLL_28 1 #define PLL_35 2 - int tuner_type; - int has_radio; + unsigned int tuner_type; + unsigned int has_radio; void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; extern struct tvcard bttv_tvcards[]; -extern const int bttv_num_tvcards; +extern const unsigned int bttv_num_tvcards; /* identification / initialization of the card */ extern void bttv_idcard(struct bttv *btv); diff -puN drivers/media/video/bttv-if.c~v4l-3 drivers/media/video/bttv-if.c --- 25/drivers/media/video/bttv-if.c~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv-if.c 2003-05-17 14:09:42.000000000 -0700 @@ -198,6 +198,9 @@ static int attach_inform(struct i2c_clie if (btv->tuner_type != UNSET) bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + if (btv->pinnacle_id != UNSET) + bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE, + &btv->pinnacle_id); if (bttv_debug) printk("bttv%d: i2c attach [client=%s]\n", @@ -231,9 +234,9 @@ static struct i2c_algo_bit_data bttv_i2c static struct i2c_adapter bttv_i2c_adap_template = { .owner = THIS_MODULE, + .class = I2C_ADAP_CLASS_TV_ANALOG, I2C_DEVNAME("bt848"), .id = I2C_HW_B_BT848, - .class = I2C_ADAP_CLASS_TV_ANALOG, .client_register = attach_inform, }; diff -puN drivers/media/video/bttvp.h~v4l-3 drivers/media/video/bttvp.h --- 25/drivers/media/video/bttvp.h~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttvp.h 2003-05-17 14:09:42.000000000 -0700 @@ -24,7 +24,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,4) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,11) #include #include @@ -40,6 +40,7 @@ #include "bt848.h" #include "bttv.h" +#include "btcx-risc.h" #ifdef __KERNEL__ @@ -66,8 +67,7 @@ /* ---------------------------------------------------------- */ -struct bttv_tvnorm -{ +struct bttv_tvnorm { int v4l2_id; char *name; u32 Fsc; @@ -78,10 +78,11 @@ struct bttv_tvnorm u16 hdelayx1, hactivex1; u16 vdelay; u8 vbipack; + u16 vtotal; int sram; }; extern const struct bttv_tvnorm bttv_tvnorms[]; -extern const int BTTV_TVNORMS; +extern const unsigned int BTTV_TVNORMS; struct bttv_format { char *name; @@ -94,21 +95,14 @@ struct bttv_format { int hshift,vshift; /* for planar modes */ }; extern const struct bttv_format bttv_formats[]; -extern const int BTTV_FORMATS; +extern const unsigned int BTTV_FORMATS; /* ---------------------------------------------------------- */ struct bttv_geometry { u8 vtc,crop,comb; u16 width,hscale,hdelay; - u16 sheight,vscale,vdelay; -}; - -struct bttv_riscmem { - unsigned int size; - u32 *cpu; - u32 *jmp; - dma_addr_t dma; + u16 sheight,vscale,vdelay,vtotal; }; struct bttv_buffer { @@ -121,16 +115,25 @@ struct bttv_buffer { int btformat; int btswap; struct bttv_geometry geo; - struct bttv_riscmem top; - struct bttv_riscmem bottom; + struct btcx_riscmem top; + struct btcx_riscmem bottom; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + struct bttv_buffer *vbi; /* vbi buffer */ + unsigned int irqflags; + unsigned int topirq; }; struct bttv_overlay { - int tvnorm; + int tvnorm; struct v4l2_rect w; enum v4l2_field field; struct v4l2_clip *clips; int nclips; + int setup_ok; }; struct bttv_fh { @@ -140,7 +143,6 @@ struct bttv_fh { /* video capture */ struct videobuf_queue cap; - /* struct bttv_buffer buf; */ const struct bttv_format *fmt; int width; int height; @@ -157,28 +159,19 @@ struct bttv_fh { /* ---------------------------------------------------------- */ /* bttv-risc.c */ -/* alloc/free memory */ -int bttv_riscmem_alloc(struct pci_dev *pci, - struct bttv_riscmem *risc, - unsigned int size); -void bttv_riscmem_free(struct pci_dev *pci, - struct bttv_riscmem *risc); - /* risc code generators - capture */ -int bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc, +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, - int offset, int bpl, int pitch, int lines); -int bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int lines); +int bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, - int yoffset, int ybpl, int ypadding, int ylines, - int uoffset, int voffset, int hshift, int vshift, - int cpadding); - -/* risc code generator + helpers - screen overlay */ -int bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win, - struct v4l2_clip *clips, int n); -void bttv_sort_clips(struct v4l2_clip *clips, int nclips); -int bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc, + unsigned int yoffset, unsigned int ybpl, + unsigned int ypadding, unsigned int ylines, + unsigned int uoffset, unsigned int voffset, + unsigned int hshift, unsigned int vshift, + unsigned int cpadding); +int bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int skip_top, int skip_bottom); @@ -191,13 +184,13 @@ void bttv_apply_geo(struct bttv *btv, st /* control dma register + risc main loop */ void bttv_set_dma(struct bttv *btv, int override, int irqflags); int bttv_risc_init_main(struct bttv *btv); -int bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc, +int bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, int irqflags); /* capture buffer handling */ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); -int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *top, - struct bttv_buffer *bottom); +int bttv_buffer_set_activate(struct bttv *btv, + struct bttv_buffer_set *set); void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf); /* overlay handling */ @@ -209,7 +202,8 @@ int bttv_overlay_risc(struct bttv *btv, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f); void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); extern struct videobuf_queue_ops bttv_vbi_qops; @@ -236,7 +230,7 @@ extern void bttv_field_count(struct bttv /* our devices */ #define BTTV_MAX 4 -extern int bttv_num; +extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; #define BTTV_MAX_FBUF 0x208000 @@ -263,8 +257,9 @@ struct bttv { unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ char name[8]; /* dev name */ unsigned int cardid; /* pci subsystem id (bt878 based ones) */ - int type; /* card type (pointer into tvcards[]) */ - int tuner_type; /* tuner chip type */ + unsigned int type; /* card type (pointer into tvcards[]) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int pinnacle_id; struct bttv_pll_info pll; int triton1; @@ -291,12 +286,12 @@ struct bttv { struct semaphore reslock; /* video state */ - int input; - int audio; + unsigned int input; + unsigned int audio; unsigned long freq; int tvnorm,hue,contrast,bright,saturation; struct video_buffer fbuf; - int field_count; + unsigned int field_count; /* various options */ int opt_combfilter; @@ -325,21 +320,19 @@ struct bttv { /* risc memory management data - must aquire s_lock before changing these - - only the irq handler is supported to touch odd + even */ - struct bttv_riscmem main; - struct bttv_buffer *top; /* current active top field */ - struct bttv_buffer *bottom; /* current active bottom field */ - struct bttv_buffer *screen; /* overlay */ - struct list_head capture; /* capture buffer queue */ - struct bttv_buffer *vcurr; - struct list_head vcapture; + - only the irq handler is supported to touch top + bottom + vcurr */ + struct btcx_riscmem main; + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* video capture queue */ + struct list_head vcapture; /* vbi capture queue */ + struct bttv_buffer_set curr; /* active buffers */ unsigned long cap_ctl; unsigned long dma_on; struct timer_list timeout; - int errors; + unsigned int errors; - int users; + unsigned int users; struct bttv_fh init; }; diff -puN drivers/media/video/bttv-risc.c~v4l-3 drivers/media/video/bttv-risc.c --- 25/drivers/media/video/bttv-risc.c~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv-risc.c 2003-05-17 14:09:42.000000000 -0700 @@ -35,58 +35,24 @@ #include "bttvp.h" /* ---------------------------------------------------------- */ -/* allocate/free risc memory */ - -int bttv_riscmem_alloc(struct pci_dev *pci, - struct bttv_riscmem *risc, - unsigned int size) -{ - u32 *cpu; - dma_addr_t dma; - - cpu = pci_alloc_consistent(pci, size, &dma); - if (NULL == cpu) - return -ENOMEM; - memset(cpu,0,size); - - if (risc->cpu && risc->size < size) { - /* realloc (enlarge buffer) -- copy old stuff */ - memcpy(cpu,risc->cpu,risc->size); - bttv_riscmem_free(pci,risc); - } - risc->cpu = cpu; - risc->dma = dma; - risc->size = size; - - return 0; -} - -void bttv_riscmem_free(struct pci_dev *pci, - struct bttv_riscmem *risc) -{ - if (NULL == risc->cpu) - return; - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); - memset(risc,0,sizeof(*risc)); -} - -/* ---------------------------------------------------------- */ /* risc code generators */ int -bttv_risc_packed(struct bttv *btv, struct bttv_riscmem *risc, +bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, - int offset, int bpl, int padding, int lines) + unsigned int offset, unsigned int bpl, + unsigned int padding, unsigned int lines) { - int instructions,rc,line,todo; + u32 instructions,line,todo; struct scatterlist *sg; u32 *rp; + int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + sync + jump (all 2 dwords) */ instructions = (bpl * lines) / PAGE_SIZE + lines; instructions += 2; - if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) return rc; /* sync instruction */ @@ -130,6 +96,7 @@ bttv_risc_packed(struct bttv *btv, struc } offset += padding; } + dprintk("bttv%d: risc planar: %d sglist elems\n", btv->nr, (int)(sg-sglist)); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -137,24 +104,27 @@ bttv_risc_packed(struct bttv *btv, struc } int -bttv_risc_planar(struct bttv *btv, struct bttv_riscmem *risc, +bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, struct scatterlist *sglist, - int yoffset, int ybpl, int ypadding, int ylines, - int uoffset, int voffset, int hshift, int vshift, - int cpadding) + unsigned int yoffset, unsigned int ybpl, + unsigned int ypadding, unsigned int ylines, + unsigned int uoffset, unsigned int voffset, + unsigned int hshift, unsigned int vshift, + unsigned int cpadding) { - int instructions,rc,line,todo,ylen,chroma; + unsigned int instructions,line,todo,ylen,chroma; u32 *rp,ri; struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; + int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line (5 dwords) plus sync + jump (2 dwords) */ instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines; instructions += 2; - if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0) + if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*4*5)) < 0) return rc; /* sync instruction */ @@ -231,138 +201,13 @@ bttv_risc_planar(struct bttv *btv, struc return 0; } -/* ---------------------------------------------------------- */ - -struct SKIPLIST { - int start; - int end; -}; - int -bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win, - struct v4l2_clip *clips, int n) -{ - if (win->left < 0) { - /* left */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = -win->left; - clips[n].c.height = win->height; - n++; - } - if (win->left + win->width > swidth) { - /* right */ - clips[n].c.left = swidth - win->left; - clips[n].c.top = 0; - clips[n].c.width = win->width - clips[n].c.left; - clips[n].c.height = win->height; - n++; - } - if (win->top < 0) { - /* top */ - clips[n].c.left = 0; - clips[n].c.top = 0; - clips[n].c.width = win->width; - clips[n].c.height = -win->top; - n++; - } - if (win->top + win->height > sheight) { - /* bottom */ - clips[n].c.left = 0; - clips[n].c.top = sheight - win->top; - clips[n].c.width = win->width; - clips[n].c.height = win->height - clips[n].c.top; - n++; - } - return n; -} - -void -bttv_sort_clips(struct v4l2_clip *clips, int nclips) -{ - struct v4l2_clip swap; - int i,j,n; - - for (i = nclips-2; i >= 0; i--) { - for (n = 0, j = 0; j <= i; j++) { - if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; - n++; - } - } - if (0 == n) - break; - } -} - -static void -calc_skips(int line, int width, int *maxy, - struct SKIPLIST *skips, int *nskips, - const struct v4l2_clip *clips, int nclips) -{ - int clip,skip,maxline,end; - - skip=0; - maxline = 9999; - for (clip = 0; clip < nclips; clip++) { - - /* sanity checks */ - if (clips[clip].c.left + clips[clip].c.width <= 0) - continue; - if (clips[clip].c.left > width) - break; - - /* vertical range */ - if (line > clips[clip].c.top+clips[clip].c.height-1) - continue; - if (line < clips[clip].c.top) { - if (maxline > clips[clip].c.top-1) - maxline = clips[clip].c.top-1; - continue; - } - if (maxline > clips[clip].c.top+clips[clip].c.height-1) - maxline = clips[clip].c.top+clips[clip].c.height-1; - - /* horizontal range */ - if (0 == skip || clips[clip].c.left > skips[skip-1].end) { - /* new one */ - skips[skip].start = clips[clip].c.left; - if (skips[skip].start < 0) - skips[skip].start = 0; - skips[skip].end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip].end > width) - skips[skip].end = width; - skip++; - } else { - /* overlaps -- expand last one */ - end = clips[clip].c.left + clips[clip].c.width; - if (skips[skip-1].end < end) - skips[skip-1].end = end; - if (skips[skip-1].end > width) - skips[skip-1].end = width; - } - } - *nskips = skip; - *maxy = maxline; - - if (bttv_debug) { - printk(KERN_DEBUG "bttv: skips line %d-%d:",line,maxline); - for (skip = 0; skip < *nskips; skip++) { - printk(" %d-%d",skips[skip].start,skips[skip].end); - } - printk("\n"); - } -} - -int -bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc, +bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int skip_even, int skip_odd) { int instructions,rc,line,maxy,start,end,skip,nskips; - struct SKIPLIST *skips; + struct btcx_skiplist *skips; u32 *rp,ri,ra; u32 addr; @@ -375,7 +220,7 @@ bttv_risc_overlay(struct bttv *btv, stru instructions = (ov->nclips + 1) * ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height); instructions += 2; - if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) + if ((rc = btcx_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) return rc; /* sync instruction */ @@ -397,8 +242,8 @@ bttv_risc_overlay(struct bttv *btv, stru /* calculate clipping */ if (line > maxy) - calc_skips(line, ov->w.width, &maxy, - skips, &nskips, ov->clips, ov->nclips); + btcx_calc_skips(line, ov->w.width, &maxy, + skips, &nskips, ov->clips, ov->nclips); /* write out risc code */ for (start = 0, skip = 0; start < ov->w.width; start = end) { @@ -432,7 +277,6 @@ bttv_risc_overlay(struct bttv *btv, stru /* save pointer to jmp instruction address */ risc->jmp = rp; - kfree(skips); return 0; } @@ -476,6 +320,7 @@ bttv_calc_geo(struct bttv *btv, struct b geo->vdelay = vdelay; geo->width = width; geo->sheight = tvnorm->sheight; + geo->vtotal = tvnorm->vtotal; if (btv->opt_combfilter) { geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); @@ -506,6 +351,8 @@ bttv_apply_geo(struct bttv *btv, struct btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off); btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off); btwrite(geo->crop, BT848_E_CROP+off); + btwrite(geo->vtotal>>8, BT848_VTOTAL_HI); + btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO); } /* ---------------------------------------------------------- */ @@ -518,9 +365,9 @@ bttv_set_dma(struct bttv *btv, int overr int capctl; btv->cap_ctl = 0; - if (NULL != btv->top) btv->cap_ctl |= 0x02; - if (NULL != btv->bottom) btv->cap_ctl |= 0x01; - if (NULL != btv->vcurr) btv->cap_ctl |= 0x0c; + if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; + if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; + if (NULL != btv->curr.vbi) btv->cap_ctl |= 0x0c; capctl = 0; capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ @@ -530,14 +377,16 @@ bttv_set_dma(struct bttv *btv, int overr d2printk(KERN_DEBUG "bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", btv->nr,capctl,irqflags, - btv->vcurr ? (u64)btv->vcurr->top.dma : 0, - btv->top ? (u64)btv->top->top.dma : 0, - btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0, - btv->bottom ? (u64)btv->bottom->bottom.dma : 0); + btv->curr.vbi ? (u64)btv->curr.vbi->top.dma : 0, + btv->curr.top ? (u64)btv->curr.top->top.dma : 0, + btv->curr.vbi ? (u64)btv->curr.vbi->bottom.dma : 0, + btv->curr.bottom ? (u64)btv->curr.bottom->bottom.dma : 0); cmd = BT848_RISC_JUMP; if (irqflags) { - cmd |= BT848_RISC_IRQ | (irqflags << 16); + cmd |= BT848_RISC_IRQ; + cmd |= (irqflags & 0x0f) << 16; + cmd |= (~irqflags & 0x0f) << 20; mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); } else { del_timer(&btv->timeout); @@ -565,7 +414,7 @@ bttv_risc_init_main(struct bttv *btv) { int rc; - if ((rc = bttv_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0) + if ((rc = btcx_riscmem_alloc(btv->dev,&btv->main,PAGE_SIZE)) < 0) return rc; dprintk(KERN_DEBUG "bttv%d: risc main @ %08Lx\n", btv->nr,(u64)btv->main.dma); @@ -600,7 +449,7 @@ bttv_risc_init_main(struct bttv *btv) } int -bttv_risc_hook(struct bttv *btv, int slot, struct bttv_riscmem *risc, +bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, int irqflags) { unsigned long cmd; @@ -614,8 +463,11 @@ bttv_risc_hook(struct bttv *btv, int slo d2printk(KERN_DEBUG "bttv%d: risc=%p slot[%d]=%08Lx irq=%d\n", btv->nr,risc,slot,(u64)risc->dma,irqflags); cmd = BT848_RISC_JUMP; - if (irqflags) - cmd |= BT848_RISC_IRQ | (irqflags << 16); + if (irqflags) { + cmd |= BT848_RISC_IRQ; + cmd |= (irqflags & 0x0f) << 16; + cmd |= (~irqflags & 0x0f) << 20; + } risc->jmp[0] = cpu_to_le32(cmd); risc->jmp[1] = cpu_to_le32(next); btv->main.cpu[slot+1] = cpu_to_le32(risc->dma); @@ -631,43 +483,68 @@ bttv_dma_free(struct bttv *btv, struct b videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); - bttv_riscmem_free(btv->dev,&buf->bottom); - bttv_riscmem_free(btv->dev,&buf->top); + btcx_riscmem_free(btv->dev,&buf->bottom); + btcx_riscmem_free(btv->dev,&buf->top); buf->vb.state = STATE_NEEDS_INIT; } int -bttv_buffer_activate(struct bttv *btv, - struct bttv_buffer *top, - struct bttv_buffer *bottom) -{ - if (NULL != top && NULL != bottom) { - top->vb.state = STATE_ACTIVE; - bottom->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &top->geo, 1); - bttv_apply_geo(btv, &bottom->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0); - btaor((top->btformat & 0xf0) | (bottom->btformat & 0x0f), +bttv_buffer_set_activate(struct bttv *btv, + struct bttv_buffer_set *set) +{ + /* vbi capture */ + if (set->vbi) { + set->vbi->vb.state = STATE_ACTIVE; + list_del(&set->vbi->vb.queue); + bttv_risc_hook(btv, RISC_SLOT_O_VBI, &set->vbi->top, 0); + bttv_risc_hook(btv, RISC_SLOT_E_VBI, &set->vbi->bottom, 0); + } else { + bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0); + bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0); + } + + /* video capture */ + if (NULL != set->top && NULL != set->bottom) { + if (set->top == set->bottom) { + set->top->vb.state = STATE_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + } else { + set->top->vb.state = STATE_ACTIVE; + set->bottom->vb.state = STATE_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + if (set->bottom->vb.queue.next) + list_del(&set->bottom->vb.queue); + } + bttv_apply_geo(btv, &set->top->geo, 1); + bttv_apply_geo(btv, &set->bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, set->topirq); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0); + btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), ~0xff, BT848_COLOR_FMT); - btaor((top->btswap & 0x0a) | (bottom->btswap & 0x05), + btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); - } else if (NULL != top) { - top->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &top->geo,1); - bttv_apply_geo(btv, &top->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); - btaor(top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); - } else if (NULL != bottom) { - bottom->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &bottom->geo,1); - bttv_apply_geo(btv, &bottom->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0); - btaor(bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + } else if (NULL != set->top) { + set->top->vb.state = STATE_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + bttv_apply_geo(btv, &set->top->geo,1); + bttv_apply_geo(btv, &set->top->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &set->top->top, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); + btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + } else if (NULL != set->bottom) { + set->bottom->vb.state = STATE_ACTIVE; + if (set->bottom->vb.queue.next) + list_del(&set->bottom->vb.queue); + bttv_apply_geo(btv, &set->bottom->geo,1); + bttv_apply_geo(btv, &set->bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, 0); + btaor(set->bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(set->bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else { bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); @@ -734,12 +611,12 @@ bttv_buffer_risc(struct bttv *btv, struc /* Y-Cr-Cb plane order */ uoffset >>= buf->fmt->hshift; uoffset >>= buf->fmt->vshift; - uoffset += voffset; + uoffset += voffset; } else { /* Y-Cb-Cr plane order */ voffset >>= buf->fmt->hshift; voffset >>= buf->fmt->vshift; - voffset += uoffset; + voffset += uoffset; } switch (buf->vb.field) { @@ -781,6 +658,29 @@ bttv_buffer_risc(struct bttv *btv, struc buf->fmt->vshift, cpadding); break; + case V4L2_FIELD_SEQ_TB: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,1,buf->tvnorm); + lines = buf->vb.height >> 1; + ypadding = buf->vb.width; + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, + buf->vb.dma.sglist, + 0,buf->vb.width,0,lines, + uoffset >> 1, + voffset >> 1, + buf->fmt->hshift, + buf->fmt->vshift, + 0); + bttv_risc_planar(btv,&buf->bottom, + buf->vb.dma.sglist, + lines * ypadding,buf->vb.width,0,lines, + lines * ypadding + (uoffset >> 1), + lines * ypadding + (voffset >> 1), + buf->fmt->hshift, + buf->fmt->vshift, + 0); + break; default: BUG(); } diff -puN drivers/media/video/bttv-vbi.c~v4l-3 drivers/media/video/bttv-vbi.c --- 25/drivers/media/video/bttv-vbi.c~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/bttv-vbi.c 2003-05-17 14:09:42.000000000 -0700 @@ -63,7 +63,7 @@ vbi_buffer_risc(struct bttv *btv, struct } static int vbi_buffer_setup(struct file *file, - unsigned int *count, unsigned int *size) + unsigned int *count, unsigned int *size) { struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; @@ -155,7 +155,43 @@ void bttv_vbi_setlines(struct bttv_fh *f } } -void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f) +void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f) +{ + u32 start0,start1,count0,count1,count; + + f->type = V4L2_BUF_TYPE_VBI_CAPTURE; + f->fmt.vbi.sampling_rate = 35468950; + f->fmt.vbi.samples_per_line = 2048; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 244; + f->fmt.vbi.flags = 0; + switch (fh->btv->tvnorm) { + case 1: /* NTSC */ + start0 = 10; + start1 = 273; + break; + case 0: /* PAL */ + case 2: /* SECAM */ + default: + start0 = 7; + start1 = 319; + } + + count0 = (f->fmt.vbi.start[0] + f->fmt.vbi.count[0]) - start0; + count1 = (f->fmt.vbi.start[1] + f->fmt.vbi.count[1]) - start1; + count = max(count0,count1); + if (count > VBI_MAXLINES) + count = VBI_MAXLINES; + if (count < 1) + count = 1; + + f->fmt.vbi.start[0] = start0; + f->fmt.vbi.start[1] = start1; + f->fmt.vbi.count[0] = count; + f->fmt.vbi.count[1] = count; +} + +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f) { memset(f,0,sizeof(*f)); f->type = V4L2_BUF_TYPE_VBI_CAPTURE; diff -puN drivers/media/video/Makefile~v4l-3 drivers/media/video/Makefile --- 25/drivers/media/video/Makefile~v4l-3 2003-05-17 14:09:42.000000000 -0700 +++ 25-akpm/drivers/media/video/Makefile 2003-05-17 14:09:42.000000000 -0700 @@ -36,4 +36,5 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o obj-$(CONFIG_VIDEO_BUF) += video-buf.o +obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o _