From: Mauro Carvalho Chehab Date: Tue, 14 Aug 2012 14:49:09 +0000 (-0300) Subject: [media] bt8xx: move analog TV part to be together with DTV one X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=68de959f773a1d49096835c411390bceff5d1549;p=openwrt%2Fstaging%2Fblogic.git [media] bt8xx: move analog TV part to be together with DTV one Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index 8668e634c7ec..f2667a5cc144 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -1,5 +1,26 @@ +config VIDEO_BT848 + tristate "BT848 Video For Linux" + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEO_BTCX + select VIDEOBUF_DMA_SG + depends on RC_CORE + select VIDEO_TUNER + select VIDEO_TVEEPROM + select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO + ---help--- + Support for BT848 based frame grabber/overlay boards. This includes + the Miro, Hauppauge and STB boards. Please read the material in + for more information. + + To compile this driver as a module, choose M here: the + module will be called bttv. + config DVB_BT8XX - tristate "BT8xx based PCI cards" + tristate "DVB/ATSC Support for bt878 based TV cards" depends on DVB_CORE && PCI && I2C && VIDEO_BT848 select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_SP887X if !DVB_FE_CUSTOMISE diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile index c008d0c135d6..ae347b78fccf 100644 --- a/drivers/media/pci/bt8xx/Makefile +++ b/drivers/media/pci/bt8xx/Makefile @@ -1,6 +1,11 @@ +bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ + bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ + bttv-input.o bttv-audio-hook.o + +obj-$(CONFIG_VIDEO_BT848) += bttv.o obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/video/bt8xx +ccflags-y += -Idrivers/media/video ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/bt8xx/bt848.h b/drivers/media/pci/bt8xx/bt848.h new file mode 100644 index 000000000000..c37e6acffded --- /dev/null +++ b/drivers/media/pci/bt8xx/bt848.h @@ -0,0 +1,369 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_FUSION879 +#define PCI_DEVICE_ID_FUSION879 0x36c +#endif + +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_PLOCK (1<<2) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_NTSC_J 2 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_PAL_NC 7 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (3<<3) + + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_WC_UP 0x044 +#define BT848_WC_DOWN 0x078 + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#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) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT878_I2C_MODE (1<<7) +#define BT878_I2C_RATE (1<<6) +#define BT878_I2C_NOSTOP (1<<5) +#define BT878_I2C_NOSTART (1<<4) +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#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 (1U<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1U<<26) +/* RISC command is first one in this line */ +#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 !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c new file mode 100644 index 000000000000..2364d16586b3 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -0,0 +1,382 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttv-audio-hook.h" + +#include + +/* ----------------------------------------------------------------------- */ +/* winview */ + +void winview_volume(struct bttv *btv, __u16 volume) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x300; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x200; +/* if (t->audmode & V4L2_TUNER_MODE_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) { + if (t->audmode & V4L2_TUNER_MODE_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x30: + t->rxsubchans = V4L2_TUNER_SUB_LANG2; + break; + case 0x50: + t->rxsubchans = V4L2_TUNER_SUB_LANG1; + break; + case 0x60: + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 0x70: + t->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + default: + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + } + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Mario Medina Nussbaum + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ + +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x02; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1; + return; + } +} + + +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x01; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + t->audmode = V4L2_TUNER_MODE_MONO; + return; + } + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ + val = 0x0080; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ + val = 0x0880; + if ((t->audmode & V4L2_TUNER_MODE_LANG1) || + (t->audmode & V4L2_TUNER_MODE_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x080000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + + +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x410000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x01; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x0000; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) + val = 0x040000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) + val = 0; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + val = 0x100000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (t->audmode & V4L2_TUNER_MODE_LANG1) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x00180000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h new file mode 100644 index 000000000000..159d07adeff8 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h @@ -0,0 +1,23 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttvp.h" + +void winview_volume (struct bttv *btv, __u16 volume); + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); + diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c new file mode 100644 index 000000000000..38952faaffda --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -0,0 +1,4895 @@ +/* + + bttv-cards.c + + this file has configuration informations - card-specific stuff + like the big tvcards array for the most part + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2001 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bttvp.h" +#include +#include +#include "bttv-audio-hook.h" + +/* fwd decl */ +static void boot_msp34xx(struct bttv *btv, int pin); +static void hauppauge_eeprom(struct bttv *btv); +static void avermedia_eeprom(struct bttv *btv); +static void osprey_eeprom(struct bttv *btv, const u8 ee[256]); +static void modtec_eeprom(struct bttv *btv); +static void init_PXC200(struct bttv *btv); +static void init_RTV24(struct bttv *btv); + +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 void ivc120_muxsel(struct bttv *btv, unsigned int input); +static void gvc1100_muxsel(struct bttv *btv, unsigned int input); + +static void PXC200_muxsel(struct bttv *btv, unsigned int input); + +static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); +static void picolo_tetra_init(struct bttv *btv); + +static void tibetCS16_muxsel(struct bttv *btv, unsigned int input); +static void tibetCS16_init(struct bttv *btv); + +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input); +static void kodicom4400r_init(struct bttv *btv); + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); + +static void geovision_muxsel(struct bttv *btv, unsigned int input); + +static void phytec_muxsel(struct bttv *btv, unsigned int input); + +static void gv800s_muxsel(struct bttv *btv, unsigned int input); +static void gv800s_init(struct bttv *btv); + +static void td3116_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); +static void identify_by_eeprom(struct bttv *btv, + unsigned char eeprom_data[256]); +static int __devinit pvr_boot(struct bttv *btv); + +/* config variables */ +static unsigned int triton1; +static unsigned int vsfx; +static unsigned int latency = UNSET; +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 }; +static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; +static unsigned int audiodev[BTTV_MAX]; +static unsigned int saa6588[BTTV_MAX]; +static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL }; +static unsigned int autoload = UNSET; +static unsigned int gpiomask = UNSET; +static unsigned int audioall = UNSET; +static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET }; + +/* insmod options */ +module_param(triton1, int, 0444); +module_param(vsfx, int, 0444); +module_param(no_overlay, int, 0444); +module_param(latency, int, 0444); +module_param(gpiomask, int, 0444); +module_param(audioall, int, 0444); +module_param(autoload, int, 0444); + +module_param_array(card, int, NULL, 0444); +module_param_array(pll, int, NULL, 0444); +module_param_array(tuner, int, NULL, 0444); +module_param_array(svhs, int, NULL, 0444); +module_param_array(remote, int, NULL, 0444); +module_param_array(audiodev, int, NULL, 0444); +module_param_array(audiomux, int, NULL, 0444); + +MODULE_PARM_DESC(triton1,"set ETBF pci config bit " + "[enable bug compatibility for triton1 + others]"); +MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " + "[yet another chipset flaw workaround]"); +MODULE_PARM_DESC(latency,"pci latency timer"); +MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); +MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); +MODULE_PARM_DESC(tuner,"specify installed tuner type"); +MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore"); +MODULE_PARM_DESC(audiodev, "specify audio device:\n" + "\t\t-1 = no audio\n" + "\t\t 0 = autodetect (default)\n" + "\t\t 1 = msp3400\n" + "\t\t 2 = tda7432\n" + "\t\t 3 = tvaudio"); +MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); + +/* ----------------------------------------------------------------------- */ +/* list of card IDs for bt878+ cards */ + +static struct CARD { + unsigned id; + int cardnr; + char *name; +} cards[] __devinitdata = { + { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" }, + { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" }, + { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" }, + { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" }, + { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" }, + { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" }, + { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" }, + { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" }, + { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" }, + + { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" }, + { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, + + { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" }, + { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" }, + { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, + { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, + { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, + { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, + { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, + { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, + + { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, + /* some cards ship with byteswapped IDs ... */ + { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, + { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, + /* this seems to happen as well ... */ + { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, + + { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" }, + { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" }, + { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" }, + + { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, + { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" }, + { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, + { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, + { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" }, + { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" }, + { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, + + { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" }, + { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, + { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" }, + { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" }, + + { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" }, + { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" }, + { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" }, + { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" }, + + { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" }, + { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" }, + /* clashes with FlyVideo + *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */ + { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" }, + { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ + { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */ + { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ + + { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, + { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, + + { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" }, + { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" }, + { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" }, + { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" }, + { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" }, + + { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" }, + { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" }, + { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" }, + { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" }, + + { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" }, + { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" }, + { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" }, + { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" }, + + { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" }, + { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" }, + { 0xa1550800, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550801, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550802, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa1550803, BTTV_BOARD_IVC200, "IVC-200" }, + { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" }, + { 0xf0500000, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500001, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500002, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + { 0xf0500003, BTTV_BOARD_IVCE8784, "IVCE-8784" }, + + { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" }, + { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" }, + + { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, + { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, + { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, + { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, + { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" }, + + { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" }, + { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" }, + + { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, + { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, + { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" }, + { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" }, + { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, + { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, + { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, + { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" }, + { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" }, + + { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" }, + { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" }, + + { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" }, + { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" }, + { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, + { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, + + { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, + + { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, + { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, + + /* likely broken, vendor id doesn't match the other magic views ... + * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ + + /* Duplicate PCI ID, reconfigure for this board during the eeprom read. + * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ + + { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"}, + + /* DVB cards (using pci function .1 for mpeg data xfer) */ + { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, + { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, + { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, + { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, + { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, + { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, + { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, + { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, + { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, + { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, + { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, + { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, + { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, + { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, + { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" }, + { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, + + { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" }, + { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" }, + { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" }, + { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" }, + { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" }, + { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, + { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, + { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, + { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" }, + { 0x02280279, BTTV_BOARD_APOSONIC_WDVR, "Aposonic W-DVR" }, + { 0, -1, NULL } +}; + +/* ----------------------------------------------------------------------- */ +/* array with description for bt848 / bt878 tv/grabber cards */ + +struct tvcard bttv_tvcards[] = { + /* ---- card 0x00 ---------------------------------- */ + [BTTV_BOARD_UNKNOWN] = { + .name = " *** UNKNOWN/GENERIC *** ", + .video_inputs = 4, + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MIRO] = { + .name = "MIRO PCTV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_HAUPPAUGE] = { + .name = "Hauppauge (bt848)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_STB] = { + .name = "STB, Gateway P/N 6000699 (bt848)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 4, 0, 2, 3 }, + .gpiomute = 1, + .no_msp34xx = 1, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + + /* ---- card 0x04 ---------------------------------- */ + [BTTV_BOARD_INTEL] = { + .name = "Intel Create and Share PCI/ Smart Video Recorder III", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_DIAMOND] = { + .name = "Diamond DTV2000", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0, 1, 0, 1 }, + .gpiomute = 3, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AVERMEDIA] = { + .name = "AVerMedia TVPhone", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomask = 0x0f, + .gpiomux = { 0x0c, 0x04, 0x08, 0x04 }, + /* 0x04 for some cards ?? */ + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= avermedia_tvphone_audio, + .has_remote = 1, + }, + [BTTV_BOARD_MATRIX_VISION] = { + .name = "MATRIX-Vision MV-Delta", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x08 ---------------------------------- */ + [BTTV_BOARD_FLYVIDEO] = { + .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xc00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0xc00, 0x800, 0x400 }, + .gpiomute = 0xc00, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TURBOTV] = { + .name = "IMS/IXmicro TurboTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 2, 3 }, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_HAUPPAUGE878] = { + .name = "Hauppauge (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0f, /* old: 7 */ + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MIROPRO] = { + .name = "MIRO PCTV pro", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x0c ---------------------------------- */ + [BTTV_BOARD_ADSTECH_TV] = { + .name = "ADS Technologies Channel Surfer TV (bt848)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 14, 11, 7 }, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AVERMEDIA98] = { + .name = "AVerMedia TVCapture 98", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 14, 11, 7 }, + .msp34xx_alt = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= avermedia_tv_stereo_audio, + .no_gpioirq = 1, + }, + [BTTV_BOARD_VHX] = { + .name = "Aimslab Video Highway Xtreme (VHX)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */ + .gpiomute = 4, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ZOLTRIX] = { + .name = "Zoltrix TV-Max", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 1, 0 }, + .gpiomute = 10, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x10 ---------------------------------- */ + [BTTV_BOARD_PIXVIEWPLAYTV] = { + .name = "Prolink Pixelview PlayTV (bt878)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1), + /* 2003-10-20 by "Anton A. Arapov" */ + .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, + .gpiomute = 0x002000, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_WINVIEW_601] = { + .name = "Leadtek WinView 601", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x8300f8, + .muxsel = MUXSEL(2, 3, 1, 1, 0), + .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 }, + .gpiomute = 0xcfa007, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .volume_gpio = winview_volume, + .has_radio = 1, + }, + [BTTV_BOARD_AVEC_INTERCAP] = { + .name = "AVEC Intercapture", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0, 0, 0 }, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_LIFE_FLYKIT] = { + .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x8dff00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x14 ---------------------------------- */ + [BTTV_BOARD_CEI_RAFFLES] = { + .name = "CEI Raffles Card", + .video_inputs = 3, + /* .audio_inputs= 3, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 1), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_CONFERENCETV] = { + .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", + .video_inputs = 4, + /* .audio_inputs= 2, tuner, line in */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_PHOEBE_TVMAS] = { + .name = "Askey CPH050/ Phoebe Tv Master + FM", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xc00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 0x800, 0x400 }, + .gpiomute = 0xc00, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MODTEC_205] = { + .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .has_dig_in = 1, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 0), /* input 2 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0, 0, 0, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ALPS_TSBB5_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x18 ---------------------------------- */ + [BTTV_BOARD_MAGICTVIEW061] = { + .name = "Askey CPH05X/06X (bt878) [many vendors]", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = {0x400, 0x400, 0x400, 0x400 }, + .gpiomute = 0xc00, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, /* not every card has radio */ + }, + [BTTV_BOARD_VOBIS_BOOSTAR] = { + .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1f0fff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, + .gpiomute = 0x40000, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= terratv_audio, + }, + [BTTV_BOARD_HAUPPAUG_WCAM] = { + .name = "Hauppauge WinCam newer (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 7, + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MAXI] = { + .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", + .video_inputs = 4, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_SECAM, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x1c ---------------------------------- */ + [BTTV_BOARD_TERRATV] = { + .name = "Terratec TerraTV+ Version 1.1 (bt878)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1f0fff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0x00000 }, + .gpiomute = 0x40000, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= terratv_audio, + /* GPIO wiring: + External 20 pin connector (for Active Radio Upgrade board) + gpio00: i2c-sda + gpio01: i2c-scl + gpio02: om5610-data + gpio03: om5610-clk + gpio04: om5610-wre + gpio05: om5610-stereo + gpio06: rds6588-davn + gpio07: Pin 7 n.c. + gpio08: nIOW + gpio09+10: nIOR, nSEL ?? (bt878) + gpio09: nIOR (bt848) + gpio10: nSEL (bt848) + Sound Routing: + gpio16: u2-A0 (1st 4052bt) + gpio17: u2-A1 + gpio18: u2-nEN + gpio19: u4-A0 (2nd 4052) + gpio20: u4-A1 + u4-nEN - GND + Btspy: + 00000 : Cdrom (internal audio input) + 10000 : ext. Video audio input + 20000 : TV Mono + a0000 : TV Mono/2 + 1a0000 : TV Stereo + 30000 : Radio + 40000 : Mute + */ + + }, + [BTTV_BOARD_PXC200] = { + /* Jannik Fritsch */ + .name = "Imagenation PXC200", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 1, /* was: 4 */ + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = PXC200_muxsel, + + }, + [BTTV_BOARD_FLYVIDEO_98] = { + .name = "Lifeview FlyVideo 98 LR50", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x1800, /* 0x8dfe00 */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x0800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_IPROTV] = { + .name = "Formac iProTV, Formac ProTV I (bt848)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 1, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0, 0, 0 }, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x20 ---------------------------------- */ + [BTTV_BOARD_INTEL_C_S_PCI] = { + .name = "Intel Create and Share PCI/ Smart Video Recorder III", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0 }, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TERRATVALUE] = { + .name = "Terratec TerraTValue Version Bt878", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xffff00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x500, 0, 0x300, 0x900 }, + .gpiomute = 0x900, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_WINFAST2000] = { + .name = "Leadtek WinFast 2000/ WinFast 2000 XP", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + /* TV, CVid, SVid, CVid over SVid connector */ + .muxsel = MUXSEL(2, 3, 1, 1, 0), + /* Alexander Varakin [stereo version] */ + .gpiomask = 0xb33000, + .gpiomux = { 0x122000,0x1000,0x0000,0x620000 }, + .gpiomute = 0x800000, + /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) + gpio23 -- hef4052:nEnable (0x800000) + gpio12 -- hef4052:A1 + gpio13 -- hef4052:A0 + 0x0000: external audio + 0x1000: FM + 0x2000: TV + 0x3000: n.c. + Note: There exists another variant "Winfast 2000" with tv stereo !? + Note: eeprom only contains FF and pci subsystem id 107d:6606 + */ + .pll = PLL_28, + .has_radio = 1, + .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= winfast2000_audio, + .has_remote = 1, + }, + [BTTV_BOARD_CHRONOS_VS2] = { + .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x24 ---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVIEW] = { + .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1800, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, + .gpiomute = 0x1800, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + [BTTV_BOARD_PXELVWPLTVPRO] = { + .name = "Prolink PixelView PlayTV pro", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xff, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, + .gpiomute = 0x29, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MAGICTVIEW063] = { + .name = "Askey CPH06X TView99", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x551e00, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0x551400, 0x551200, 0, 0 }, + .gpiomute = 0x551c00, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + [BTTV_BOARD_PINNACLE] = { + .name = "Pinnacle PCTV Studio/Rave", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0xd0001, 0, 0 }, + .gpiomute = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x28 ---------------------------------- */ + [BTTV_BOARD_STB2] = { + .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 4, 0, 2, 3 }, + .gpiomute = 1, + .no_msp34xx = 1, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_AVPHONE98] = { + .name = "AVerMedia TVPhone 98", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 13, 4, 11, 7 }, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .audio_mode_gpio= avermedia_tvphone_audio, + }, + [BTTV_BOARD_PV951] = { + .name = "ProVideo PV951", /* pic16c54 */ + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0, 0}, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ONAIR_TV] = { + .name = "Little OnAir TV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00b, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 }, + .gpiomute = 0xff3ffc, + .no_msp34xx = 1, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x2c ---------------------------------- */ + [BTTV_BOARD_SIGMA_TVII_FM] = { + .name = "Sigma TVII-FM", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 0, 2 }, + .gpiomute = 3, + .no_msp34xx = 1, + .pll = PLL_NONE, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MATRIX_VISION2] = { + .name = "MATRIX-Vision MV-Delta 2", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ZOLTRIX_GENIE] = { + .name = "Zoltrix Genie TV/FM", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xbcf03f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 }, + .gpiomute = 0xbcb03f, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4039FR5_NTSC, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TERRATVRADIO] = { + .name = "Terratec TV/Radio+", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x70000, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, + .gpiomute = 0x40000, + .no_msp34xx = 1, + .pll = PLL_35, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + + /* ---- card 0x30 ---------------------------------- */ + [BTTV_BOARD_DYNALINK] = { + .name = "Askey CPH03x/ Dynalink Magic TView", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = {2,0,0,0 }, + .gpiomute = 1, + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GVBCTV3PCI] = { + .name = "IODATA GV-BCTV3/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x010f00, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = {0x10000, 0, 0x10000, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ALPS_TSHC6_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv3pci_audio, + }, + [BTTV_BOARD_PXELVWPLTVPAK] = { + .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .has_dig_in = 1, + .gpiomask = 0xAA0000, + .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0x20000, 0, 0x80000, 0x80000 }, + .gpiomute = 0xa8000, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + /* GPIO wiring: (different from Rev.4C !) + GPIO17: U4.A0 (first hef4052bt) + GPIO19: U4.A1 + GPIO20: U5.A1 (second hef4052bt) + GPIO21: U4.nEN + GPIO22: BT832 Reset Line + GPIO23: A5,A0, U5,nEN + Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 + */ + }, + [BTTV_BOARD_EAGLE] = { + .name = "Eagle Wireless Capricorn2 (bt878A)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 0, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .pll = PLL_28, + .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x34 ---------------------------------- */ + [BTTV_BOARD_PINNACLEPRO] = { + /* David Härdeman */ + .name = "Pinnacle PCTV Studio Pro", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 0xd0001, 0, 0 }, + .gpiomute = 10, + /* sound path (5 sources): + MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) + 0= ext. Audio IN + 1= from MUX2 + 2= Mono TV sound from Tuner + 3= not connected + MUX2 (mask 0x30000): + 0,2,3= from MSP34xx + 1= FM stereo Radio from Tuner */ + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TVIEW_RDS_FM] = { + /* Claas Langbehn , + Sven Grothklags */ + .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 0x1c, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0x10, 8 }, + .gpiomute = 4, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + [BTTV_BOARD_LIFETEC_9415] = { + /* Tim Röstermundt + in de.comp.os.unix.linux.hardware: + options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 + gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff + options tuner type=5 */ + .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x18e0, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, + .gpiomute = 0x18e0, + /* For cards with tda9820/tda9821: + 0x0000: Tuner normal stereo + 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) + 0x0880: Tuner A2 stereo */ + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_BESTBUY_EASYTV] = { + /* Miguel Angel Alvarez + old Easy TV BT848 version (model CPH031) */ + .name = "Askey CPH031/ BESTBUY Easy TV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xF, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x38 ---------------------------------- */ + [BTTV_BOARD_FLYVIDEO_98FM] = { + /* Gordon Heydon */ + [BTTV_BOARD_GRANDTEC] = { + .name = "GrandTec 'Grand Video Capture' (Bt848)", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .gpiomask = 0, + .muxsel = MUXSEL(3, 1), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_35, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ASKEY_CPH060] = { + /* Daniel Herrington */ + .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x400, 0x400, 0x400, 0x400 }, + .gpiomute = 0x800, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4036FY5_NTSC, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ASKEY_CPH03X] = { + /* Matti Mottus */ + .name = "Askey CPH03x TV Capturer", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x03000F, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + + /* ---- card 0x3c ---------------------------------- */ + [BTTV_BOARD_MM100PCTV] = { + /* Philip Blundell */ + .name = "Modular Technology MM100PCTV", + .video_inputs = 2, + /* .audio_inputs= 2, */ + .svhs = NO_SVHS, + .gpiomask = 11, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 1 }, + .gpiomute = 8, + .pll = PLL_35, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GMV1] = { + /* Adrian Cox + new Easy TV BT878 version (model CPH061) + special thanks to Informatica Mieres for providing the card */ + .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0xFF, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 1, 0, 4, 4 }, + .gpiomute = 9, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_ATI_TVWONDER] = { + /* Lukas Gebauer */ + .name = "ATI TV-Wonder", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0xf03f, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0xbffe, 0, 0xbfff, 0 }, + .gpiomute = 0xbffe, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x40 ---------------------------------- */ + [BTTV_BOARD_ATI_TVWONDERVE] = { + /* Lukas Gebauer */ + .name = "ATI TV-Wonder VE", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 1, + .muxsel = MUXSEL(2, 3, 0, 1), + .gpiomux = { 0, 0, 1, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_FLYVIDEO2000] = { + /* DeeJay */ + .name = "IODATA GV-BCTV4/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x010f00, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = {0x10000, 0, 0x10000, 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv3pci_audio, + }, + + /* ---- card 0x44 ---------------------------------- */ + [BTTV_BOARD_VOODOOTV_FM] = { + .name = "3Dfx VoodooTV FM (Euro)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, + .gpiomute = 0x947fff, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = MUXSEL(2, 3, 0, 1), + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_VOODOOTV_200] = { + .name = "VoodooTV 200 (USA)", + /* try "insmod msp3400 simple=0" if you have + * sound problems with this card. */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0x4f8a00, + /* 0x100000: 1=MSP enabled (0=disable again) + * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ + .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, + .gpiomute = 0x947fff, + /* tvtuner, radio, external,internal, mute, stereo + * tuner, Composit, SVid, Composit-on-Svid-adapter */ + .muxsel = MUXSEL(2, 3, 0, 1), + .tuner_type = TUNER_MT2032, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + [BTTV_BOARD_AIMMS] = { + /* Philip Blundell */ + .name = "Active Imaging AIMMS", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = MUXSEL(2), + .gpiomask = 0 + }, + [BTTV_BOARD_PV_BT878P_PLUS] = { + /* Tomasz Pyra */ + .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", + .video_inputs = 3, + /* .audio_inputs= 4, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */ + .gpiomute = 13, + .pll = PLL_28, + .tuner_type = TUNER_LG_PAL_I_FM, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + /* GPIO wiring: + GPIO0: U4.A0 (hef4052bt) + GPIO1: U4.A1 + GPIO2: U4.A1 (second hef4052bt) + GPIO3: U4.nEN, U5.A0, A5.nEN + GPIO8-15: vrd866b ? + */ + }, + [BTTV_BOARD_FLYVIDEO98EZ] = { + .name = "Lifeview FlyVideo 98EZ (capture only) LR51", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 2, + /* AV1, AV2, SVHS, CVid adapter on SVHS */ + .muxsel = MUXSEL(2, 3, 1, 1), + .pll = PLL_28, + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x48 ---------------------------------- */ + [BTTV_BOARD_PV_BT878P_9B] = { + /* Dariusz Kowalewski */ + .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x01, 0x00, 0x03, 0x03 }, + .gpiomute = 0x09, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ + .has_radio = 1, /* Note: not all cards have radio */ + .has_remote = 1, + /* GPIO wiring: + GPIO0: A0 hef4052 + GPIO1: A1 hef4052 + GPIO3: nEN hef4052 + GPIO8-15: vrd866b + GPIO20,22,23: R30,R29,R28 + */ + }, + [BTTV_BOARD_SENSORAY311_611] = { + /* Clay Kunz */ + /* you must jumper JP5 for the 311 card (PC/104+) to work */ + .name = "Sensoray 311/611", + .video_inputs = 5, + /* .audio_inputs= 0, */ + .svhs = 4, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0, 0), + .gpiomux = { 0 }, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_RV605] = { + /* Miguel Freitas */ + .name = "RemoteVision MX (RV605)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x00, + .gpiomask2 = 0x07ff, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .no_msp34xx = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = rv605_muxsel, + }, + [BTTV_BOARD_POWERCLR_MTV878] = { + .name = "Powercolor MTV878/ MTV878R/ MTV878F", + .video_inputs = 3, + /* .audio_inputs= 2, */ + .svhs = 2, + .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ + .muxsel = MUXSEL(2, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 4, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + }, + + /* ---- card 0x4c ---------------------------------- */ + [BTTV_BOARD_WINDVR] = { + /* Masaki Suzuki */ + .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x140007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= windvr_audio, + }, + [BTTV_BOARD_GRANDTEC_MULTI] = { + .name = "GrandTec Multi Capture Card (Bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_KWORLD] = { + .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", + .video_inputs = 4, + /* .audio_inputs= 3, */ + .svhs = 2, + .gpiomask = 7, + /* Tuner, SVid, SVHS, SVid to SVHS connector */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio! + * This card lacks external Audio In, so we mute it on Ext. & Int. + * The PCB can take a sbx1637/sbx1673, wiring unknown. + * This card lacks PCI subsystem ID, sigh. + * gpiomux =1: lower volume, 2+3: mute + * btwincap uses 0x80000/0x80003 + */ + .gpiomute = 4, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and + radio signal strength indicators work fine. */ + .has_radio = 1, + /* GPIO Info: + GPIO0,1: HEF4052 A0,A1 + GPIO2: HEF4052 nENABLE + GPIO3-7: n.c. + GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card] + GPIO14,15: ?? + GPIO16-21: n.c. + GPIO22,23: ?? + ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ + }, + [BTTV_BOARD_DSP_TCVIDEO] = { + /* Arthur Tetzlaff-Deas, DSP Design Ltd */ + .name = "DSP Design TCVIDEO", + .video_inputs = 4, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x50 ---------------------------------- */ + [BTTV_BOARD_HAUPPAUGEPVR] = { + .name = "Hauppauge WinTV PVR", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 0, 1, 1), + .pll = PLL_28, + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + + .gpiomask = 7, + .gpiomux = {7}, + }, + [BTTV_BOARD_GVBCTV5PCI] = { + .name = "IODATA GV-BCTV5/PCI", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0f0f80, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = {0x030000, 0x010000, 0, 0 }, + .gpiomute = 0x020000, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= gvbctv5pci_audio, + .has_radio = 1, + }, + [BTTV_BOARD_OSPREY1x0] = { + .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ + .video_inputs = 4, /* id-inputs-clock */ + /* .audio_inputs= 0, */ + .svhs = 3, + .muxsel = MUXSEL(3, 2, 0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x0_848] = { + .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x54 ---------------------------------- */ + [BTTV_BOARD_OSPREY101_848] = { + .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(3, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x1] = { + .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ + .video_inputs = 1, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY1x1_SVID] = { + .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY2xx] = { + .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ + .video_inputs = 1, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x58 ---------------------------------- */ + [BTTV_BOARD_OSPREY2x0_SVID] = { + .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY2x0] = { + .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY500] = { + .name = "Osprey 500", /* 500 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + [BTTV_BOARD_OSPREY540] = { + .name = "Osprey 540", /* 540 */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + + /* ---- card 0x5C ---------------------------------- */ + [BTTV_BOARD_OSPREY2000] = { + .name = "Osprey 2000", /* 2000 */ + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = 1, + .muxsel = MUXSEL(2, 3), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ + }, + [BTTV_BOARD_IDS_EAGLE] = { + /* M G Berberich */ + .name = "IDS Eagle", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 2, 2, 2), + .muxsel_hook = eagle_muxsel, + .no_msp34xx = 1, + .pll = PLL_28, + }, + [BTTV_BOARD_PINNACLESAT] = { + .name = "Pinnacle PCTV Sat", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel = MUXSEL(3, 1), + .pll = PLL_28, + .no_gpioirq = 1, + .has_dvb = 1, + }, + [BTTV_BOARD_FORMAC_PROTV] = { + .name = "Formac ProTV II (bt878)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 3, + .gpiomask = 2, + /* TV, Comp1, Composite over SVID con, SVID */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 2, 0, 0 }, + .pll = PLL_28, + .has_radio = 1, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* sound routing: + GPIO=0x00,0x01,0x03: mute (?) + 0x02: both TV and radio (tuner: FM1216/I) + The card has onboard audio connectors labeled "cdrom" and "board", + not soldered here, though unknown wiring. + Card lacks: external audio in, pci subsystem id. + */ + }, + + /* ---- card 0x60 ---------------------------------- */ + [BTTV_BOARD_MACHTV] = { + .name = "MachTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3}, + .gpiomute = 4, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + [BTTV_BOARD_EURESYS_PICOLO] = { + .name = "Euresys Picolo", + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 2, + .gpiomask = 0, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel = MUXSEL(2, 0, 1), + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_PV150] = { + /* Luc Van Hoeylandt */ + .name = "ProVideo PV150", /* 0x4f */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_AD_TVK503] = { + /* Hiroshi Takekawa */ + /* This card lacks subsystem ID */ + .name = "AD-TVK503", /* 0x63 */ + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x001e8007, + .muxsel = MUXSEL(2, 3, 1, 0), + /* Tuner, Radio, external, internal, off, on */ + .gpiomux = { 0x08, 0x0f, 0x0a, 0x08 }, + .gpiomute = 0x0f, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .audio_mode_gpio= adtvk503_audio, + }, + + /* ---- card 0x64 ---------------------------------- */ + [BTTV_BOARD_HERCULES_SM_TV] = { + .name = "Hercules Smart TV Stereo", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 1), + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + /* 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 + */ + }, + [BTTV_BOARD_PACETV] = { + .name = "Pace TV & Radio Card", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + /* Tuner, CVid, SVid, CVid over SVid connector */ + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomask = 0, + .no_tda7432 = 1, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + .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! + */ + }, + [BTTV_BOARD_IVC200] = { + /* Chris Willing */ + .name = "IVC-200", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2), + .pll = PLL_28, + }, + [BTTV_BOARD_IVCE8784] = { + .name = "IVCE-8784", + .video_inputs = 1, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2), + .pll = PLL_28, + }, + [BTTV_BOARD_XGUARD] = { + .name = "Grand X-Guard / Trust 814PCI", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .gpiomask2 = 0xff, + .muxsel = 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_tda7432 = 1, + .pll = PLL_28, + }, + + /* ---- card 0x68 ---------------------------------- */ + [BTTV_BOARD_NEBULA_DIGITV] = { + .name = "Nebula Electronics DigiTV", + .video_inputs = 1, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + .has_remote = 1, + .gpiomask = 0x1b, + .no_gpioirq = 1, + }, + [BTTV_BOARD_PV143] = { + /* Jorge Boncompte - DTI2 */ + .name = "ProVideo PV143", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { + /* M.Klahr@phytec.de */ + .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009X1_VD011_COMBI] = { + .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + + /* ---- card 0x6c ---------------------------------- */ + [BTTV_BOARD_VD009_MINIDIN] = { + .name = "PHYTEC VD-009 MiniDIN (bt878)", + .video_inputs = 10, + /* .audio_inputs= 0, */ + .svhs = 9, + .gpiomask = 0x00, + .gpiomask2 = 0x03, /* used for external vodeo mux */ + .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0), + .muxsel_hook = phytec_muxsel, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD009_COMBI] = { + .name = "PHYTEC VD-009 Combi (bt878)", + .video_inputs = 10, + /* .audio_inputs= 0, */ + .svhs = 9, + .gpiomask = 0x00, + .gpiomask2 = 0x03, /* used for external vodeo mux */ + .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1), + .muxsel_hook = phytec_muxsel, + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_IVC100] = { + .name = "IVC-100", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xdf, + .muxsel = MUXSEL(2, 3, 1, 0), + .pll = PLL_28, + }, + [BTTV_BOARD_IVC120] = { + /* IVC-120G - Alan Garfield */ + .name = "IVC-120G", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, /* card has no svhs */ + .no_msp34xx = 1, + .no_tda7432 = 1, + .gpiomask = 0x00, + .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + .muxsel_hook = ivc120_muxsel, + .pll = PLL_28, + }, + + /* ---- card 0x70 ---------------------------------- */ + [BTTV_BOARD_PC_HDTV] = { + .name = "pcHDTV HD-2000 TV", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + }, + [BTTV_BOARD_TWINHAN_DST] = { + .name = "Twinhan DST + clones", + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_video = 1, + .has_dvb = 1, + }, + [BTTV_BOARD_WINFASTVC100] = { + .name = "Winfast VC100", + .video_inputs = 3, + /* .audio_inputs= 0, */ + .svhs = 1, + /* Vid In, SVid In, Vid over SVid in connector */ + .muxsel = MUXSEL(3, 1, 1, 3), + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + [BTTV_BOARD_TEV560] = { + .name = "Teppro TEV-560/InterVision IV-560", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 3, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 1, 1, 1, 1 }, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_35, + }, + + /* ---- card 0x74 ---------------------------------- */ + [BTTV_BOARD_SIMUS_GVC1100] = { + .name = "SIMUS GVC1100", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .muxsel = MUXSEL(2, 2, 2, 2), + .gpiomask = 0x3F, + .muxsel_hook = gvc1100_muxsel, + }, + [BTTV_BOARD_NGSTV_PLUS] = { + /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ + .name = "NGS NGSTV+", + .video_inputs = 3, + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 0, 0), + .gpiomux = { 0, 0, 0, 0 }, + .gpiomute = 0x000003, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + [BTTV_BOARD_LMLBT4] = { + /* http://linuxmedialabs.com */ + .name = "LMLBT4", + .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TEKRAM_M205] = { + /* Helmroos Harri */ + .name = "Tekram M205 PRO", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .svhs = 2, + .gpiomask = 0x68, + .muxsel = MUXSEL(2, 3, 1), + .gpiomux = { 0x68, 0x68, 0x61, 0x61 }, + .pll = PLL_28, + }, + + /* ---- card 0x78 ---------------------------------- */ + [BTTV_BOARD_CONTVFMI] = { + /* Javier Cendan Ares */ + /* bt878 TV + FM without subsystem ID */ + .name = "Conceptronic CONTVFMi", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 3, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, + }, + [BTTV_BOARD_PICOLO_TETRA_CHIP] = { + /*Eric DEBIEF */ + /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/ + /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ + /*0x79 in bttv.h*/ + .name = "Euresys Picolo Tetra", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ + .no_msp34xx = 1, + .no_tda7432 = 1, + /*878A input is always MUX0, see above.*/ + .muxsel = MUXSEL(2, 2, 2, 2), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_SPIRIT_TV] = { + /* Spirit TV Tuner from http://spiritmodems.com.au */ + /* Stafford Goodsell */ + .name = "Spirit TV Tuner", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x0000000f, + .muxsel = MUXSEL(2, 1, 1), + .gpiomux = { 0x02, 0x00, 0x00, 0x00 }, + .tuner_type = TUNER_TEMIC_PAL, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + }, + [BTTV_BOARD_AVDVBT_771] = { + /* Wolfram Joost */ + .name = "AVerMedia AVerTV DVB-T 771", + .video_inputs = 2, + .svhs = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel = MUXSEL(3, 3), + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, + }, + /* ---- card 0x7c ---------------------------------- */ + [BTTV_BOARD_AVDVBT_761] = { + /* Matt Jesson */ + /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */ + .name = "AverMedia AverTV DVB-T 761", + .video_inputs = 2, + .svhs = 1, + .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */ + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .has_dvb = 1, + .no_gpioirq = 1, + .has_remote = 1, + }, + [BTTV_BOARD_MATRIX_VISIONSQ] = { + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SQ", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), + .muxsel_hook = sigmaSQ_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MATRIX_VISIONSLC] = { + /* andre.schwarz@matrix-vision.de */ + .name = "MATRIX Vision Sigma-SLC", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2), + .muxsel_hook = sigmaSLC_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + /* BTTV_BOARD_APAC_VIEWCOMP */ + [BTTV_BOARD_APAC_VIEWCOMP] = { + /* Attila Kondoros */ + /* bt878 TV + FM 0x00000000 subsystem ID */ + .name = "APAC Viewcomp 878(AMAX)", + .video_inputs = 2, + /* .audio_inputs= 1, */ + .svhs = NO_SVHS, + .gpiomask = 0xFF, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 10, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ + .has_radio = 1, /* not every card has radio */ + }, + + /* ---- card 0x80 ---------------------------------- */ + [BTTV_BOARD_DVICO_DVBT_LITE] = { + /* Chris Pascoe */ + .name = "DViCO FusionHDTV DVB-T Lite", + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .no_video = 1, + .has_dvb = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VGEAR_MYVCD] = { + /* Steven */ + .name = "V-Gear MyVCD", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 0), + .gpiomux = {0x31, 0x31, 0x31, 0x31 }, + .gpiomute = 0x31, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC_M, + .tuner_addr = ADDR_UNSET, + .has_radio = 0, + }, + [BTTV_BOARD_SUPER_TV] = { + /* Rick C */ + .name = "Super TV Tuner", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + .gpiomask = 0x008007, + .gpiomux = { 0, 0x000001,0,0 }, + .has_radio = 1, + }, + [BTTV_BOARD_TIBET_CS16] = { + /* Chris Fanning */ + .name = "Tibet Systems 'Progress DVR' CS16", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .muxsel_hook = tibetCS16_muxsel, + }, + [BTTV_BOARD_KODICOM_4400R] = { + /* Bill Brack */ + /* + * Note that, because of the card's wiring, the "master" + * BT878A chip (i.e. the one which controls the analog switch + * and must use this card type) is the 2nd one detected. The + * other 3 chips should use card type 0x85, whose description + * follows this one. There is a EEPROM on the card (which is + * connected to the I2C of one of those other chips), but is + * not currently handled. There is also a facility for a + * "monitor", which is also not currently implemented. + */ + .name = "Kodicom 4400R (master)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + /* GPIO bits 0-9 used for analog switch: + * 00 - 03: camera selector + * 04 - 06: channel (controller) selector + * 07: data (1->on, 0->off) + * 08: strobe + * 09: reset + * bit 16 is input from sync separator for the channel + */ + .gpiomask = 0x0003ff, + .no_gpioirq = 1, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = kodicom4400r_muxsel, + }, + [BTTV_BOARD_KODICOM_4400R_SL] = { + /* Bill Brack */ + /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the + * one which controls the analog switch, and must use the card type) + * is the 2nd one detected. The other 3 chips should use this card + * type + */ + .name = "Kodicom 4400R (slave)", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0x010000, + .no_gpioirq = 1, + .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = kodicom4400r_muxsel, + }, + /* ---- card 0x86---------------------------------- */ + [BTTV_BOARD_ADLINK_RTV24] = { + /* Michael Henson */ + /* Adlink RTV24 with special unlock codes */ + .name = "Adlink RTV24", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = UNSET, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + }, + /* ---- card 0x87---------------------------------- */ + [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = { + /* Michael Krufky */ + .name = "DViCO FusionHDTV 5 Lite", + .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ + .tuner_addr = ADDR_UNSET, + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .gpiomask = 0x00e00007, + .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, + .gpiomute = 0x00c00007, + .no_msp34xx = 1, + .no_tda7432 = 1, + .has_dvb = 1, + }, + /* ---- card 0x88---------------------------------- */ + [BTTV_BOARD_ACORP_Y878F] = { + /* Mauro Carvalho Chehab */ + .name = "Acorp Y878F", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, + .gpiomute = 0x002000, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, + .tuner_addr = 0xc1 >>1, + .has_radio = 1, + }, + /* ---- card 0x89 ---------------------------------- */ + [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = { + .name = "Conceptronic CTVFMi v2", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x001c0007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, + .gpiomute = 3, + .pll = PLL_28, + .tuner_type = TUNER_TENA_9533_DI, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + .has_radio = 1, + }, + /* ---- card 0x8a ---------------------------------- */ + [BTTV_BOARD_PV_BT878P_2E] = { + .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)", + .video_inputs = 5, + /* .audio_inputs= 1, */ + .svhs = 3, + .has_dig_in = 1, + .gpiomask = 0x01fe00, + .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ + /* .digital_mode= DIGITAL_MODE_CAMERA, */ + .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 }, + .gpiomute = 0x12400, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_LG_PAL_FM, + .tuner_addr = ADDR_UNSET, + .has_remote = 1, + }, + /* ---- card 0x8b ---------------------------------- */ + [BTTV_BOARD_PV_M4900] = { + /* Sérgio Fortier */ + .name = "Prolink PixelView PlayTV MPEG2 PV-M4900", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, + .gpiomute = 0x29, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + .has_remote = 1, + }, + /* ---- card 0x8c ---------------------------------- */ + /* Has four Bt878 chips behind a PCI bridge, each chip has: + one external BNC composite input (mux 2) + three internal composite inputs (unknown muxes) + an 18-bit stereo A/D (CS5331A), which has: + one external stereo unblanced (RCA) audio connection + one (or 3?) internal stereo balanced (XLR) audio connection + input is selected via gpio to a 14052B mux + (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) + gain is controlled via an X9221A chip on the I2C bus @0x28 + sample rate is controlled via gpio to an MK1413S + (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3) + There is neither a tuner nor an svideo input. */ + [BTTV_BOARD_OSPREY440] = { + .name = "Osprey 440", + .video_inputs = 4, + /* .audio_inputs= 2, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */ + .gpiomask = 0x303, + .gpiomute = 0x000, /* int + 32kHz */ + .gpiomux = { 0, 0, 0x000, 0x100}, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + /* ---- card 0x8d ---------------------------------- */ + [BTTV_BOARD_ASOUND_SKYEYE] = { + .name = "Asound Skyeye PCTV", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 15, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 2, 0, 0, 0 }, + .gpiomute = 1, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_NTSC, + .tuner_addr = ADDR_UNSET, + }, + /* ---- card 0x8e ---------------------------------- */ + [BTTV_BOARD_SABRENT_TVFM] = { + .name = "Sabrent TV-FM (bttv version)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x108007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 100000, 100002, 100002, 100000 }, + .no_msp34xx = 1, + .no_tda7432 = 1, + .pll = PLL_28, + .tuner_type = TUNER_TNF_5335MF, + .tuner_addr = ADDR_UNSET, + .has_radio = 1, + }, + /* ---- card 0x8f ---------------------------------- */ + [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = { + .name = "Hauppauge ImpactVCB (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0f, /* old: 7 */ + .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */ + .no_msp34xx = 1, + .no_tda7432 = 1, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_MACHTV_MAGICTV] = { + /* Julian Calaby + * Slightly different from original MachTV definition (0x60) + + * FIXME: RegSpy says gpiomask should be "0x001c800f", but it + * stuffs up remote chip. Bug is a pin on the jaecs is not set + * properly (methinks) causing no keyup bits being set */ + + .name = "MagicTV", /* rebranded MachTV */ + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 7, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 3 }, + .gpiomute = 4, + .tuner_type = TUNER_TEMIC_4009FR5_PAL, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_SSAI_SECURITY] = { + .name = "SSAI Security Video Interface", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .muxsel = MUXSEL(0, 1, 2, 3), + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_SSAI_ULTRASOUND] = { + .name = "SSAI Ultrasound Video Interface", + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = 1, + .muxsel = MUXSEL(2, 0, 1, 3), + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + /* ---- card 0x94---------------------------------- */ + [BTTV_BOARD_DVICO_FUSIONHDTV_2] = { + .name = "DViCO FusionHDTV 2", + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tuner_addr = ADDR_UNSET, + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .muxsel = MUXSEL(2, 3, 1), + .gpiomask = 0x00e00007, + .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, + .gpiomute = 0x00c00007, + .no_msp34xx = 1, + .no_tda7432 = 1, + }, + /* ---- card 0x95---------------------------------- */ + [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { + .name = "Typhoon TV-Tuner PCI (50684)", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x3014f, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0x20001,0x10001, 0, 0 }, + .gpiomute = 10, + .pll = PLL_28, + .tuner_type = TUNER_PHILIPS_PAL_I, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GEOVISION_GV600] = { + /* emhn@usb.ve */ + .name = "Geovision GV-600", + .video_inputs = 16, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x0, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .muxsel_hook = geovision_muxsel, + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_KOZUMI_KTV_01C] = { + /* Mauro Lacy + * Based on MagicTV and Conceptronic CONTVFMi */ + + .name = "Kozumi KTV-01C", + .video_inputs = 3, + /* .audio_inputs= 1, */ + .svhs = 2, + .gpiomask = 0x008007, + .muxsel = MUXSEL(2, 3, 1, 1), + .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */ + .gpiomute = 3, /* CONTVFMi */ + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */ + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_ENLTV_FM_2] = { + /* Encore TV Tuner Pro ENL TV-FM-2 + Mauro Carvalho Chehab IR disabled + bit 18/17 = 00 -> mute + 01 -> enable external audio input + 10 -> internal audio input (mono?) + 11 -> internal audio input + */ + .gpiomask = 0x060040, + .muxsel = MUXSEL(2, 3, 3), + .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, + .gpiomute = 0, + .tuner_type = TUNER_TCL_MF02GIP_5N, + .tuner_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + }, + [BTTV_BOARD_VD012] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0x00, + .muxsel = MUXSEL(0, 2, 3, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X1] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X1 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(2, 3, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_VD012_X2] = { + /* D.Heer@Phytec.de */ + .name = "PHYTEC VD-012-X2 (bt878)", + .video_inputs = 4, + /* .audio_inputs= 0, */ + .svhs = 3, + .gpiomask = 0x00, + .muxsel = MUXSEL(3, 2, 1), + .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_GEOVISION_GV800S] = { + /* Bruno Christo + * + * GeoVision GV-800(S) has 4 Conexant Fusion 878A: + * 1 audio input per BT878A = 4 audio inputs + * 4 video inputs per BT878A = 16 video inputs + * This is the first BT878A chip of the GV-800(S). It's the + * "master" chip and it controls the video inputs through an + * analog multiplexer (a CD22M3494) via some GPIO pins. The + * slaves should use card type 0x9e (following this one). + * There is a EEPROM on the card which is currently not handled. + * The audio input is not working yet. + */ + .name = "Geovision GV-800(S) (master)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0xf107f, + .no_gpioirq = 1, + .muxsel = MUXSEL(2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = gv800s_muxsel, + }, + [BTTV_BOARD_GEOVISION_GV800S_SL] = { + /* Bruno Christo + * + * GeoVision GV-800(S) has 4 Conexant Fusion 878A: + * 1 audio input per BT878A = 4 audio inputs + * 4 video inputs per BT878A = 16 video inputs + * The 3 other BT878A chips are "slave" chips of the GV-800(S) + * and should use this card type. + * The audio input is not working yet. + */ + .name = "Geovision GV-800(S) (slave)", + .video_inputs = 4, + /* .audio_inputs= 1, */ + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + .svhs = NO_SVHS, + .gpiomask = 0x00, + .no_gpioirq = 1, + .muxsel = MUXSEL(2, 2, 2, 2), + .pll = PLL_28, + .no_msp34xx = 1, + .no_tda7432 = 1, + .muxsel_hook = gv800s_muxsel, + }, + [BTTV_BOARD_PV183] = { + .name = "ProVideo PV183", /* 0x9f */ + .video_inputs = 2, + /* .audio_inputs= 0, */ + .svhs = NO_SVHS, + .gpiomask = 0, + .muxsel = MUXSEL(2, 3), + .gpiomux = { 0 }, + .no_msp34xx = 1, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + .tuner_addr = ADDR_UNSET, + }, + [BTTV_BOARD_TVT_TD3116] = { + .name = "Tongwei Video Technology TD-3116", + .video_inputs = 16, + .gpiomask = 0xc00ff, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .muxsel_hook = td3116_muxsel, + .svhs = NO_SVHS, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + }, + [BTTV_BOARD_APOSONIC_WDVR] = { + .name = "Aposonic W-DVR", + .video_inputs = 4, + .svhs = NO_SVHS, + .muxsel = MUXSEL(2, 3, 1, 0), + .tuner_type = TUNER_ABSENT, + }, + +}; + +static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); + +/* ----------------------------------------------------------------------- */ + +static unsigned char eeprom_data[256]; + +/* + * identify card + */ +void __devinit bttv_idcard(struct bttv *btv) +{ + unsigned int gpiobits; + int i,type; + + /* read PCI subsystem ID */ + btv->cardid = btv->c.pci->subsystem_device << 16; + btv->cardid |= btv->c.pci->subsystem_vendor; + + if (0 != btv->cardid && 0xffffffff != btv->cardid) { + /* look for the card */ + for (type = -1, i = 0; cards[i].id != 0; i++) + if (cards[i].id == btv->cardid) + type = i; + + if (type != -1) { + /* found it */ + pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n", + btv->c.nr, cards[type].name, cards[type].cardnr, + btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + btv->c.type = cards[type].cardnr; + } else { + /* 404 */ + pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n", + btv->c.nr, btv->cardid & 0xffff, + (btv->cardid >> 16) & 0xffff); + pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n"); + } + } + + /* let the user override the autodetected type */ + if (card[btv->c.nr] < bttv_num_tvcards) + btv->c.type=card[btv->c.nr]; + + /* print which card config we are using */ + pr_info("%d: using: %s [card=%d,%s]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type, + card[btv->c.nr] < bttv_num_tvcards + ? "insmod option" : "autodetected"); + + /* overwrite gpio stuff ?? */ + if (UNSET == audioall && UNSET == audiomux[0]) + return; + + if (UNSET != audiomux[0]) { + gpiobits = 0; + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; + gpiobits |= audiomux[i]; + } + } else { + gpiobits = audioall; + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + bttv_tvcards[btv->c.type].gpiomux[i] = audioall; + } + } + bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; + pr_info("%d: gpio config override: mask=0x%x, mux=", + btv->c.nr, bttv_tvcards[btv->c.type].gpiomask); + for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { + pr_cont("%s0x%x", + i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); + } + pr_cont("\n"); +} + +/* + * (most) board specific initialisations goes here + */ + +/* Some Modular Technology cards have an eeprom, but no subsystem ID */ +static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) +{ + int type = -1; + + if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13)) + type = BTTV_BOARD_MODTEC_205; + else if (0 == strncmp(eeprom_data+20,"Picolo",7)) + type = BTTV_BOARD_EURESYS_PICOLO; + else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0) + type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */ + + if (-1 != type) { + btv->c.type = type; + pr_info("%d: detected by eeprom: %s [card=%d]\n", + btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); + } +} + +static void flyvideo_gpio(struct bttv *btv) +{ + int gpio, has_remote, has_radio, is_capture_only; + int is_lr90, has_tda9820_tda9821; + int tuner_type = UNSET, ttype; + + gpio_inout(0xffffff, 0); + udelay(8); /* without this we would see the 0x1800 mask */ + gpio = gpio_read(); + /* FIXME: must restore OUR_EN ??? */ + + /* all cards provide GPIO info, some have an additional eeprom + * LR50: GPIO coding can be found lower right CP1 .. CP9 + * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. + * GPIO14-12: n.c. + * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) + + * lowest 3 bytes are remote control codes (no handshake needed) + * xxxFFF: No remote control chip soldered + * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered + * Note: Some bits are Audio_Mask ! + */ + ttype = (gpio & 0x0f0000) >> 16; + switch (ttype) { + case 0x0: + tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ + break; + case 0x2: + tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ + break; + case 0x4: + tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ + break; + case 0x6: + tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ + break; + case 0xC: + tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ + break; + default: + pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr); + break; + } + + has_remote = gpio & 0x800000; + has_radio = gpio & 0x400000; + /* unknown 0x200000; + * unknown2 0x100000; */ + is_capture_only = !(gpio & 0x008000); /* GPIO15 */ + has_tda9820_tda9821 = !(gpio & 0x004000); + is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ + /* + * gpio & 0x001000 output bit for audio routing */ + + if (is_capture_only) + tuner_type = TUNER_ABSENT; /* No tuner present */ + + pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", + btv->c.nr, has_radio ? "yes" : "no", + has_remote ? "yes" : "no", tuner_type, gpio); + pr_info("%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", + btv->c.nr, is_lr90 ? "yes" : "no", + has_tda9820_tda9821 ? "yes" : "no", + is_capture_only ? "yes" : "no"); + + if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ + btv->tuner_type = tuner_type; + btv->has_radio = has_radio; + + /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 + * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 + * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ + if (has_tda9820_tda9821) + btv->audio_mode_gpio = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ +} + +static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, + 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; +static int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, + 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 }; + +static void miro_pinnacle_gpio(struct bttv *btv) +{ + int id,msp,gpio; + char *info; + + gpio_inout(0xffffff, 0); + gpio = gpio_read(); + id = ((gpio>>10) & 63) -1; + msp = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx"); + if (id < 32) { + btv->tuner_type = miro_tunermap[id]; + if (0 == (gpio & 0x20)) { + btv->has_radio = 1; + if (!miro_fmtuner[id]) { + btv->has_matchbox = 1; + btv->mbox_we = (1<<6); + btv->mbox_most = (1<<7); + btv->mbox_clk = (1<<8); + btv->mbox_data = (1<<9); + btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); + } + } else { + btv->has_radio = 0; + } + if (-1 != msp) { + if (btv->c.type == BTTV_BOARD_MIRO) + btv->c.type = BTTV_BOARD_MIROPRO; + if (btv->c.type == BTTV_BOARD_PINNACLE) + btv->c.type = BTTV_BOARD_PINNACLEPRO; + } + pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + btv->c.nr, id+1, btv->tuner_type, + !btv->has_radio ? "no" : + (btv->has_matchbox ? "matchbox" : "fmtuner"), + (-1 == msp) ? "no" : "yes"); + } else { + /* new cards with microtune tuner */ + id = 63 - id; + btv->has_radio = 0; + switch (id) { + case 1: + info = "PAL / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 2: + info = "PAL+SECAM / stereo"; + btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; + break; + case 3: + info = "NTSC / stereo"; + btv->has_radio = 1; + btv->tda9887_conf = TDA9887_QSS; + break; + case 4: + info = "PAL+SECAM / mono"; + btv->tda9887_conf = TDA9887_QSS; + break; + case 5: + info = "NTSC / mono"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 6: + info = "NTSC / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + case 7: + info = "PAL / stereo"; + btv->tda9887_conf = TDA9887_INTERCARRIER; + break; + default: + info = "oops: unknown card"; + break; + } + if (-1 != msp) + btv->c.type = BTTV_BOARD_PINNACLEPRO; + pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", + btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); + btv->tuner_type = TUNER_MT2032; + } +} + +/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */ +#define LM1882_SYNC_DRIVE 0x200000L + +static void init_ids_eagle(struct bttv *btv) +{ + gpio_inout(0xffffff,0xFFFF37); + gpio_write(0x200020); + + /* flash strobe inverter ?! */ + gpio_write(0x200024); + + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); + + /* set BT848 muxel to 2 */ + btaor((2)<<5, ~(2<<5), BT848_IFORM); +} + +/* Muxsel helper for the IDS Eagle. + * the eagles does not use the standard muxsel-bits but + * has its own multiplexer */ +static void eagle_muxsel(struct bttv *btv, unsigned int input) +{ + gpio_bits(3, input & 3); + + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + + /* switch sync drive off */ + gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); +} + +static void gvc1100_muxsel(struct bttv *btv, unsigned int input) +{ + static const int masks[] = {0x30, 0x01, 0x12, 0x23}; + gpio_write(masks[input%4]); +} + +/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and + alarms output + + GPIObit | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1| | | + + IN - sensor inputs, INx - sensor inputs and TI XORed together + O1,O2,O3 - alarm outputs (relays) + + OUT ENABLE 1 1 0 . 1 1 0 0 . 0 0 0 0 = 0x6C0 + +*/ + +static void init_lmlbt4x(struct bttv *btv) +{ + pr_debug("LMLBT4x init\n"); + btwrite(0x000000, BT848_GPIO_REG_INP); + gpio_inout(0xffffff, 0x0006C0); + gpio_write(0x000000); +} + +static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 8; + gpio_inout( 0xf, 0xf ); + gpio_bits( 0xf, inmux ); +} + +static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 4; + gpio_inout( 3<<9, 3<<9 ); + gpio_bits( 3<<9, inmux<<9 ); +} + +static void geovision_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int inmux = input % 16; + gpio_inout(0xf, 0xf); + gpio_bits(0xf, inmux); +} + +/* + * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878. + * The first 74HC4051 has the lower 8 inputs, the second one the higher 8. + * The muxes are controlled via a 74HC373 latch which is connected to + * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch. + * Q0 of the latch is connected to the Enable (~E) input of the first + * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051. + * Q4 - Q7 are connected to the second 74HC4051 in the same way. + */ + +static void td3116_latch_value(struct bttv *btv, u32 value) +{ + gpio_bits((1<<18) | 0xff, value); + gpio_bits((1<<18) | 0xff, (1<<18) | value); + udelay(1); + gpio_bits((1<<18) | 0xff, value); +} + +static void td3116_muxsel(struct bttv *btv, unsigned int input) +{ + u32 value; + u32 highbit; + + highbit = (input & 0x8) >> 3 ; + + /* Disable outputs and set value in the mux */ + value = 0x11; /* Disable outputs */ + value |= ((input & 0x7) << 1) << (4 * highbit); + td3116_latch_value(btv, value); + + /* Enable the correct output */ + value &= ~0x11; + value |= ((highbit ^ 0x1) << 4) | highbit; + td3116_latch_value(btv, value); +} + +/* ----------------------------------------------------------------------- */ + +static void bttv_reset_audio(struct bttv *btv) +{ + /* + * BT878A has a audio-reset register. + * 1. This register is an audio reset function but it is in + * function-0 (video capture) address space. + * 2. It is enough to do this once per power-up of the card. + * 3. There is a typo in the Conexant doc -- it is not at + * 0x5B, but at 0x058. (B is an odd-number, obviously a typo!). + * --//Shrikumar 030609 + */ + if (btv->id != 878) + return; + + if (bttv_debug) + pr_debug("%d: BT878A ARESET\n", btv->c.nr); + btwrite((1<<7), 0x058); + udelay(10); + btwrite( 0, 0x058); +} + +/* initialization part one -- before registering i2c bus */ +void __devinit bttv_init_card1(struct bttv *btv) +{ + switch (btv->c.type) { + case BTTV_BOARD_HAUPPAUGE: + case BTTV_BOARD_HAUPPAUGE878: + boot_msp34xx(btv,5); + break; + case BTTV_BOARD_VOODOOTV_200: + case BTTV_BOARD_VOODOOTV_FM: + boot_msp34xx(btv,20); + break; + case BTTV_BOARD_AVERMEDIA98: + boot_msp34xx(btv,11); + break; + case BTTV_BOARD_HAUPPAUGEPVR: + pvr_boot(btv); + break; + case BTTV_BOARD_TWINHAN_DST: + case BTTV_BOARD_AVDVBT_771: + case BTTV_BOARD_PINNACLESAT: + btv->use_i2c_hw = 1; + break; + case BTTV_BOARD_ADLINK_RTV24: + init_RTV24( btv ); + break; + + } + if (!bttv_tvcards[btv->c.type].has_dvb) + bttv_reset_audio(btv); +} + +/* initialization part two -- after registering i2c bus */ +void __devinit bttv_init_card2(struct bttv *btv) +{ + btv->tuner_type = UNSET; + + if (BTTV_BOARD_UNKNOWN == btv->c.type) { + bttv_readee(btv,eeprom_data,0xa0); + identify_by_eeprom(btv,eeprom_data); + } + + switch (btv->c.type) { + case BTTV_BOARD_MIRO: + case BTTV_BOARD_MIROPRO: + case BTTV_BOARD_PINNACLE: + case BTTV_BOARD_PINNACLEPRO: + /* miro/pinnacle */ + miro_pinnacle_gpio(btv); + break; + case BTTV_BOARD_FLYVIDEO_98: + case BTTV_BOARD_MAXI: + case BTTV_BOARD_LIFE_FLYKIT: + case BTTV_BOARD_FLYVIDEO: + case BTTV_BOARD_TYPHOON_TVIEW: + case BTTV_BOARD_CHRONOS_VS2: + case BTTV_BOARD_FLYVIDEO_98FM: + case BTTV_BOARD_FLYVIDEO2000: + case BTTV_BOARD_FLYVIDEO98EZ: + case BTTV_BOARD_CONFERENCETV: + case BTTV_BOARD_LIFETEC_9415: + flyvideo_gpio(btv); + break; + case BTTV_BOARD_HAUPPAUGE: + case BTTV_BOARD_HAUPPAUGE878: + case BTTV_BOARD_HAUPPAUGEPVR: + /* pick up some config infos from the eeprom */ + bttv_readee(btv,eeprom_data,0xa0); + hauppauge_eeprom(btv); + break; + case BTTV_BOARD_AVERMEDIA98: + case BTTV_BOARD_AVPHONE98: + bttv_readee(btv,eeprom_data,0xa0); + avermedia_eeprom(btv); + break; + case BTTV_BOARD_PXC200: + init_PXC200(btv); + break; + case BTTV_BOARD_PICOLO_TETRA_CHIP: + picolo_tetra_init(btv); + break; + case BTTV_BOARD_VHX: + btv->has_radio = 1; + btv->has_matchbox = 1; + btv->mbox_we = 0x20; + btv->mbox_most = 0; + btv->mbox_clk = 0x08; + btv->mbox_data = 0x10; + btv->mbox_mask = 0x38; + break; + case BTTV_BOARD_VOBIS_BOOSTAR: + case BTTV_BOARD_TERRATV: + terratec_active_radio_upgrade(btv); + break; + case BTTV_BOARD_MAGICTVIEW061: + if (btv->cardid == 0x3002144f) { + btv->has_radio=1; + pr_info("%d: radio detected by subsystem id (CPH05x)\n", + btv->c.nr); + } + break; + case BTTV_BOARD_STB2: + if (btv->cardid == 0x3060121a) { + /* Fix up entry for 3DFX VoodooTV 100, + which is an OEM STB card variant. */ + btv->has_radio=0; + btv->tuner_type=TUNER_TEMIC_NTSC; + } + break; + case BTTV_BOARD_OSPREY1x0: + case BTTV_BOARD_OSPREY1x0_848: + case BTTV_BOARD_OSPREY101_848: + case BTTV_BOARD_OSPREY1x1: + case BTTV_BOARD_OSPREY1x1_SVID: + case BTTV_BOARD_OSPREY2xx: + case BTTV_BOARD_OSPREY2x0_SVID: + case BTTV_BOARD_OSPREY2x0: + case BTTV_BOARD_OSPREY440: + case BTTV_BOARD_OSPREY500: + case BTTV_BOARD_OSPREY540: + case BTTV_BOARD_OSPREY2000: + bttv_readee(btv,eeprom_data,0xa0); + osprey_eeprom(btv, eeprom_data); + break; + case BTTV_BOARD_IDS_EAGLE: + init_ids_eagle(btv); + break; + case BTTV_BOARD_MODTEC_205: + bttv_readee(btv,eeprom_data,0xa0); + modtec_eeprom(btv); + break; + case BTTV_BOARD_LMLBT4: + init_lmlbt4x(btv); + break; + case BTTV_BOARD_TIBET_CS16: + tibetCS16_init(btv); + break; + case BTTV_BOARD_KODICOM_4400R: + kodicom4400r_init(btv); + break; + case BTTV_BOARD_GEOVISION_GV800S: + gv800s_init(btv); + break; + } + + /* pll configuration */ + if (!(btv->id==848 && btv->revision==0x11)) { + /* defaults from card list */ + if (PLL_28 == bttv_tvcards[btv->c.type].pll) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; + } + if (PLL_35 == bttv_tvcards[btv->c.type].pll) { + btv->pll.pll_ifreq=35468950; + btv->pll.pll_crystal=BT848_IFORM_XT1; + } + /* insmod options can override */ + switch (pll[btv->c.nr]) { + case 0: /* none */ + btv->pll.pll_crystal = 0; + btv->pll.pll_ifreq = 0; + btv->pll.pll_ofreq = 0; + break; + case 1: /* 28 MHz */ + case 28: + btv->pll.pll_ifreq = 28636363; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal = BT848_IFORM_XT0; + break; + case 2: /* 35 MHz */ + case 35: + btv->pll.pll_ifreq = 35468950; + btv->pll.pll_ofreq = 0; + btv->pll.pll_crystal = BT848_IFORM_XT1; + break; + } + } + btv->pll.pll_current = -1; + + /* tuner configuration (from card list / autodetect / insmod option) */ + if (UNSET != bttv_tvcards[btv->c.type].tuner_type) + if (UNSET == btv->tuner_type) + btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; + if (UNSET != tuner[btv->c.nr]) + btv->tuner_type = tuner[btv->c.nr]; + + if (btv->tuner_type == TUNER_ABSENT) + pr_info("%d: tuner absent\n", btv->c.nr); + else if (btv->tuner_type == UNSET) + pr_warn("%d: tuner type unset\n", btv->c.nr); + else + pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type); + + if (autoload != UNSET) { + pr_warn("%d: the autoload option is obsolete\n", btv->c.nr); + pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n", + btv->c.nr); + } + + if (UNSET == btv->tuner_type) + btv->tuner_type = TUNER_ABSENT; + + btv->dig = bttv_tvcards[btv->c.type].has_dig_in ? + bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET; + btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ? + UNSET : bttv_tvcards[btv->c.type].svhs; + if (svhs[btv->c.nr] != UNSET) + btv->svhs = svhs[btv->c.nr]; + if (remote[btv->c.nr] != UNSET) + btv->has_remote = remote[btv->c.nr]; + + if (bttv_tvcards[btv->c.type].has_radio) + btv->has_radio = 1; + if (bttv_tvcards[btv->c.type].has_remote) + btv->has_remote = 1; + if (!bttv_tvcards[btv->c.type].no_gpioirq) + btv->gpioirq = 1; + if (bttv_tvcards[btv->c.type].volume_gpio) + btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio; + if (bttv_tvcards[btv->c.type].audio_mode_gpio) + btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio; + + if (btv->tuner_type == TUNER_ABSENT) + return; /* no tuner or related drivers to load */ + + if (btv->has_saa6588 || saa6588[btv->c.nr]) { + /* Probe for RDS receiver chip */ + static const unsigned short addrs[] = { + 0x20 >> 1, + 0x22 >> 1, + I2C_CLIENT_END + }; + struct v4l2_subdev *sd; + + sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "saa6588", 0, addrs); + btv->has_saa6588 = (sd != NULL); + } + + /* try to detect audio/fader chips */ + + /* First check if the user specified the audio chip via a module + option. */ + + switch (audiodev[btv->c.nr]) { + case -1: + return; /* do not load any audio module */ + + case 0: /* autodetect */ + break; + + case 1: { + /* The user specified that we should probe for msp3400 */ + static const unsigned short addrs[] = { + I2C_ADDR_MSP3400 >> 1, + I2C_ADDR_MSP3400_ALT >> 1, + I2C_CLIENT_END + }; + + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", 0, addrs); + if (btv->sd_msp34xx) + return; + goto no_audio; + } + + case 2: { + /* The user specified that we should probe for tda7432 */ + static const unsigned short addrs[] = { + I2C_ADDR_TDA7432 >> 1, + I2C_CLIENT_END + }; + + if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs)) + return; + goto no_audio; + } + + case 3: { + /* The user specified that we should probe for tvaudio */ + btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + if (btv->sd_tvaudio) + return; + goto no_audio; + } + + default: + pr_warn("%d: unknown audiodev value!\n", btv->c.nr); + return; + } + + /* There were no overrides, so now we try to discover this through the + card definition */ + + /* probe for msp3400 first: this driver can detect whether or not + it really is a msp3400, so it will return NULL when the device + found is really something else (e.g. a tea6300). */ + if (!bttv_tvcards[btv->c.type].no_msp34xx) { + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", + 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); + } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { + btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "msp3400", + 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); + } + + /* If we found a msp34xx, then we're done. */ + if (btv->sd_msp34xx) + return; + + /* it might also be a tda7432. */ + if (!bttv_tvcards[btv->c.type].no_tda7432) { + static const unsigned short addrs[] = { + I2C_ADDR_TDA7432 >> 1, + I2C_CLIENT_END + }; + + if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs)) + return; + } + + /* Now see if we can find one of the tvaudio devices. */ + btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + if (btv->sd_tvaudio) + return; + +no_audio: + pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr); +} + + +/* initialize the tuner */ +void __devinit bttv_init_tuner(struct bttv *btv) +{ + int addr = ADDR_UNSET; + + if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) + addr = bttv_tvcards[btv->c.type].tuner_addr; + + if (btv->tuner_type != TUNER_ABSENT) { + struct tuner_setup tun_setup; + + /* Load tuner module before issuing tuner config call! */ + if (btv->has_radio) + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = btv->tuner_type; + tun_setup.addr = addr; + + if (btv->has_radio) + tun_setup.mode_mask |= T_RADIO; + + bttv_call_all(btv, tuner, s_type_addr, &tun_setup); + } + + if (btv->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_all(btv, tuner, s_config, &tda9887_cfg); + } +} + +/* ----------------------------------------------------------------------- */ + +static void modtec_eeprom(struct bttv *btv) +{ + if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { + btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); + } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { + btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); + } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { + btv->tuner_type=TUNER_PHILIPS_NTSC; + pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", + btv->c.nr, &eeprom_data[0x1e]); + } else { + pr_info("%d: Modtec: Unknown TunerString: %s\n", + btv->c.nr, &eeprom_data[0x1e]); + } +} + +static void __devinit hauppauge_eeprom(struct bttv *btv) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); + btv->tuner_type = tv.tuner_type; + btv->has_radio = tv.has_radio; + + pr_info("%d: Hauppauge eeprom indicates model#%d\n", + btv->c.nr, tv.model); + + /* + * Some of the 878 boards have duplicate PCI IDs. Switch the board + * type based on model #. + */ + if(tv.model == 64900) { + pr_info("%d: Switching board type from %s to %s\n", + btv->c.nr, + bttv_tvcards[btv->c.type].name, + bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); + btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB; + } + + /* The 61334 needs the msp3410 to do the radio demod to get sound */ + if (tv.model == 61334) + btv->radio_uses_msp_demodulator = 1; +} + +static int terratec_active_radio_upgrade(struct bttv *btv) +{ + int freq; + + btv->has_radio = 1; + btv->has_matchbox = 1; + btv->mbox_we = 0x10; + btv->mbox_most = 0x20; + btv->mbox_clk = 0x08; + btv->mbox_data = 0x04; + btv->mbox_mask = 0x3c; + + btv->mbox_iow = 1 << 8; + btv->mbox_ior = 1 << 9; + btv->mbox_csel = 1 << 10; + + freq=88000/62.5; + tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ + if (0x1ed8 == tea5757_read(btv)) { + pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr); + btv->has_radio = 1; + btv->has_saa6588 = 1; + btv->has_matchbox = 1; + } else { + btv->has_radio = 0; + btv->has_matchbox = 0; + } + return 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* + * minimal bootstrap for the WinTV/PVR -- upload altera firmware. + * + * The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have + * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be + * unpacked with unzip). + */ +#define PVR_GPIO_DELAY 10 + +#define BTTV_ALT_DATA 0x000001 +#define BTTV_ALT_DCLK 0x100000 +#define BTTV_ALT_NCONFIG 0x800000 + +static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro, + u32 microlen) +{ + u32 n; + u8 bits; + int i; + + gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG); + gpio_write(0); + udelay(PVR_GPIO_DELAY); + + gpio_write(BTTV_ALT_NCONFIG); + udelay(PVR_GPIO_DELAY); + + for (n = 0; n < microlen; n++) { + bits = micro[n]; + for (i = 0 ; i < 8 ; i++) { + gpio_bits(BTTV_ALT_DCLK,0); + if (bits & 0x01) + gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); + else + gpio_bits(BTTV_ALT_DATA,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); + bits >>= 1; + } + } + gpio_bits(BTTV_ALT_DCLK,0); + udelay(PVR_GPIO_DELAY); + + /* begin Altera init loop (Not necessary,but doesn't hurt) */ + for (i = 0 ; i < 30 ; i++) { + gpio_bits(BTTV_ALT_DCLK,0); + gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); + } + gpio_bits(BTTV_ALT_DCLK,0); + return 0; +} + +static int __devinit pvr_boot(struct bttv *btv) +{ + const struct firmware *fw_entry; + int rc; + + rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); + if (rc != 0) { + pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr); + return rc; + } + rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); + pr_info("%d: altera firmware upload %s\n", + btv->c.nr, (rc < 0) ? "failed" : "ok"); + release_firmware(fw_entry); + return rc; +} + +/* ----------------------------------------------------------------------- */ +/* some osprey specific stuff */ + +static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) +{ + int i; + u32 serial = 0; + int cardid = -1; + + /* This code will nevery actually get called in this case.... */ + if (btv->c.type == BTTV_BOARD_UNKNOWN) { + /* this might be an antique... check for MMAC label in eeprom */ + if (!strncmp(ee, "MMAC", 4)) { + u8 checksum = 0; + for (i = 0; i < 21; i++) + checksum += ee[i]; + if (checksum != ee[21]) + return; + cardid = BTTV_BOARD_OSPREY1x0_848; + for (i = 12; i < 21; i++) + serial *= 10, serial += ee[i] - '0'; + } + } else { + unsigned short type; + + for (i = 4*16; i < 8*16; i += 16) { + u16 checksum = ip_compute_csum(ee + i, 16); + + if ((checksum&0xff) + (checksum>>8) == 0xff) + break; + } + if (i >= 8*16) + return; + ee += i; + + /* found a valid descriptor */ + type = get_unaligned_be16((__be16 *)(ee+4)); + + switch(type) { + /* 848 based */ + case 0x0004: + cardid = BTTV_BOARD_OSPREY1x0_848; + break; + case 0x0005: + cardid = BTTV_BOARD_OSPREY101_848; + break; + + /* 878 based */ + case 0x0012: + case 0x0013: + cardid = BTTV_BOARD_OSPREY1x0; + break; + case 0x0014: + case 0x0015: + cardid = BTTV_BOARD_OSPREY1x1; + break; + case 0x0016: + case 0x0017: + case 0x0020: + cardid = BTTV_BOARD_OSPREY1x1_SVID; + break; + case 0x0018: + case 0x0019: + case 0x001E: + case 0x001F: + cardid = BTTV_BOARD_OSPREY2xx; + break; + case 0x001A: + case 0x001B: + cardid = BTTV_BOARD_OSPREY2x0_SVID; + break; + case 0x0040: + cardid = BTTV_BOARD_OSPREY500; + break; + case 0x0050: + case 0x0056: + cardid = BTTV_BOARD_OSPREY540; + /* bttv_osprey_540_init(btv); */ + break; + case 0x0060: + case 0x0070: + case 0x00A0: + cardid = BTTV_BOARD_OSPREY2x0; + /* enable output on select control lines */ + gpio_inout(0xffffff,0x000303); + break; + case 0x00D8: + cardid = BTTV_BOARD_OSPREY440; + break; + default: + /* unknown...leave generic, but get serial # */ + pr_info("%d: osprey eeprom: unknown card type 0x%04x\n", + btv->c.nr, type); + break; + } + serial = get_unaligned_be32((__be32 *)(ee+6)); + } + + pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n", + btv->c.nr, cardid, + cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial); + + if (cardid<0 || btv->c.type == cardid) + return; + + /* card type isn't set correctly */ + if (card[btv->c.nr] < bttv_num_tvcards) { + pr_warn("%d: osprey eeprom: Not overriding user specified card type\n", + btv->c.nr); + } else { + pr_info("%d: osprey eeprom: Changing card type from %d to %d\n", + btv->c.nr, btv->c.type, cardid); + btv->c.type = cardid; + } +} + +/* ----------------------------------------------------------------------- */ +/* AVermedia specific stuff, from bktr_card.c */ + +static int tuner_0_table[] = { + TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/, + TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/, + TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, + TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, + TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, + TUNER_PHILIPS_FM1216ME_MK3 }; + +static int tuner_1_table[] = { + TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, + TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, + TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, + TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ + TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; + +static void __devinit avermedia_eeprom(struct bttv *btv) +{ + int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; + + tuner_make = (eeprom_data[0x41] & 0x7); + tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; + tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; + btv->has_remote = (eeprom_data[0x42] & 0x01); + + if (tuner_make == 0 || tuner_make == 2) + if (tuner_format <= 0x0a) + tuner_type = tuner_0_table[tuner_format]; + if (tuner_make == 1) + if (tuner_format <= 9) + tuner_type = tuner_1_table[tuner_format]; + + if (tuner_make == 4) + if (tuner_format == 0x09) + tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ + + pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=", + btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); + if (tuner_type) { + btv->tuner_type = tuner_type; + pr_cont("%d", tuner_type); + } else + pr_cont("Unknown type"); + pr_cont(" radio:%s remote control:%s\n", + tuner_tv_fm ? "yes" : "no", + btv->has_remote ? "yes" : "no"); +} + +/* + * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880 + * analog demod, which is not I2C controlled like the newer and more common + * TDA9887 series. Instead is has two tri-state input pins, S0 and S1, + * that control the IF for the video and audio. Apparently, bttv GPIO + * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I + * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC). + */ +u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits) +{ + + if (btv->audio == TVAUDIO_INPUT_TUNER) { + if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN) + gpiobits |= 0x10000; + else + gpiobits &= ~0x10000; + } + + gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits); + return gpiobits; +} + + +/* + * reset/enable the MSP on some Hauppauge cards + * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! + * + * Hauppauge: pin 5 + * Voodoo: pin 20 + */ +static void __devinit boot_msp34xx(struct bttv *btv, int pin) +{ + int mask = (1 << pin); + + gpio_inout(mask,mask); + gpio_bits(mask,0); + mdelay(2); + udelay(500); + gpio_bits(mask,mask); + + if (bttv_gpio) + bttv_gpio_tracking(btv,"msp34xx"); + if (bttv_verbose) + pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n", + btv->c.nr, pin); +} + +/* ----------------------------------------------------------------------- */ +/* 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 int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x00 }; + unsigned int i; + int tmp; + u32 val; + + /* Initialise GPIO-connevted stuff */ + gpio_inout(0xffffff, (1<<13)); + gpio_write(0); + udelay(3); + gpio_write(1<<13); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + gpio_bits(0xffffff, 0); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pxc200"); + + /* 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 */ + pr_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 */ + + + pr_info("Initialising 12C508 PIC chip ...\n"); + + /* First of all, enable the clock line. This is used in the PXC200-F */ + val = btread(BT848_GPIO_DMA_CTL); + val |= BT848_GPIO_DMA_CTL_GPCLKMODE; + btwrite(val, BT848_GPIO_DMA_CTL); + + /* Then, push to 0 the reset pin long enough to reset the * + * device same as above for the reset line, but not the same + * value sent to the GPIO-connected stuff + * which one is the good one? */ + gpio_inout(0xffffff,(1<<2)); + gpio_write(0); + udelay(10); + gpio_write(1<<2); + + for (i = 0; i < ARRAY_SIZE(vals); i++) { + tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); + if (tmp != -1) { + pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", + vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); + } + } + + pr_info("PXC200 Initialised\n"); +} + + + +/* ----------------------------------------------------------------------- */ +/* + * The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock + * it. This apparently involves the following procedure for each 878 chip: + * + * 1) write 0x00C3FEFF to the GPIO_OUT_EN register + * + * 2) write to GPIO_DATA + * - 0x0E + * - sleep 1ms + * - 0x10 + 0x0E + * - sleep 10ms + * - 0x0E + * read from GPIO_DATA into buf (uint_32) + * - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 ) + * error. ERROR_CPLD_Check_Failed stop. + * + * 3) write to GPIO_DATA + * - write 0x4400 + 0x0E + * - sleep 10ms + * - write 0x4410 + 0x0E + * - sleep 1ms + * - write 0x0E + * read from GPIO_DATA into buf (uint_32) + * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) + * error. ERROR_CPLD_Check_Failed. + */ +/* ----------------------------------------------------------------------- */ +static void +init_RTV24 (struct bttv *btv) +{ + uint32_t dataRead = 0; + long watchdog_value = 0x0E; + + pr_info("%d: Adlink RTV-24 initialisation in progress ...\n", + btv->c.nr); + + btwrite (0x00c3feff, BT848_GPIO_OUT_EN); + + btwrite (0 + watchdog_value, BT848_GPIO_DATA); + msleep (1); + btwrite (0x10 + watchdog_value, BT848_GPIO_DATA); + msleep (10); + btwrite (0 + watchdog_value, BT848_GPIO_DATA); + + dataRead = btread (BT848_GPIO_DATA); + + if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { + pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", + btv->c.nr, dataRead); + } + + btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA); + msleep (10); + btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA); + msleep (1); + btwrite (watchdog_value, BT848_GPIO_DATA); + msleep (1); + dataRead = btread (BT848_GPIO_DATA); + + if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { + pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", + btv->c.nr, dataRead); + + return; + } + + pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr); +} + + + +/* ----------------------------------------------------------------------- */ +/* 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 + */ + +static void bus_low(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + gpio_bits(bit,0); + udelay(5); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } +} + +static void bus_high(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + gpio_bits(bit,bit); + udelay(5); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } +} + +static int bus_in(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + + gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); + udelay(5); + } + return gpio_read() & (bit); +} + +/* 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 tea5757_read(struct bttv *btv) +{ + unsigned long timeout; + int value = 0; + int i; + + /* better safe than sorry */ + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + + if (bttv_gpio) + bttv_gpio_tracking(btv,"tea5757 read"); + + bus_low(btv,btv->mbox_we); + bus_low(btv,btv->mbox_clk); + + udelay(10); + timeout= jiffies + msecs_to_jiffies(1000); + + /* wait for DATA line to go low; error if it doesn't */ + while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) + schedule(); + if (bus_in(btv,btv->mbox_data)) { + pr_warn("%d: tea5757: read timeout\n", btv->c.nr); + return -1; + } + + dprintk("%d: tea5757:", btv->c.nr); + for (i = 0; i < 24; i++) { + udelay(5); + bus_high(btv,btv->mbox_clk); + udelay(5); + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-'); + bus_low(btv,btv->mbox_clk); + value <<= 1; + value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ + dprintk_cont("%c", + bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M'); + } + dprintk_cont("\n"); + dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value); + return value; +} + +static int tea5757_write(struct bttv *btv, int value) +{ + int i; + int reg = value; + + gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); + + if (btv->mbox_ior) { + gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); + udelay(5); + } + if (bttv_gpio) + bttv_gpio_tracking(btv,"tea5757 write"); + + dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value); + bus_low(btv,btv->mbox_clk); + bus_high(btv,btv->mbox_we); + for (i = 0; i < 25; i++) { + if (reg & 0x1000000) + bus_high(btv,btv->mbox_data); + else + bus_low(btv,btv->mbox_data); + reg <<= 1; + bus_high(btv,btv->mbox_clk); + udelay(10); + bus_low(btv,btv->mbox_clk); + udelay(10); + } + bus_low(btv,btv->mbox_we); /* unmute !!! */ + return 0; +} + +void tea5757_set_freq(struct bttv *btv, unsigned short freq) +{ + dprintk("tea5757_set_freq %d\n",freq); + tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ +} + +/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] + * + * This is needed because rv605 don't use a normal multiplex, but a crosspoint + * switch instead (CD22M3494E). This IC can have multiple active connections + * between Xn (input) and Yn (output) pins. We need to clear any existing + * connection prior to establish a new one, pulsing the STROBE pin. + * + * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. + * GPIO pins are wired as: + * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller) + * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller) + * GPIO[7] - DATA (xpoint) - P1[7] (microcontroller) + * GPIO[8] - - P3[5] (microcontroller) + * GPIO[9] - RESET (xpoint) - P3[6] (microcontroller) + * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroller) + * GPINTR - - P3[4] (microcontroller) + * + * The microcontroller is a 80C32 like. It should be possible to change xpoint + * configuration either directly (as we are doing) or using the microcontroller + * which is also wired to I2C interface. I have no further info on the + * microcontroller features, one would need to disassembly the firmware. + * note: the vendor refused to give any information on this product, all + * that stuff was found using a multimeter! :) + */ +static void rv605_muxsel(struct bttv *btv, unsigned int input) +{ + static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0, + 0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa }; + + gpio_bits(0x07f, muxgpio[input]); + + /* reset all conections */ + gpio_bits(0x200,0x200); + mdelay(1); + gpio_bits(0x200,0x000); + mdelay(1); + + /* create a new connection */ + gpio_bits(0x480,0x480); + mdelay(1); + gpio_bits(0x480,0x080); + mdelay(1); +} + +/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning] + * + * The CS16 (available on eBay cheap) is a PCI board with four Fusion + * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator + * chips, ten eight input analog multiplexors, a not chip and a few + * other components. + * + * 16 inputs on a secondary bracket are provided and can be selected + * from each of the four capture chips. Two of the eight input + * multiplexors are used to select from any of the 16 input signals. + * + * Unsupported hardware capabilities: + * . A video output monitor on the secondary bracket can be selected from + * one of the 878A chips. + * . Another passthrough but I haven't spent any time investigating it. + * . Digital I/O (logic level connected to GPIO) is available from an + * onboard header. + * + * The on chip input mux should always be set to 2. + * GPIO[16:19] - Video input selection + * GPIO[0:3] - Video output monitor select (only available from one 878A) + * GPIO[?:?] - Digital I/O. + * + * There is an ATMEL microcontroller with an 8031 core on board. I have not + * determined what function (if any) it provides. With the microcontroller + * and sync separator chips a guess is that it might have to do with video + * switching and maybe some digital I/O. + */ +static void tibetCS16_muxsel(struct bttv *btv, unsigned int input) +{ + /* video mux */ + gpio_bits(0x0f0000, input << 16); +} + +static void tibetCS16_init(struct bttv *btv) +{ + /* enable gpio bits, mask obtained via btSpy */ + gpio_inout(0xffffff, 0x0f7fff); + gpio_write(0x0f7fff); +} + +/* + * The following routines for the Kodicom-4400r get a little mind-twisting. + * There is a "master" controller and three "slave" controllers, together + * an analog switch which connects any of 16 cameras to any of the BT87A's. + * The analog switch is controlled by the "master", but the detection order + * of the four BT878A chips is in an order which I just don't understand. + * The "master" is actually the second controller to be detected. The + * logic on the board uses logical numbers for the 4 controllers, but + * those numbers are different from the detection sequence. When working + * with the analog switch, we need to "map" from the detection sequence + * over to the board's logical controller number. This mapping sequence + * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical + * unit 3, the second (which is the master) is logical unit 0, etc. + * We need to maintain the status of the analog switch (which of the 16 + * cameras is connected to which of the 4 controllers). Rather than + * add to the bttv structure for this, we use the data reserved for + * the mbox (unused for this card type). + */ + +/* + * First a routine to set the analog switch, which controls which camera + * is routed to which controller. The switch comprises an X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). + * A data value (gpio bit 7) of '1' enables the switch, and '0' disables + * the switch. A STROBE bit (gpio bit 8) latches the data value into the + * specified address. The idea is to set the address and data, then bring + * STROBE high, and finally bring STROBE back to low. + */ +static void kodicom4400r_write(struct bttv *btv, + unsigned char xaddr, + unsigned char yaddr, + unsigned char data) { + unsigned int udata; + + udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf); + gpio_bits(0x1ff, udata); /* write ADDR and DAT */ + gpio_bits(0x1ff, udata | (1 << 8)); /* strobe high */ + gpio_bits(0x1ff, udata); /* strobe low */ +} + +/* + * Next the mux select. Both the "master" and "slave" 'cards' (controllers) + * use this routine. The routine finds the "master" for the card, maps + * the controller number from the detected position over to the logical + * number, writes the appropriate data to the analog switch, and housekeeps + * the local copy of the switch information. The parameter 'input' is the + * requested camera number (0 - 15). + */ +static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input) +{ + char *sw_status; + int xaddr, yaddr; + struct bttv *mctlr; + static unsigned char map[4] = {3, 0, 2, 1}; + + mctlr = master[btv->c.nr]; + if (mctlr == NULL) { /* ignore if master not yet detected */ + return; + } + yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */ + yaddr = map[yaddr]; + sw_status = (char *)(&mctlr->mbox_we); + xaddr = input & 0xf; + /* Check if the controller/camera pair has changed, else ignore */ + if (sw_status[yaddr] != xaddr) + { + /* "open" the old switch, "close" the new one, save the new */ + kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0); + sw_status[yaddr] = xaddr; + kodicom4400r_write(mctlr, xaddr, yaddr, 1); + } +} + +/* + * During initialisation, we need to reset the analog switch. We + * also preset the switch to map the 4 connectors on the card to the + * *user's* (see above description of kodicom4400r_muxsel) channels + * 0 through 3 + */ +static void kodicom4400r_init(struct bttv *btv) +{ + char *sw_status = (char *)(&btv->mbox_we); + int ix; + + gpio_inout(0x0003ff, 0x0003ff); + gpio_write(1 << 9); /* reset MUX */ + gpio_write(0); + /* Preset camera 0 to the 4 controllers */ + for (ix = 0; ix < 4; ix++) { + sw_status[ix] = ix; + kodicom4400r_write(btv, ix, ix, 1); + } + /* + * Since this is the "master", we need to set up the + * other three controller chips' pointers to this structure + * for later use in the muxsel routine. + */ + if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3)) + return; + master[btv->c.nr-1] = btv; + master[btv->c.nr] = btv; + master[btv->c.nr+1] = btv; + master[btv->c.nr+2] = btv; +} + +/* 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, + }; + gpio_write(masks[input%16]); +} +static void picolo_tetra_init(struct bttv *btv) +{ + /*This is the video input redirection fonctionality : I DID NOT USED IT. */ + btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */ + btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A] set to 1*/ +} +static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) +{ + + dprintk("%d : picolo_tetra_muxsel => input = %d\n", btv->c.nr, input); + /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ + /*GPIO[20]&GPIO[21] used to choose the right input*/ + btwrite (input<<20,BT848_GPIO_DATA); + +} + +/* + * ivc120_muxsel [Added by Alan Garfield ] + * + * The IVC120G security card has 4 i2c controlled TDA8540 matrix + * swichers to provide 16 channels to MUX0. The TDA8540's have + * 4 independent outputs and as such the IVC120G also has the + * optional "Monitor Out" bus. This allows the card to be looking + * at one input while the monitor is looking at another. + * + * Since I've couldn't be bothered figuring out how to add an + * independent muxsel for the monitor bus, I've just set it to + * whatever the card is looking at. + * + * OUT0 of the TDA8540's is connected to MUX0 (0x03) + * OUT1 of the TDA8540's is connected to "Monitor Out" (0x0C) + * + * TDA8540_ALT3 IN0-3 = Channel 13 - 16 (0x03) + * TDA8540_ALT4 IN0-3 = Channel 1 - 4 (0x03) + * TDA8540_ALT5 IN0-3 = Channel 5 - 8 (0x03) + * TDA8540_ALT6 IN0-3 = Channel 9 - 12 (0x03) + * + */ + +/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */ +#define I2C_TDA8540 0x90 +#define I2C_TDA8540_ALT1 0x92 +#define I2C_TDA8540_ALT2 0x94 +#define I2C_TDA8540_ALT3 0x96 +#define I2C_TDA8540_ALT4 0x98 +#define I2C_TDA8540_ALT5 0x9a +#define I2C_TDA8540_ALT6 0x9c + +static void ivc120_muxsel(struct bttv *btv, unsigned int input) +{ + /* Simple maths */ + int key = input % 4; + int matrix = input / 4; + + dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", + btv->c.nr, input, matrix, key); + + /* Handles the input selection on the TDA8540's */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, + ((matrix == 3) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, + ((matrix == 0) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00, + ((matrix == 1) ? (key | key << 2) : 0x00), 1); + bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, + ((matrix == 2) ? (key | key << 2) : 0x00), 1); + + /* Handles the output enables on the TDA8540's */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, + ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, + ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, + ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ + bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, + ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ + + /* 878's MUX0 is already selected for input via muxsel values */ +} + + +/* PXC200 muxsel helper + * luke@syseng.anu.edu.au + * another transplant + * from Alessandro Rubini (rubini@linux.it) + * + * There are 4 kinds of cards: + * PXC200L which is bt848 + * PXC200F which is bt848 with PIC controlling mux + * PXC200AL which is bt878 + * PXC200AF which is bt878 with PIC controlling mux + */ +#define PX_CFG_PXC200F 0x01 +#define PX_FLAG_PXC200A 0x00001000 /* a pxc200A is bt-878 based */ +#define PX_I2C_PIC 0x0f +#define PX_PXC200A_CARDID 0x200a1295 +#define PX_I2C_CMD_CFG 0x00 + +static void PXC200_muxsel(struct bttv *btv, unsigned int input) +{ + int rc; + long mux; + int bitmask; + unsigned char buf[2]; + + /* Read PIC config to determine if this is a PXC200F */ + /* PX_I2C_CMD_CFG*/ + buf[0]=0; + buf[1]=0; + rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); + if (rc) { + pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n", + btv->c.nr, rc); + /* not PXC ? do nothing */ + return; + } + + rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); + if (!(rc & PX_CFG_PXC200F)) { + pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n", + btv->c.nr, rc); + return; + } + + + /* The multiplexer in the 200F is handled by the GPIO port */ + /* get correct mapping between inputs */ + /* mux = bttv_tvcards[btv->type].muxsel[input] & 3; */ + /* ** not needed!? */ + mux = input; + + /* make sure output pins are enabled */ + /* bitmask=0x30f; */ + bitmask=0x302; + /* check whether we have a PXC200A */ + if (btv->cardid == PX_PXC200A_CARDID) { + bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */ + bitmask |= 7<<4; /* the DAC */ + } + btwrite(bitmask, BT848_GPIO_OUT_EN); + + bitmask = btread(BT848_GPIO_DATA); + if (btv->cardid == PX_PXC200A_CARDID) + bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7); + else /* older device */ + bitmask = (bitmask & ~0x300) | ((mux & 3) << 8); + btwrite(bitmask,BT848_GPIO_DATA); + + /* + * Was "to be safe, set the bt848 to input 0" + * Actually, since it's ok at load time, better not messing + * with these bits (on PXC200AF you need to set mux 2 here) + * + * needed because bttv-driver sets mux before calling this function + */ + if (btv->cardid == PX_PXC200A_CARDID) + btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM); + else /* older device */ + btand(~BT848_IFORM_MUXSEL,BT848_IFORM); + + pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux); +} + +static void phytec_muxsel(struct bttv *btv, unsigned int input) +{ + unsigned int mux = input % 4; + + if (input == btv->svhs) + mux = 0; + + gpio_bits(0x3, mux); +} + +/* + * GeoVision GV-800(S) functions + * Bruno Christo +*/ + +/* This is a function to control the analog switch, which determines which + * camera is routed to which controller. The switch comprises an X-address + * (gpio bits 0-3, representing the camera, ranging from 0-15), and a + * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). + * A data value (gpio bit 18) of '1' enables the switch, and '0' disables + * the switch. A STROBE bit (gpio bit 17) latches the data value into the + * specified address. There is also a chip select (gpio bit 16). + * The idea is to set the address and chip select together, bring + * STROBE high, write the data, and finally bring STROBE back to low. + */ +static void gv800s_write(struct bttv *btv, + unsigned char xaddr, + unsigned char yaddr, + unsigned char data) { + /* On the "master" 878A: + * GPIO bits 0-9 are used for the analog switch: + * 00 - 03: camera selector + * 04 - 06: 878A (controller) selector + * 16: cselect + * 17: strobe + * 18: data (1->on, 0->off) + * 19: reset + */ + const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4); + const u32 CSELECT = 1<<16; + const u32 STROBE = 1<<17; + const u32 DATA = data<<18; + + gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */ + gpio_bits(0x20000, STROBE); /* STROBE high */ + gpio_bits(0x40000, DATA); /* write DATA */ + gpio_bits(0x20000, ~STROBE); /* STROBE low */ +} + +/* + * GeoVision GV-800(S) muxsel + * + * Each of the 4 cards (controllers) use this function. + * The controller using this function selects the input through the GPIO pins + * of the "master" card. A pointer to this card is stored in master[btv->c.nr]. + * + * The parameter 'input' is the requested camera number (0-4) on the controller. + * The map array has the address of each input. Note that the addresses in the + * array are in the sequence the original GeoVision driver uses, that is, set + * every controller to input 0, then to input 1, 2, 3, repeat. This means that + * the physical "camera 1" connector corresponds to controller 0 input 0, + * "camera 2" corresponds to controller 1 input 0, and so on. + * + * After getting the input address, the function then writes the appropriate + * data to the analog switch, and housekeeps the local copy of the switch + * information. + */ +static void gv800s_muxsel(struct bttv *btv, unsigned int input) +{ + struct bttv *mctlr; + char *sw_status; + int xaddr, yaddr; + static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 }, + { 0x1, 0x5, 0xb, 0x7 }, + { 0x2, 0x8, 0xc, 0xe }, + { 0x3, 0x9, 0xd, 0xf } }; + input = input%4; + mctlr = master[btv->c.nr]; + if (mctlr == NULL) { + /* do nothing until the "master" is detected */ + return; + } + yaddr = (btv->c.nr - mctlr->c.nr) & 3; + sw_status = (char *)(&mctlr->mbox_we); + xaddr = map[yaddr][input] & 0xf; + + /* Check if the controller/camera pair has changed, ignore otherwise */ + if (sw_status[yaddr] != xaddr) { + /* disable the old switch, enable the new one and save status */ + gv800s_write(mctlr, sw_status[yaddr], yaddr, 0); + sw_status[yaddr] = xaddr; + gv800s_write(mctlr, xaddr, yaddr, 1); + } +} + +/* GeoVision GV-800(S) "master" chip init */ +static void gv800s_init(struct bttv *btv) +{ + char *sw_status = (char *)(&btv->mbox_we); + int ix; + + gpio_inout(0xf107f, 0xf107f); + gpio_write(1<<19); /* reset the analog MUX */ + gpio_write(0); + + /* Preset camera 0 to the 4 controllers */ + for (ix = 0; ix < 4; ix++) { + sw_status[ix] = ix; + gv800s_write(btv, ix, ix, 1); + } + + /* Inputs on the "master" controller need this brightness fix */ + bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1); + + if (btv->c.nr > BTTV_MAX-4) + return; + /* + * Store the "master" controller pointer in the master + * array for later use in the muxsel function. + */ + master[btv->c.nr] = btv; + master[btv->c.nr+1] = btv; + master[btv->c.nr+2] = btv; + master[btv->c.nr+3] = btv; +} + +/* ----------------------------------------------------------------------- */ +/* motherboard chipset specific stuff */ + +void __init bttv_check_chipset(void) +{ + int pcipci_fail = 0; + struct pci_dev *dev = NULL; + + if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */ + pcipci_fail = 1; + if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF)) + triton1 = 1; + if (pci_pci_problems & PCIPCI_VSFX) + vsfx = 1; +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) + latency = 0x0A; +#endif + + + /* print warnings about any quirks found */ + if (triton1) + pr_info("Host bridge needs ETBF enabled\n"); + if (vsfx) + pr_info("Host bridge needs VSFX enabled\n"); + if (pcipci_fail) { + pr_info("bttv and your chipset may not work together\n"); + if (!no_overlay) { + pr_info("overlay will be disabled\n"); + no_overlay = 1; + } else { + pr_info("overlay forced. Use this option at your own risk.\n"); + } + } + if (UNSET != latency) + pr_info("pci latency fixup [%d]\n", latency); + while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + if (bttv_debug) + pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n", + b); + } +} + +int __devinit bttv_handle_chipset(struct bttv *btv) +{ + unsigned char command; + + if (!triton1 && !vsfx && UNSET == latency) + return 0; + + if (bttv_verbose) { + if (triton1) + pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n", + btv->c.nr); + if (vsfx && btv->id >= 878) + pr_info("%d: enabling VSFX\n", btv->c.nr); + if (UNSET != latency) + pr_info("%d: setting pci timer to %d\n", + btv->c.nr, latency); + } + + if (btv->id < 878) { + /* bt848 (mis)uses a bit in the irq mask for etbf */ + if (triton1) + btv->triton1 = BT848_INT_ETBF; + } else { + /* bt878 has a bit in the pci config space for it */ + pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command); + if (triton1) + command |= BT878_EN_TBFX; + if (vsfx) + command |= BT878_EN_VSFX; + pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command); + } + if (UNSET != latency) + pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); + return 0; +} + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c new file mode 100644 index 000000000000..b58ff87db771 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -0,0 +1,4630 @@ +/* + + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97,98 Ralph Metzler + & Marcus Metzler + (c) 1999-2002 Gerd Knorr + + some v4l2 code lines are taken from Justin's bttv2 driver which is + (c) 2000 Justin Schoeman + + V4L1 removal from: + (c) 2005-2006 Nickolay V. Shmyrev + + Fixes to be fully V4L2 compliant by + (c) 2006 Mauro Carvalho Chehab + + Cropping and overscan support + Copyright (C) 2005, 2006 Michael H. Schimek + Sponsored by OPQ Systems AB + + 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bttvp.h" +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#define BTTV_VERSION "0.9.19" + +unsigned int bttv_num; /* number of Bt848s in use */ +struct bttv *bttvs[BTTV_MAX]; + +unsigned int bttv_debug; +unsigned int bttv_verbose = 1; +unsigned int bttv_gpio; + +/* config variables */ +#ifdef __BIG_ENDIAN +static unsigned int bigendian=1; +#else +static unsigned int bigendian; +#endif +static unsigned int radio[BTTV_MAX]; +static unsigned int irq_debug; +static unsigned int gbuffers = 8; +static unsigned int gbufsize = 0x208000; +static unsigned int reset_crop = 1; + +static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; +static int debug_latency; +static int disable_ir; + +static unsigned int fdsr; + +/* options */ +static unsigned int combfilter; +static unsigned int lumafilter; +static unsigned int automute = 1; +static unsigned int chroma_agc; +static unsigned int adc_crush = 1; +static unsigned int whitecrush_upper = 0xCF; +static unsigned int whitecrush_lower = 0x7F; +static unsigned int vcr_hack; +static unsigned int irq_iswitch; +static unsigned int uv_ratio = 50; +static unsigned int full_luma_range; +static unsigned int coring; + +/* API features (turn on/off stuff for testing) */ +static unsigned int v4l2 = 1; + +/* insmod args */ +module_param(bttv_verbose, int, 0644); +module_param(bttv_gpio, int, 0644); +module_param(bttv_debug, int, 0644); +module_param(irq_debug, int, 0644); +module_param(debug_latency, int, 0644); +module_param(disable_ir, int, 0444); + +module_param(fdsr, int, 0444); +module_param(gbuffers, int, 0444); +module_param(gbufsize, int, 0444); +module_param(reset_crop, int, 0444); + +module_param(v4l2, int, 0644); +module_param(bigendian, int, 0644); +module_param(irq_iswitch, int, 0644); +module_param(combfilter, int, 0444); +module_param(lumafilter, int, 0444); +module_param(automute, int, 0444); +module_param(chroma_agc, int, 0444); +module_param(adc_crush, int, 0444); +module_param(whitecrush_upper, int, 0444); +module_param(whitecrush_lower, int, 0444); +module_param(vcr_hack, int, 0444); +module_param(uv_ratio, int, 0444); +module_param(full_luma_range, int, 0444); +module_param(coring, int, 0444); + +module_param_array(radio, int, NULL, 0444); +module_param_array(video_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); + +MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); +MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); +MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); +MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); +MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); +MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); +MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); +MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); +MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " + "is 1 (yes) for compatibility with older applications"); +MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); +MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); +MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); +MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); +MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); +MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); +MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(BTTV_VERSION); + +/* ----------------------------------------------------------------------- */ +/* sysfs */ + +static ssize_t show_card(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct video_device *vfd = container_of(cd, struct video_device, dev); + struct bttv *btv = video_get_drvdata(vfd); + return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); +} +static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); + +/* ----------------------------------------------------------------------- */ +/* dvb auto-load setup */ +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + request_module("dvb-bt8xx"); +} + +static void request_modules(struct bttv *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct bttv *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + + +/* ----------------------------------------------------------------------- */ +/* static data */ + +/* special timing tables from conexant... */ +static u8 SRAM_Table[][60] = +{ + /* PAL digital input over GPIO[7:0] */ + { + 45, // 45 bytes following + 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16, + 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00, + 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00, + 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37, + 0x37,0x00,0xAF,0x21,0x00 + }, + /* NTSC digital input over GPIO[7:0] */ + { + 51, // 51 bytes following + 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06, + 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00, + 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07, + 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6, + 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21, + 0x00, + }, + // TGB_NTSC392 // quartzsight + // This table has been modified to be used for Fusion Rev D + { + 0x2A, // size of table = 42 + 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24, + 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10, + 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00, + 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3, + 0x20, 0x00 + } +}; + +/* minhdelayx1 first video pixel we can capture on a line and + hdelayx1 start of active video, both relative to rising edge of + /HRESET pulse (0H) in 1 / fCLKx1. + swidth width of active video and + totalwidth total line width, both in 1 / fCLKx1. + sqwidth total line width in square pixels. + vdelay start of active video in 2 * field lines relative to + trailing edge of /VRESET pulse (VDELAY register). + sheight height of active video in 2 * field lines. + videostart0 ITU-R frame line number of the line corresponding + to vdelay in the first field. */ +#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ + vdelay, sheight, videostart0) \ + .cropcap.bounds.left = minhdelayx1, \ + /* * 2 because vertically we count field lines times two, */ \ + /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ + .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ + /* 4 is a safety margin at the end of the line. */ \ + .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ + .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ + .cropcap.defrect.left = hdelayx1, \ + .cropcap.defrect.top = (videostart0) * 2, \ + .cropcap.defrect.width = swidth, \ + .cropcap.defrect.height = sheight, \ + .cropcap.pixelaspect.numerator = totalwidth, \ + .cropcap.pixelaspect.denominator = sqwidth, + +const struct bttv_tvnorm bttv_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 */ + { + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 924, + .vdelay = 0x20, + .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */ + .sram = 0, + /* ITU-R frame line number of the first VBI line + we can capture, of the first and second field. + The last line is determined by cropcap.bounds. */ + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* Should be (768 * 1135 + 944 / 2) / 944. + cropcap.defrect is used for image width + checks, so we keep the old value 924. */ + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + /* bt878 (and bt848?) can capture another + line below active video. */ + .cropcap.bounds.height = (576 + 2) + 0x20 - 2, + },{ + .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, + .name = "NTSC", + .Fsc = 28636363, + .swidth = 768, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0), + .scaledtwidth = 910, + .hdelayx1 = 128, + .hactivex1 = 910, + .vdelay = 0x1a, + .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */ + .sram = 1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 128, + /* Should be (640 * 910 + 780 / 2) / 780? */ + /* swidth */ 768, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_SECAM, + .name = "SECAM", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0xb0, + .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 255, + .sram = 0, /* like PAL, correct? */ + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_Nc, + .name = "PAL-Nc", + .Fsc = 28636363, + .swidth = 640, + .sheight = 576, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 130, + .hactivex1 = 734, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 130, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_M, + .name = "PAL-M", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 135, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_PAL_N, + .name = "PAL-N", + .Fsc = 35468950, + .swidth = 768, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1), + .scaledtwidth = 944, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 144, + .sram = -1, + .vbistart = { 7, 320 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ (768 * 1135 + 944 / 2) / 944, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x20, + /* sheight */ 576, + /* videostart0 */ 23) + },{ + .v4l2_id = V4L2_STD_NTSC_M_JP, + .name = "NTSC-JP", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x16, + .vbipack = 144, + .sram = -1, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 135, + /* swidth */ (640 * 910 + 780 / 2) / 780, + /* totalwidth */ 910, + /* sqwidth */ 780, + /* vdelay */ 0x16, + /* sheight */ 480, + /* videostart0 */ 23) + },{ + /* 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, + .vbistart = { 10, 273 }, + CROPCAP(/* minhdelayx1 */ 68, + /* hdelayx1 */ 186, + /* swidth */ 924, + /* totalwidth */ 1135, + /* sqwidth */ 944, + /* vdelay */ 0x1a, + /* sheight */ 480, + /* videostart0 */ 23) + } +}; +static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); + +/* ----------------------------------------------------------------------- */ +/* bttv format list + packed pixel formats must come first */ +static const struct bttv_format formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .btformat = BT848_COLOR_FMT_Y8, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "8 bpp, dithered color", + .fourcc = V4L2_PIX_FMT_HI240, + .btformat = BT848_COLOR_FMT_RGB8, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, + },{ + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .btformat = BT848_COLOR_FMT_RGB15, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .btformat = BT848_COLOR_FMT_RGB15, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .btformat = BT848_COLOR_FMT_RGB16, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .btformat = BT848_COLOR_FMT_RGB16, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .btformat = BT848_COLOR_FMT_RGB24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .btformat = BT848_COLOR_FMT_RGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .btformat = BT848_COLOR_FMT_RGB32, + .btswap = 0x0f, /* byte+word swap */ + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .btformat = BT848_COLOR_FMT_YUY2, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .btformat = BT848_COLOR_FMT_YUY2, + .btswap = 0x03, /* byteswap */ + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + },{ + .name = "4:2:2, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV422P, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 16, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 1, + .vshift = 0, + },{ + .name = "4:2:0, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV420, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 1, + .vshift = 1, + },{ + .name = "4:2:0, planar, Y-Cr-Cb", + .fourcc = V4L2_PIX_FMT_YVU420, + .btformat = BT848_COLOR_FMT_YCrCb422, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, + .hshift = 1, + .vshift = 1, + },{ + .name = "4:1:1, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV411P, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 12, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 2, + .vshift = 0, + },{ + .name = "4:1:0, planar, Y-Cb-Cr", + .fourcc = V4L2_PIX_FMT_YUV410, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 9, + .flags = FORMAT_FLAGS_PLANAR, + .hshift = 2, + .vshift = 2, + },{ + .name = "4:1:0, planar, Y-Cr-Cb", + .fourcc = V4L2_PIX_FMT_YVU410, + .btformat = BT848_COLOR_FMT_YCrCb411, + .depth = 9, + .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, + .hshift = 2, + .vshift = 2, + },{ + .name = "raw scanlines", + .fourcc = -1, + .btformat = BT848_COLOR_FMT_RAW, + .depth = 8, + .flags = FORMAT_FLAGS_RAW, + } +}; +static const unsigned int FORMATS = ARRAY_SIZE(formats); + +/* ----------------------------------------------------------------------- */ + +#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; +static const struct v4l2_queryctrl bttv_ctls[] = { + /* --- video --- */ + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 65535, + .step = 256, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 65535, + .step = 128, + .default_value = 27648, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 65535, + .step = 128, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 65535, + .step = 256, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + /* --- audio --- */ + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 65535, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_BASS, + .name = "Bass", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_TREBLE, + .name = "Treble", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + /* --- private --- */ + { + .id = V4L2_CID_PRIVATE_CHROMA_AGC, + .name = "chroma agc", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_COMBFILTER, + .name = "combfilter", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "automute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_LUMAFILTER, + .name = "luma decimation filter", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_AGC_CRUSH, + .name = "agc crush", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_VCR_HACK, + .name = "vcr hack", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, + .name = "whitecrush upper", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0xCF, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, + .name = "whitecrush lower", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x7F, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "uv ratio", + .minimum = 0, + .maximum = 100, + .step = 1, + .default_value = 50, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "full luma range", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_CORING, + .name = "coring", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } + + + +}; + +static const struct v4l2_queryctrl *ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) + if (bttv_ctls[i].id == id) + return bttv_ctls+i; + + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* resource management */ + +/* + RESOURCE_ allocated by freed by + + VIDEO_READ bttv_read 1) bttv_read 2) + + VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF + VIDIOC_QBUF 1) bttv_release + VIDIOCMCAPTURE 1) + + OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off + VIDIOC_OVERLAY on VIDIOC_OVERLAY off + 3) bttv_release + + VBI VIDIOC_STREAMON VIDIOC_STREAMOFF + VIDIOC_QBUF 1) bttv_release + bttv_read, bttv_poll 1) 4) + + 1) The resource must be allocated when we enter buffer prepare functions + and remain allocated while buffers are in the DMA queue. + 2) This is a single frame read. + 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when + RESOURCE_OVERLAY is allocated. + 4) This is a continuous read, implies VIDIOC_STREAMON. + + Note this driver permits video input and standard changes regardless if + resources are allocated. +*/ + +#define VBI_RESOURCES (RESOURCE_VBI) +#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \ + RESOURCE_VIDEO_STREAM | \ + RESOURCE_OVERLAY) + +static +int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) +{ + int xbits; /* mutual exclusive resources */ + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + xbits = bit; + if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM)) + xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; + + /* is it free? */ + if (btv->resources & xbits) { + /* no, someone else uses it */ + goto fail; + } + + if ((bit & VIDEO_RESOURCES) + && 0 == (btv->resources & VIDEO_RESOURCES)) { + /* Do crop - use current, don't - use default parameters. */ + __s32 top = btv->crop[!!fh->do_crop].rect.top; + + if (btv->vbi_end > top) + goto fail; + + /* We cannot capture the same line as video and VBI data. + Claim scan lines crop[].rect.top to bottom. */ + btv->crop_start = top; + } else if (bit & VBI_RESOURCES) { + __s32 end = fh->vbi_fmt.end; + + if (end > btv->crop_start) + goto fail; + + /* Claim scan lines above fh->vbi_fmt.end. */ + btv->vbi_end = end; + } + + /* it's free, grab it */ + fh->resources |= bit; + btv->resources |= bit; + return 1; + + fail: + return 0; +} + +static +int check_btres(struct bttv_fh *fh, int bit) +{ + return (fh->resources & bit); +} + +static +int locked_btres(struct bttv *btv, int bit) +{ + return (btv->resources & bit); +} + +/* Call with btv->lock down. */ +static void +disclaim_vbi_lines(struct bttv *btv) +{ + btv->vbi_end = 0; +} + +/* Call with btv->lock down. */ +static void +disclaim_video_lines(struct bttv *btv) +{ + const struct bttv_tvnorm *tvnorm; + u8 crop; + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + btv->crop_start = tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height; + + /* VBI capturing ends at VDELAY, start of video capturing, no + matter how many lines the VBI RISC program expects. When video + capturing is off, it shall no longer "preempt" VBI capturing, + so we set VDELAY to maximum. */ + crop = btread(BT848_E_CROP) | 0xc0; + btwrite(crop, BT848_E_CROP); + btwrite(0xfe, BT848_E_VDELAY_LO); + btwrite(crop, BT848_O_CROP); + btwrite(0xfe, BT848_O_VDELAY_LO); +} + +static +void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) +{ + if ((fh->resources & bits) != bits) { + /* trying to free resources not allocated by us ... */ + pr_err("BUG! (btres)\n"); + } + fh->resources &= ~bits; + btv->resources &= ~bits; + + bits = btv->resources; + + if (0 == (bits & VIDEO_RESOURCES)) + disclaim_video_lines(btv); + + if (0 == (bits & VBI_RESOURCES)) + disclaim_vbi_lines(btv); +} + +/* ----------------------------------------------------------------------- */ +/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */ + +/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C + PLL_X = Reference pre-divider (0=1, 1=2) + PLL_C = Post divider (0=6, 1=4) + PLL_I = Integer input + PLL_F = Fractional input + + F_input = 28.636363 MHz: + PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 +*/ + +static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) +{ + unsigned char fl, fh, fi; + + /* prevent overflows */ + fin/=4; + fout/=4; + + fout*=12; + fi=fout/fin; + + fout=(fout%fin)*256; + fh=fout/fin; + + fout=(fout%fin)*256; + fl=fout/fin; + + btwrite(fl, BT848_PLL_F_LO); + btwrite(fh, BT848_PLL_F_HI); + btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); +} + +static void set_pll(struct bttv *btv) +{ + int i; + + if (!btv->pll.pll_crystal) + return; + + if (btv->pll.pll_ofreq == btv->pll.pll_current) { + dprintk("%d: PLL: no change required\n", btv->c.nr); + return; + } + + if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { + /* no PLL needed */ + if (btv->pll.pll_current == 0) + return; + if (bttv_verbose) + pr_info("%d: PLL can sleep, using XTAL (%d)\n", + btv->c.nr, btv->pll.pll_ifreq); + btwrite(0x00,BT848_TGCTRL); + btwrite(0x00,BT848_PLL_XCI); + btv->pll.pll_current = 0; + return; + } + + if (bttv_verbose) + pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n", + btv->c.nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); + set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + for (i=0; i<10; i++) { + /* Let other people run while the PLL stabilizes */ + msleep(10); + + if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { + btwrite(0,BT848_DSTATUS); + } else { + btwrite(0x08,BT848_TGCTRL); + btv->pll.pll_current = btv->pll.pll_ofreq; + if (bttv_verbose) + pr_info("PLL set ok\n"); + return; + } + } + btv->pll.pll_current = -1; + if (bttv_verbose) + pr_info("Setting PLL failed\n"); + return; +} + +/* used to switch between the bt848's analog/digital video capture modes */ +static void bt848A_set_timing(struct bttv *btv) +{ + int i, len; + int table_idx = bttv_tvnorms[btv->tvnorm].sram; + int fsc = bttv_tvnorms[btv->tvnorm].Fsc; + + if (btv->input == btv->dig) { + dprintk("%d: load digital timing table (table_idx=%d)\n", + btv->c.nr,table_idx); + + /* timing change...reset timing generator address */ + btwrite(0x00, BT848_TGCTRL); + btwrite(0x02, BT848_TGCTRL); + btwrite(0x00, BT848_TGCTRL); + + len=SRAM_Table[table_idx][0]; + for(i = 1; i <= len; i++) + btwrite(SRAM_Table[table_idx][i],BT848_TGLB); + btv->pll.pll_ofreq = 27000000; + + set_pll(btv); + btwrite(0x11, BT848_TGCTRL); + btwrite(0x41, BT848_DVSIF); + } else { + btv->pll.pll_ofreq = fsc; + set_pll(btv); + btwrite(0x0, BT848_DVSIF); + } +} + +/* ----------------------------------------------------------------------- */ + +static void bt848_bright(struct bttv *btv, int bright) +{ + int value; + + // printk("set bright: %d\n", bright); // DEBUG + btv->bright = bright; + + /* We want -128 to 127 we get 0-65535 */ + value = (bright >> 8) - 128; + btwrite(value & 0xff, BT848_BRIGHT); +} + +static void bt848_hue(struct bttv *btv, int hue) +{ + int value; + + btv->hue = hue; + + /* -128 to 127 */ + value = (hue >> 8) - 128; + btwrite(value & 0xff, BT848_HUE); +} + +static void bt848_contrast(struct bttv *btv, int cont) +{ + int value,hibit; + + btv->contrast = cont; + + /* 0-511 */ + value = (cont >> 7); + hibit = (value >> 6) & 4; + btwrite(value & 0xff, BT848_CONTRAST_LO); + btaor(hibit, ~4, BT848_E_CONTROL); + btaor(hibit, ~4, BT848_O_CONTROL); +} + +static void bt848_sat(struct bttv *btv, int color) +{ + int val_u,val_v,hibits; + + btv->saturation = color; + + /* 0-511 for the color */ + val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; + val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; + hibits = (val_u >> 7) & 2; + hibits |= (val_v >> 8) & 1; + btwrite(val_u & 0xff, BT848_SAT_U_LO); + btwrite(val_v & 0xff, BT848_SAT_V_LO); + btaor(hibits, ~3, BT848_E_CONTROL); + btaor(hibits, ~3, BT848_O_CONTROL); +} + +/* ----------------------------------------------------------------------- */ + +static int +video_mux(struct bttv *btv, unsigned int input) +{ + int mux,mask2; + + if (input >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + + /* needed by RemoteVideo MX */ + mask2 = bttv_tvcards[btv->c.type].gpiomask2; + if (mask2) + gpio_inout(mask2,mask2); + + if (input == btv->svhs) { + btor(BT848_CONTROL_COMP, BT848_E_CONTROL); + btor(BT848_CONTROL_COMP, BT848_O_CONTROL); + } else { + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); + } + mux = bttv_muxsel(btv, input); + btaor(mux<<5, ~(3<<5), BT848_IFORM); + dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux); + + /* card specific hook */ + if(bttv_tvcards[btv->c.type].muxsel_hook) + bttv_tvcards[btv->c.type].muxsel_hook (btv, input); + return 0; +} + +static char *audio_modes[] = { + "audio: tuner", "audio: radio", "audio: extern", + "audio: intern", "audio: mute" +}; + +static int +audio_mux(struct bttv *btv, int input, int mute) +{ + int gpio_val, signal; + struct v4l2_control ctrl; + + gpio_inout(bttv_tvcards[btv->c.type].gpiomask, + bttv_tvcards[btv->c.type].gpiomask); + signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; + + btv->mute = mute; + btv->audio = input; + + /* automute */ + mute = mute || (btv->opt_automute && !signal && !btv->radio_user); + + if (mute) + gpio_val = bttv_tvcards[btv->c.type].gpiomute; + else + gpio_val = bttv_tvcards[btv->c.type].gpiomux[input]; + + switch (btv->c.type) { + case BTTV_BOARD_VOODOOTV_FM: + case BTTV_BOARD_VOODOOTV_200: + gpio_val = bttv_tda9880_setnorm(btv, gpio_val); + break; + + default: + gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val); + } + + if (bttv_gpio) + bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]); + if (in_interrupt()) + return 0; + + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = btv->mute; + bttv_call_all(btv, core, s_ctrl, &ctrl); + if (btv->sd_msp34xx) { + u32 in; + + /* Note: the inputs tuner/radio/extern/intern are translated + to msp routings. This assumes common behavior for all msp3400 + based TV cards. When this assumption fails, then the + specific MSP routing must be added to the card table. + For now this is sufficient. */ + switch (input) { + case TVAUDIO_INPUT_RADIO: + /* Some boards need the msp do to the radio demod */ + if (btv->radio_uses_msp_demodulator) { + in = MSP_INPUT_DEFAULT; + break; + } + in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_EXTERN: + in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_INTERN: + /* Yes, this is the same input as for RADIO. I doubt + if this is ever used. The only board with an INTERN + input is the BTTV_BOARD_AVERMEDIA98. I wonder how + that was tested. My guess is that the whole INTERN + input does not work. */ + in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case TVAUDIO_INPUT_TUNER: + default: + /* This is the only card that uses TUNER2, and afaik, + is the only difference between the VOODOOTV_FM + and VOODOOTV_200 */ + if (btv->c.type == BTTV_BOARD_VOODOOTV_200) + in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \ + MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); + else + in = MSP_INPUT_DEFAULT; + break; + } + v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, + in, MSP_OUTPUT_DEFAULT, 0); + } + if (btv->sd_tvaudio) { + v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, + input, 0, 0); + } + return 0; +} + +static inline int +audio_mute(struct bttv *btv, int mute) +{ + return audio_mux(btv, btv->audio, mute); +} + +static inline int +audio_input(struct bttv *btv, int input) +{ + return audio_mux(btv, input, btv->mute); +} + +static void +bttv_crop_calc_limits(struct bttv_crop *c) +{ + /* Scale factor min. 1:1, max. 16:1. Min. image size + 48 x 32. Scaled width must be a multiple of 4. */ + + if (1) { + /* For bug compatibility with VIDIOCGCAP and image + size checks in earlier driver versions. */ + c->min_scaled_width = 48; + c->min_scaled_height = 32; + } else { + c->min_scaled_width = + (max(48, c->rect.width >> 4) + 3) & ~3; + c->min_scaled_height = + max(32, c->rect.height >> 4); + } + + c->max_scaled_width = c->rect.width & ~3; + c->max_scaled_height = c->rect.height; +} + +static void +bttv_crop_reset(struct bttv_crop *c, unsigned int norm) +{ + c->rect = bttv_tvnorms[norm].cropcap.defrect; + bttv_crop_calc_limits(c); +} + +/* Call with btv->lock down. */ +static int +set_tvnorm(struct bttv *btv, unsigned int norm) +{ + const struct bttv_tvnorm *tvnorm; + v4l2_std_id id; + + BUG_ON(norm >= BTTV_TVNORMS); + BUG_ON(btv->tvnorm >= BTTV_TVNORMS); + + tvnorm = &bttv_tvnorms[norm]; + + if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap, + sizeof (tvnorm->cropcap))) { + bttv_crop_reset(&btv->crop[0], norm); + btv->crop[1] = btv->crop[0]; /* current = default */ + + if (0 == (btv->resources & VIDEO_RESOURCES)) { + btv->crop_start = tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height; + } + } + + btv->tvnorm = norm; + + btwrite(tvnorm->adelay, BT848_ADELAY); + btwrite(tvnorm->bdelay, BT848_BDELAY); + btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), + BT848_IFORM); + btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + bt848A_set_timing(btv); + + switch (btv->c.type) { + case BTTV_BOARD_VOODOOTV_FM: + case BTTV_BOARD_VOODOOTV_200: + bttv_tda9880_setnorm(btv, gpio_read()); + break; + } + id = tvnorm->v4l2_id; + bttv_call_all(btv, core, s_std, id); + + return 0; +} + +/* Call with btv->lock down. */ +static void +set_input(struct bttv *btv, unsigned int input, unsigned int norm) +{ + unsigned long flags; + + btv->input = input; + if (irq_iswitch) { + spin_lock_irqsave(&btv->s_lock,flags); + if (btv->curr.frame_irq) { + /* active capture -> delayed input switch */ + btv->new_input = input; + } else { + video_mux(btv,input); + } + spin_unlock_irqrestore(&btv->s_lock,flags); + } else { + video_mux(btv,input); + } + audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ? + TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN); + set_tvnorm(btv, norm); +} + +static void init_irqreg(struct bttv *btv) +{ + /* clear status */ + btwrite(0xfffffUL, BT848_INT_STAT); + + if (bttv_tvcards[btv->c.type].no_video) { + /* i2c only */ + btwrite(BT848_INT_I2CDONE, + BT848_INT_MASK); + } else { + /* full video */ + btwrite((btv->triton1) | + (btv->gpioirq ? BT848_INT_GPINT : 0) | + BT848_INT_SCERR | + (fdsr ? BT848_INT_FDSR : 0) | + BT848_INT_RISCI | BT848_INT_OCERR | + BT848_INT_FMTCHG|BT848_INT_HLOCK| + BT848_INT_I2CDONE, + BT848_INT_MASK); + } +} + +static void init_bt848(struct bttv *btv) +{ + int val; + + if (bttv_tvcards[btv->c.type].no_video) { + /* very basic init only */ + init_irqreg(btv); + return; + } + + btwrite(0x00, BT848_CAP_CTL); + btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); + btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); + + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); + + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + + btwrite(0x20, BT848_E_VSCALE_HI); + btwrite(0x20, BT848_O_VSCALE_HI); + btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + + btwrite(whitecrush_upper, BT848_WC_UP); + btwrite(whitecrush_lower, BT848_WC_DOWN); + + if (btv->opt_lumafilter) { + btwrite(0, BT848_E_CONTROL); + btwrite(0, BT848_O_CONTROL); + } else { + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + + bt848_bright(btv, btv->bright); + bt848_hue(btv, btv->hue); + bt848_contrast(btv, btv->contrast); + bt848_sat(btv, btv->saturation); + + /* interrupt */ + init_irqreg(btv); +} + +static void bttv_reinit_bt848(struct bttv *btv) +{ + unsigned long flags; + + if (bttv_verbose) + pr_info("%d: reset, reinitialize\n", btv->c.nr); + spin_lock_irqsave(&btv->s_lock,flags); + btv->errors=0; + bttv_set_dma(btv,0); + spin_unlock_irqrestore(&btv->s_lock,flags); + + init_bt848(btv); + btv->pll.pll_current = -1; + set_input(btv, btv->input, btv->tvnorm); +} + +static int bttv_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = btv->bright; + break; + case V4L2_CID_HUE: + c->value = btv->hue; + break; + case V4L2_CID_CONTRAST: + c->value = btv->contrast; + break; + case V4L2_CID_SATURATION: + c->value = btv->saturation; + break; + + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_all(btv, core, g_ctrl, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + c->value = btv->opt_chroma_agc; + break; + case V4L2_CID_PRIVATE_COMBFILTER: + c->value = btv->opt_combfilter; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + c->value = btv->opt_lumafilter; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + c->value = btv->opt_automute; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + c->value = btv->opt_adc_crush; + break; + case V4L2_CID_PRIVATE_VCR_HACK: + c->value = btv->opt_vcr_hack; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + c->value = btv->opt_whitecrush_upper; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + c->value = btv->opt_whitecrush_lower; + break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; + default: + return -EINVAL; + } + return 0; +} + +static int bttv_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) +{ + int err; + int val; + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (0 != err) + return err; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + bt848_bright(btv, c->value); + break; + case V4L2_CID_HUE: + bt848_hue(btv, c->value); + break; + case V4L2_CID_CONTRAST: + bt848_contrast(btv, c->value); + break; + case V4L2_CID_SATURATION: + bt848_sat(btv, c->value); + break; + case V4L2_CID_AUDIO_MUTE: + audio_mute(btv, c->value); + /* fall through */ + case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) + btv->volume_gpio(btv, c->value); + + bttv_call_all(btv, core, s_ctrl, c); + break; + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + bttv_call_all(btv, core, s_ctrl, c); + break; + + case V4L2_CID_PRIVATE_CHROMA_AGC: + btv->opt_chroma_agc = c->value; + val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); + break; + case V4L2_CID_PRIVATE_COMBFILTER: + btv->opt_combfilter = c->value; + break; + case V4L2_CID_PRIVATE_LUMAFILTER: + btv->opt_lumafilter = c->value; + if (btv->opt_lumafilter) { + btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); + btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); + } else { + btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); + } + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + btv->opt_automute = c->value; + break; + case V4L2_CID_PRIVATE_AGC_CRUSH: + btv->opt_adc_crush = c->value; + btwrite(BT848_ADC_RESERVED | + (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); + break; + case V4L2_CID_PRIVATE_VCR_HACK: + btv->opt_vcr_hack = c->value; + break; + case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: + btv->opt_whitecrush_upper = c->value; + btwrite(c->value, BT848_WC_UP); + break; + case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: + btv->opt_whitecrush_lower = c->value; + btwrite(c->value, BT848_WC_DOWN); + break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +void bttv_gpio_tracking(struct bttv *btv, char *comment) +{ + unsigned int outbits, data; + outbits = btread(BT848_GPIO_OUT_EN); + data = btread(BT848_GPIO_DATA); + pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", + btv->c.nr, outbits, data & outbits, data & ~outbits, comment); +} + +static void bttv_field_count(struct bttv *btv) +{ + int need_count = 0; + + if (btv->users) + need_count++; + + if (need_count) { + /* start field counter */ + btor(BT848_INT_VSYNC,BT848_INT_MASK); + } else { + /* stop field counter */ + btand(~BT848_INT_VSYNC,BT848_INT_MASK); + btv->field_count = 0; + } +} + +static const struct bttv_format* +format_by_fourcc(int fourcc) +{ + unsigned int i; + + for (i = 0; i < FORMATS; i++) { + if (-1 == formats[i].fourcc) + continue; + if (formats[i].fourcc == fourcc) + return formats+i; + } + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* misc helpers */ + +static int +bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, + struct bttv_buffer *new) +{ + struct bttv_buffer *old; + unsigned long flags; + int retval = 0; + + dprintk("switch_overlay: enter [new=%p]\n", new); + if (new) + new->vb.state = VIDEOBUF_DONE; + spin_lock_irqsave(&btv->s_lock,flags); + old = btv->screen; + btv->screen = new; + btv->loop_irq |= 1; + bttv_set_dma(btv, 0x03); + spin_unlock_irqrestore(&btv->s_lock,flags); + if (NULL != old) { + dprintk("switch_overlay: old=%p state is %d\n", + old, old->vb.state); + bttv_dma_free(&fh->cap,btv, old); + kfree(old); + } + if (NULL == new) + free_btres_lock(btv,fh,RESOURCE_OVERLAY); + dprintk("switch_overlay: done\n"); + return retval; +} + +/* ----------------------------------------------------------------------- */ +/* video4linux (1) interface */ + +static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, + struct bttv_buffer *buf, + const struct bttv_format *fmt, + unsigned int width, unsigned int height, + enum v4l2_field field) +{ + struct bttv_fh *fh = q->priv_data; + int redo_dma_risc = 0; + struct bttv_crop c; + int norm; + int rc; + + /* check settings */ + if (NULL == fmt) + return -EINVAL; + if (fmt->btformat == BT848_COLOR_FMT_RAW) { + width = RAW_BPL; + height = RAW_LINES*2; + if (width*height > buf->vb.bsize) + return -EINVAL; + buf->vb.size = buf->vb.bsize; + + /* Make sure tvnorm and vbi_end remain consistent + until we're done. */ + + norm = btv->tvnorm; + + /* In this mode capturing always starts at defrect.top + (default VDELAY), ignoring cropping parameters. */ + if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { + return -EINVAL; + } + + c.rect = bttv_tvnorms[norm].cropcap.defrect; + } else { + norm = btv->tvnorm; + c = btv->crop[!!fh->do_crop]; + + if (width < c.min_scaled_width || + width > c.max_scaled_width || + height < c.min_scaled_height) + return -EINVAL; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + /* btv->crop counts frame lines. Max. scale + factor is 16:1 for frames, 8:1 for fields. */ + if (height * 2 > c.max_scaled_height) + return -EINVAL; + break; + + default: + if (height > c.max_scaled_height) + return -EINVAL; + break; + } + + buf->vb.size = (width * height * fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + } + + /* alloc + fill struct bttv_buffer (if changed) */ + if (buf->vb.width != width || buf->vb.height != height || + buf->vb.field != field || + buf->tvnorm != norm || buf->fmt != fmt || + buf->crop.top != c.rect.top || + buf->crop.left != c.rect.left || + buf->crop.width != c.rect.width || + buf->crop.height != c.rect.height) { + buf->vb.width = width; + buf->vb.height = height; + buf->vb.field = field; + buf->tvnorm = norm; + buf->fmt = fmt; + buf->crop = c.rect; + redo_dma_risc = 1; + } + + /* alloc risc memory */ + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + redo_dma_risc = 1; + if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) + goto fail; + } + + if (redo_dma_risc) + if (0 != (rc = bttv_buffer_risc(btv,buf))) + goto fail; + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + bttv_dma_free(q,btv,buf); + return rc; +} + +static int +buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + struct bttv_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = gbuffers; + if (*size * *count > gbuffers * gbufsize) + *count = (gbuffers * gbufsize) / *size; + return 0; +} + +static int +buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + + return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, + fh->width, fh->height, field); +} + +static void +buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue,&btv->capture); + if (!btv->curr.frame_irq) { + btv->loop_irq |= 1; + bttv_set_dma(btv, 0x03); + } +} + +static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + struct bttv_fh *fh = q->priv_data; + + bttv_dma_free(q,fh->btv,buf); +} + +static struct videobuf_queue_ops bttv_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int i; + int err; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (err) + goto err; + + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) + break; + if (i == BTTV_TVNORMS) { + err = -EINVAL; + goto err; + } + + set_tvnorm(btv, i); + +err: + + return err; +} + +static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; +} + +static int bttv_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int rc = 0; + + if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { + rc = -EINVAL; + goto err; + } + + i->type = V4L2_INPUT_TYPE_CAMERA; + i->audioset = 1; + + if (btv->tuner_type != TUNER_ABSENT && i->index == 0) { + sprintf(i->name, "Television"); + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; + } else if (i->index == btv->svhs) { + sprintf(i->name, "S-Video"); + } else { + sprintf(i->name, "Composite%d", i->index); + } + + if (i->index == btv->input) { + __u32 dstatus = btread(BT848_DSTATUS); + if (0 == (dstatus & BT848_DSTATUS_PRES)) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 == (dstatus & BT848_DSTATUS_HLOC)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } + + i->std = BTTV_NORMS; + +err: + + return rc; +} + +static int bttv_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + *i = btv->input; + + return 0; +} + +static int bttv_s_input(struct file *file, void *priv, unsigned int i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + int err; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + if (i > bttv_tvcards[btv->c.type].video_inputs) { + err = -EINVAL; + goto err; + } + + set_input(btv, i, btv->tvnorm); + +err: + return 0; +} + +static int bttv_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + if (unlikely(0 != t->index)) + return -EINVAL; + + if (unlikely(btv->tuner_type == TUNER_ABSENT)) { + err = -EINVAL; + goto err; + } + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + bttv_call_all(btv, tuner, s_tuner, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 1); + +err: + + return 0; +} + +static int bttv_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; + + return 0; +} + +static int bttv_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + if (unlikely(f->tuner != 0)) + return -EINVAL; + + err = v4l2_prio_check(&btv->prio, fh->prio); + if (unlikely(err)) + goto err; + + if (unlikely(f->type != (btv->radio_user + ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) { + err = -EINVAL; + goto err; + } + btv->freq = f->frequency; + bttv_call_all(btv, tuner, s_frequency, f); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv, btv->freq); +err: + + return 0; +} + +static int bttv_log_status(struct file *file, void *f) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + bttv_call_all(btv, core, log_status); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int bttv_g_register(struct file *file, void *f, + struct v4l2_dbg_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + reg->val = btread(reg->reg); + reg->size = 1; + + return 0; +} + +static int bttv_s_register(struct file *file, void *f, + struct v4l2_dbg_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(®->match)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + btwrite(reg->val, reg->reg); + + return 0; +} +#endif + +/* Given cropping boundaries b and the scaled width and height of a + single field or frame, which must not exceed hardware limits, this + function adjusts the cropping parameters c. */ +static void +bttv_crop_adjust (struct bttv_crop * c, + const struct v4l2_rect * b, + __s32 width, + __s32 height, + enum v4l2_field field) +{ + __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); + __s32 max_left; + __s32 max_top; + + if (width < c->min_scaled_width) { + /* Max. hor. scale factor 16:1. */ + c->rect.width = width * 16; + } else if (width > c->max_scaled_width) { + /* Min. hor. scale factor 1:1. */ + c->rect.width = width; + + max_left = b->left + b->width - width; + max_left = min(max_left, (__s32) MAX_HDELAY); + if (c->rect.left > max_left) + c->rect.left = max_left; + } + + if (height < c->min_scaled_height) { + /* Max. vert. scale factor 16:1, single fields 8:1. */ + c->rect.height = height * 16; + } else if (frame_height > c->max_scaled_height) { + /* Min. vert. scale factor 1:1. + Top and height count field lines times two. */ + c->rect.height = (frame_height + 1) & ~1; + + max_top = b->top + b->height - c->rect.height; + if (c->rect.top > max_top) + c->rect.top = max_top; + } + + bttv_crop_calc_limits(c); +} + +/* Returns an error if scaling to a frame or single field with the given + width and height is not possible with the current cropping parameters + and width aligned according to width_mask. If adjust_size is TRUE the + function may adjust the width and/or height instead, rounding width + to (width + width_bias) & width_mask. If adjust_crop is TRUE it may + also adjust the current cropping parameters to get closer to the + desired image size. */ +static int +limit_scaled_size_lock (struct bttv_fh * fh, + __s32 * width, + __s32 * height, + enum v4l2_field field, + unsigned int width_mask, + unsigned int width_bias, + int adjust_size, + int adjust_crop) +{ + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + struct bttv_crop *c; + __s32 min_width; + __s32 min_height; + __s32 max_width; + __s32 max_height; + int rc; + + BUG_ON((int) width_mask >= 0 || + width_bias >= (unsigned int) -width_mask); + + /* Make sure tvnorm, vbi_end and the current cropping parameters + remain consistent until we're done. */ + + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + + /* Do crop - use current, don't - use default parameters. */ + c = &btv->crop[!!fh->do_crop]; + + if (fh->do_crop + && adjust_size + && adjust_crop + && !locked_btres(btv, VIDEO_RESOURCES)) { + min_width = 48; + min_height = 32; + + /* We cannot scale up. When the scaled image is larger + than crop.rect we adjust the crop.rect as required + by the V4L2 spec, hence cropcap.bounds are our limit. */ + max_width = min(b->width, (__s32) MAX_HACTIVE); + max_height = b->height; + + /* We cannot capture the same line as video and VBI data. + Note btv->vbi_end is really a minimum, see + bttv_vbi_try_fmt(). */ + if (btv->vbi_end > b->top) { + max_height -= btv->vbi_end - b->top; + rc = -EBUSY; + if (min_height > max_height) + goto fail; + } + } else { + rc = -EBUSY; + if (btv->vbi_end > c->rect.top) + goto fail; + + min_width = c->min_scaled_width; + min_height = c->min_scaled_height; + max_width = c->max_scaled_width; + max_height = c->max_scaled_height; + + adjust_crop = 0; + } + + min_width = (min_width - width_mask - 1) & width_mask; + max_width = max_width & width_mask; + + /* Max. scale factor is 16:1 for frames, 8:1 for fields. */ + min_height = min_height; + /* Min. scale factor is 1:1. */ + max_height >>= !V4L2_FIELD_HAS_BOTH(field); + + if (adjust_size) { + *width = clamp(*width, min_width, max_width); + *height = clamp(*height, min_height, max_height); + + /* Round after clamping to avoid overflow. */ + *width = (*width + width_bias) & width_mask; + + if (adjust_crop) { + bttv_crop_adjust(c, b, *width, *height, field); + + if (btv->vbi_end > c->rect.top) { + /* Move the crop window out of the way. */ + c->rect.top = btv->vbi_end; + } + } + } else { + rc = -EINVAL; + if (*width < min_width || + *height < min_height || + *width > max_width || + *height > max_height || + 0 != (*width & ~width_mask)) + goto fail; + } + + rc = 0; /* success */ + + fail: + + return rc; +} + +/* Returns an error if the given overlay window dimensions are not + possible with the current cropping parameters. If adjust_size is + TRUE the function may adjust the window width and/or height + instead, however it always rounds the horizontal position and + width as btcx_align() does. If adjust_crop is TRUE the function + may also adjust the current cropping parameters to get closer + to the desired window size. */ +static int +verify_window_lock (struct bttv_fh * fh, + struct v4l2_window * win, + int adjust_size, + int adjust_crop) +{ + enum v4l2_field field; + unsigned int width_mask; + int rc; + + if (win->w.width < 48 || win->w.height < 32) + return -EINVAL; + if (win->clipcount > 2048) + return -EINVAL; + + field = win->field; + + if (V4L2_FIELD_ANY == field) { + __s32 height2; + + height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; + field = (win->w.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + /* 4-byte alignment. */ + if (NULL == fh->ovfmt) + return -EINVAL; + width_mask = ~0; + switch (fh->ovfmt->depth) { + case 8: + case 24: + width_mask = ~3; + break; + case 16: + width_mask = ~1; + break; + case 32: + break; + default: + BUG(); + } + + win->w.width -= win->w.left & ~width_mask; + win->w.left = (win->w.left - width_mask - 1) & width_mask; + + rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height, + field, width_mask, + /* width_bias: round down */ 0, + adjust_size, adjust_crop); + if (0 != rc) + return rc; + + win->field = field; + return 0; +} + +static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_window *win, int fixup) +{ + struct v4l2_clip *clips = NULL; + int n,size,retval = 0; + + if (NULL == fh->ovfmt) + return -EINVAL; + if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + retval = verify_window_lock(fh, win, + /* adjust_size */ fixup, + /* adjust_crop */ fixup); + if (0 != retval) + return retval; + + /* copy clips -- luckily v4l1 + v4l2 are binary + compatible here ...*/ + n = win->clipcount; + 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)*n)) { + kfree(clips); + return -EFAULT; + } + } + + /* clip against screen */ + if (NULL != btv->fbuf.base) + n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, + &win->w, 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(); + } + + kfree(fh->ov.clips); + fh->ov.clips = clips; + fh->ov.nclips = n; + + 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; + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + retval = bttv_switch_overlay(btv,fh,new); + } + return retval; +} + +/* ----------------------------------------------------------------------- */ + +static struct videobuf_queue* bttv_queue(struct bttv_fh *fh) +{ + struct videobuf_queue* q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int bttv_resource(struct bttv_fh *fh) +{ + int res = 0; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + res = RESOURCE_VIDEO_STREAM; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + res = RESOURCE_VBI; + break; + default: + BUG(); + } + return res; +} + +static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) +{ + struct videobuf_queue *q = bttv_queue(fh); + int res = bttv_resource(fh); + + if (check_btres(fh,res)) + return -EBUSY; + if (videobuf_queue_is_busy(q)) + return -EBUSY; + fh->type = type; + return 0; +} + +static void +pix_format_set_size (struct v4l2_pix_format * f, + const struct bttv_format * fmt, + unsigned int width, + unsigned int height) +{ + f->width = width; + f->height = height; + + if (fmt->flags & FORMAT_FLAGS_PLANAR) { + f->bytesperline = width; /* Y plane */ + f->sizeimage = (width * height * fmt->depth) >> 3; + } else { + f->bytesperline = (width * fmt->depth) >> 3; + f->sizeimage = height * f->bytesperline; + } +} + +static int bttv_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + pix_format_set_size(&f->fmt.pix, fh->fmt, + fh->width, fh->height); + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + + return 0; +} + +static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + f->fmt.win.w = fh->ov.w; + f->fmt.win.field = fh->ov.field; + + return 0; +} + +static int bttv_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + enum v4l2_field field; + __s32 width, height; + int rc; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + + if (V4L2_FIELD_ANY == field) { + __s32 height2; + + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + break; + default: + return -EINVAL; + } + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + + rc = limit_scaled_size_lock(fh, &width, &height, field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 0); + if (0 != rc) + return rc; + + /* update data for the application */ + f->fmt.pix.field = field; + pix_format_set_size(&f->fmt.pix, fmt, width, height); + + return 0; +} + +static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + return verify_window_lock(fh, &f->fmt.win, + /* adjust_size */ 1, + /* adjust_crop */ 0); +} + +static int bttv_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int retval; + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + __s32 width, height; + enum v4l2_field field; + + retval = bttv_switch_type(fh, f->type); + if (0 != retval) + return retval; + + retval = bttv_try_fmt_vid_cap(file, priv, f); + if (0 != retval) + return retval; + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + field = f->fmt.pix.field; + + retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 1); + if (0 != retval) + return retval; + + f->fmt.pix.field = field; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + + /* update our state informations */ + 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; + btv->init.width = f->fmt.pix.width; + btv->init.height = f->fmt.pix.height; + + return 0; +} + +static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (no_overlay > 0) { + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + + return setup_window_lock(fh, btv, &f->fmt.win, 1); +} + +static int bttv_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 == v4l2) + return -EINVAL; + + strlcpy(cap->driver, "bttv", sizeof(cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + /* + * No need to lock here: those vars are initialized during board + * probe and remains untouched during the rest of the driver lifecycle + */ + if (btv->has_saa6588) + cap->capabilities |= V4L2_CAP_RDS_CAPTURE; + if (btv->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) +{ + int index = -1, i; + + for (i = 0; i < FORMATS; i++) { + if (formats[i].fourcc != -1) + index++; + if ((unsigned int)index == f->index) + break; + } + if (FORMATS == i) + return -EINVAL; + + f->pixelformat = formats[i].fourcc; + strlcpy(f->description, formats[i].name, sizeof(f->description)); + + return i; +} + +static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc = bttv_enum_fmt_cap_ovr(f); + + if (rc < 0) + return rc; + + return 0; +} + +static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc; + + if (no_overlay > 0) { + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + + rc = bttv_enum_fmt_cap_ovr(f); + + if (rc < 0) + return rc; + + if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + + return 0; +} + +static int bttv_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + *fb = btv->fbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) + fb->fmt.pixelformat = fh->ovfmt->fourcc; + return 0; +} + +static int bttv_overlay(struct file *file, void *f, unsigned int on) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct bttv_buffer *new; + int retval = 0; + + if (on) { + /* verify args */ + if (unlikely(!btv->fbuf.base)) { + return -EINVAL; + } + if (unlikely(!fh->ov.setup_ok)) { + dprintk("%d: overlay: !setup_ok\n", btv->c.nr); + retval = -EINVAL; + } + if (retval) + return retval; + } + + if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) + return -EBUSY; + + if (on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; + } + + /* switch over */ + retval = bttv_switch_overlay(btv, fh, new); + return retval; +} + +static int bttv_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_format *fmt; + int retval; + + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + + retval = -EINVAL; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + __s32 width = fb->fmt.width; + __s32 height = fb->fmt.height; + + retval = limit_scaled_size_lock(fh, &width, &height, + V4L2_FIELD_INTERLACED, + /* width_mask */ ~3, + /* width_bias */ 2, + /* adjust_size */ 0, + /* adjust_crop */ 0); + if (0 != retval) + return retval; + } + + /* ok, accept it */ + btv->fbuf.base = fb->base; + btv->fbuf.fmt.width = fb->fmt.width; + btv->fbuf.fmt.height = fb->fmt.height; + if (0 != fb->fmt.bytesperline) + btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; + + retval = 0; + fh->ovfmt = fmt; + btv->init.ovfmt = fmt; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; + kfree(fh->ov.clips); + fh->ov.clips = NULL; + fh->ov.nclips = 0; + + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_sg_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + retval = bttv_switch_overlay(btv, fh, new); + } + } + return retval; +} + +static int bttv_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct bttv_fh *fh = priv; + return videobuf_reqbufs(bttv_queue(fh), p); +} + +static int bttv_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_querybuf(bttv_queue(fh), b); +} + +static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); + + if (!check_alloc_btres_lock(btv, fh, res)) + return -EBUSY; + + return videobuf_qbuf(bttv_queue(fh), b); +} + +static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_dqbuf(bttv_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int bttv_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); + + if (!check_alloc_btres_lock(btv, fh, res)) + return -EBUSY; + return videobuf_streamon(bttv_queue(fh)); +} + + +static int bttv_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int retval; + int res = bttv_resource(fh); + + + retval = videobuf_streamoff(bttv_queue(fh)); + if (retval < 0) + return retval; + free_btres_lock(btv, fh, res); + return 0; +} + +static int bttv_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + const struct v4l2_queryctrl *ctrl; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + + if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + else { + ctrl = ctrl_by_id(c->id); + + *c = (NULL != ctrl) ? *ctrl : no_ctl; + } + + return 0; +} + +static int bttv_g_parm(struct file *file, void *f, + struct v4l2_streamparm *parm) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, + &parm->parm.capture.timeperframe); + + return 0; +} + +static int bttv_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->tuner_type == TUNER_ABSENT) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_all(btv, tuner, g_tuner, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + return 0; +} + +static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + *p = v4l2_prio_max(&btv->prio); + + return 0; +} + +static int bttv_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + int rc; + + rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); + + return rc; +} + +static int bttv_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + *cap = bttv_tvnorms[btv->tvnorm].cropcap; + + return 0; +} + +static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + /* No fh->do_crop = 1; because btv->crop[1] may be + inconsistent with fh->width or fh->height and apps + do not expect a change here. */ + + crop->c = btv->crop[!!fh->do_crop].rect; + + return 0; +} + +static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + int retval; + struct bttv_crop c; + __s32 b_left; + __s32 b_top; + __s32 b_right; + __s32 b_bottom; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + + /* Make sure tvnorm, vbi_end and the current cropping + parameters remain consistent until we're done. Note + read() may change vbi_end in check_alloc_btres_lock(). */ + retval = v4l2_prio_check(&btv->prio, fh->prio); + if (0 != retval) { + return retval; + } + + retval = -EBUSY; + + if (locked_btres(fh->btv, VIDEO_RESOURCES)) { + return retval; + } + + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + + b_left = b->left; + b_right = b_left + b->width; + b_bottom = b->top + b->height; + + b_top = max(b->top, btv->vbi_end); + if (b_top + 32 >= b_bottom) { + return retval; + } + + /* Min. scaled size 48 x 32. */ + c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); + + c.rect.width = clamp(crop->c.width, + 48, b_right - c.rect.left); + + c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + /* Top and height must be a multiple of two. */ + c.rect.top = (c.rect.top + 1) & ~1; + + c.rect.height = clamp(crop->c.height, + 32, b_bottom - c.rect.top); + c.rect.height = (c.rect.height + 1) & ~1; + + bttv_crop_calc_limits(&c); + + btv->crop[1] = c; + + fh->do_crop = 1; + + if (fh->width < c.min_scaled_width) { + fh->width = c.min_scaled_width; + btv->init.width = c.min_scaled_width; + } else if (fh->width > c.max_scaled_width) { + fh->width = c.max_scaled_width; + btv->init.width = c.max_scaled_width; + } + + if (fh->height < c.min_scaled_height) { + fh->height = c.min_scaled_height; + btv->init.height = c.min_scaled_height; + } else if (fh->height > c.max_scaled_height) { + fh->height = c.max_scaled_height; + btv->init.height = c.max_scaled_height; + } + + return 0; +} + +static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "audio"); + return 0; +} + +static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + return 0; +} + +static ssize_t bttv_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv_fh *fh = file->private_data; + int retval = 0; + + if (fh->btv->errors) + bttv_reinit_bt848(fh->btv); + dprintk("%d: read count=%d type=%s\n", + fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]); + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) { + /* VIDEO_READ in use by another fh, + or VIDEO_STREAM by any fh. */ + return -EBUSY; + } + retval = videobuf_read_one(&fh->cap, data, count, ppos, + file->f_flags & O_NONBLOCK); + free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) + return -EBUSY; + retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + break; + default: + BUG(); + } + return retval; +} + +static unsigned int bttv_poll(struct file *file, poll_table *wait) +{ + struct bttv_fh *fh = file->private_data; + struct bttv_buffer *buf; + enum v4l2_field field; + unsigned int rc = POLLERR; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbi, wait); + } + + if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { + /* streaming capture */ + if (list_empty(&fh->cap.stream)) + goto err; + buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); + } else { + /* read() capture */ + if (NULL == fh->cap.read_buf) { + /* need to capture a new frame */ + if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) + goto err; + fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize); + if (NULL == fh->cap.read_buf) + goto err; + fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; + field = videobuf_next_field(&fh->cap); + if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { + kfree (fh->cap.read_buf); + fh->cap.read_buf = NULL; + goto err; + } + fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); + fh->cap.read_off = 0; + } + buf = (struct bttv_buffer*)fh->cap.read_buf; + } + + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + rc = POLLIN|POLLRDNORM; + else + rc = 0; +err: + return rc; +} + +static int bttv_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct bttv *btv = video_drvdata(file); + struct bttv_fh *fh; + enum v4l2_buf_type type = 0; + + dprintk("open dev=%s\n", video_device_node_name(vdev)); + + if (vdev->vfl_type == VFL_TYPE_GRABBER) { + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } else if (vdev->vfl_type == VFL_TYPE_VBI) { + type = V4L2_BUF_TYPE_VBI_CAPTURE; + } else { + WARN_ON(1); + return -ENODEV; + } + + dprintk("%d: open called (type=%s)\n", + btv->c.nr, v4l2_type_names[type]); + + /* allocate per filehandle data */ + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (unlikely(!fh)) + return -ENOMEM; + file->private_data = fh; + + *fh = btv->init; + + fh->type = type; + fh->ov.setup_ok = 0; + + v4l2_prio_open(&btv->prio, &fh->prio); + + videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, + &btv->c.pci->dev, &btv->s_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct bttv_buffer), + fh, &btv->lock); + videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, + &btv->c.pci->dev, &btv->s_lock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct bttv_buffer), + fh, &btv->lock); + set_tvnorm(btv,btv->tvnorm); + set_input(btv, btv->input, btv->tvnorm); + + btv->users++; + + /* The V4L2 spec requires one global set of cropping parameters + which only change on request. These are stored in btv->crop[1]. + However for compatibility with V4L apps and cropping unaware + V4L2 apps we now reset the cropping parameters as seen through + this fh, which is to say VIDIOC_G_CROP and scaling limit checks + will use btv->crop[0], the default cropping parameters for the + current video standard, and VIDIOC_S_FMT will not implicitely + change the cropping parameters until VIDIOC_S_CROP has been + called. */ + fh->do_crop = !reset_crop; /* module parameter */ + + /* Likewise there should be one global set of VBI capture + parameters, but for compatibility with V4L apps and earlier + driver versions each fh has its own parameters. */ + bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); + + bttv_field_count(btv); + return 0; +} + +static int bttv_release(struct file *file) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + + /* turn off overlay */ + if (check_btres(fh, RESOURCE_OVERLAY)) + bttv_switch_overlay(btv,fh,NULL); + + /* stop video capture */ + if (check_btres(fh, RESOURCE_VIDEO_STREAM)) { + videobuf_streamoff(&fh->cap); + free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM); + } + if (fh->cap.read_buf) { + buffer_release(&fh->cap,fh->cap.read_buf); + kfree(fh->cap.read_buf); + } + if (check_btres(fh, RESOURCE_VIDEO_READ)) { + free_btres_lock(btv, fh, RESOURCE_VIDEO_READ); + } + + /* stop vbi capture */ + if (check_btres(fh, RESOURCE_VBI)) { + videobuf_stop(&fh->vbi); + free_btres_lock(btv,fh,RESOURCE_VBI); + } + + /* free stuff */ + + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); + v4l2_prio_close(&btv->prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + btv->users--; + bttv_field_count(btv); + + if (!btv->users) + audio_mute(btv, 1); + + return 0; +} + +static int +bttv_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct bttv_fh *fh = file->private_data; + + dprintk("%d: mmap type=%s 0x%lx+%ld\n", + fh->btv->c.nr, v4l2_type_names[fh->type], + vma->vm_start, vma->vm_end - vma->vm_start); + return videobuf_mmap_mapper(bttv_queue(fh),vma); +} + +static const struct v4l2_file_operations bttv_fops = +{ + .owner = THIS_MODULE, + .open = bttv_open, + .release = bttv_release, + .unlocked_ioctl = video_ioctl2, + .read = bttv_read, + .mmap = bttv_mmap, + .poll = bttv_poll, +}; + +static const struct v4l2_ioctl_ops bttv_ioctl_ops = { + .vidioc_querycap = bttv_querycap, + .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay, + .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, + .vidioc_g_audio = bttv_g_audio, + .vidioc_s_audio = bttv_s_audio, + .vidioc_cropcap = bttv_cropcap, + .vidioc_reqbufs = bttv_reqbufs, + .vidioc_querybuf = bttv_querybuf, + .vidioc_qbuf = bttv_qbuf, + .vidioc_dqbuf = bttv_dqbuf, + .vidioc_s_std = bttv_s_std, + .vidioc_enum_input = bttv_enum_input, + .vidioc_g_input = bttv_g_input, + .vidioc_s_input = bttv_s_input, + .vidioc_queryctrl = bttv_queryctrl, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_streamon = bttv_streamon, + .vidioc_streamoff = bttv_streamoff, + .vidioc_g_tuner = bttv_g_tuner, + .vidioc_s_tuner = bttv_s_tuner, + .vidioc_g_crop = bttv_g_crop, + .vidioc_s_crop = bttv_s_crop, + .vidioc_g_fbuf = bttv_g_fbuf, + .vidioc_s_fbuf = bttv_s_fbuf, + .vidioc_overlay = bttv_overlay, + .vidioc_g_priority = bttv_g_priority, + .vidioc_s_priority = bttv_s_priority, + .vidioc_g_parm = bttv_g_parm, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, + .vidioc_log_status = bttv_log_status, + .vidioc_querystd = bttv_querystd, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = bttv_g_register, + .vidioc_s_register = bttv_s_register, +#endif +}; + +static struct video_device bttv_video_template = { + .fops = &bttv_fops, + .ioctl_ops = &bttv_ioctl_ops, + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +/* ----------------------------------------------------------------------- */ +/* radio interface */ + +static int radio_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct bttv *btv = video_drvdata(file); + struct bttv_fh *fh; + + dprintk("open dev=%s\n", video_device_node_name(vdev)); + + dprintk("%d: open called (radio)\n", btv->c.nr); + + /* allocate per filehandle data */ + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (unlikely(!fh)) + return -ENOMEM; + file->private_data = fh; + *fh = btv->init; + + v4l2_prio_open(&btv->prio, &fh->prio); + + btv->radio_user++; + + bttv_call_all(btv, tuner, s_radio); + audio_input(btv,TVAUDIO_INPUT_RADIO); + + return 0; +} + +static int radio_release(struct file *file) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + + v4l2_prio_close(&btv->prio, fh->prio); + file->private_data = NULL; + kfree(fh); + + btv->radio_user--; + + bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd); + + return 0; +} + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); + cap->capabilities = V4L2_CAP_TUNER; + + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (btv->tuner_type == TUNER_ABSENT) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + bttv_call_all(btv, tuner, g_tuner, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 != t->index) + return -EINVAL; + + bttv_call_all(btv, tuner, s_tuner, t); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (unlikely(i)) + return -EINVAL; + + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctl; + + return 0; +} + +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static ssize_t radio_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + cmd.block_count = count/3; + cmd.buffer = data; + cmd.instance = file; + cmd.result = -ENODEV; + + bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd); + + return cmd.result; +} + +static unsigned int radio_poll(struct file *file, poll_table *wait) +{ + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + struct saa6588_command cmd; + cmd.instance = file; + cmd.event_list = wait; + cmd.result = -ENODEV; + bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd); + + return cmd.result; +} + +static const struct v4l2_file_operations radio_fops = +{ + .owner = THIS_MODULE, + .open = radio_open, + .read = radio_read, + .release = radio_release, + .unlocked_ioctl = video_ioctl2, + .poll = radio_poll, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, +}; + +static struct video_device radio_template = { + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + +/* ----------------------------------------------------------------------- */ +/* some debug code */ + +static int bttv_risc_decode(u32 risc) +{ + static char *instr[16] = { + [ BT848_RISC_WRITE >> 28 ] = "write", + [ BT848_RISC_SKIP >> 28 ] = "skip", + [ BT848_RISC_WRITEC >> 28 ] = "writec", + [ BT848_RISC_JUMP >> 28 ] = "jump", + [ BT848_RISC_SYNC >> 28 ] = "sync", + [ BT848_RISC_WRITE123 >> 28 ] = "write123", + [ BT848_RISC_SKIP123 >> 28 ] = "skip123", + [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23", + }; + static int incr[16] = { + [ BT848_RISC_WRITE >> 28 ] = 2, + [ BT848_RISC_JUMP >> 28 ] = 2, + [ BT848_RISC_SYNC >> 28 ] = 2, + [ BT848_RISC_WRITE123 >> 28 ] = 5, + [ BT848_RISC_SKIP123 >> 28 ] = 2, + [ BT848_RISC_WRITE1S23 >> 28 ] = 3, + }; + static char *bits[] = { + "be0", "be1", "be2", "be3/resync", + "set0", "set1", "set2", "set3", + "clr0", "clr1", "clr2", "clr3", + "irq", "res", "eol", "sol", + }; + int i; + + pr_cont("0x%08x [ %s", risc, + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + if (risc & (1 << (i + 12))) + pr_cont(" %s", bits[i]); + pr_cont(" count=%d ]\n", risc & 0xfff); + return incr[risc >> 28] ? incr[risc >> 28] : 1; +} + +static void bttv_risc_disasm(struct bttv *btv, + struct btcx_riscmem *risc) +{ + unsigned int i,j,n; + + pr_info("%s: risc disasm: %p [dma=0x%08lx]\n", + btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); + for (i = 0; i < (risc->size >> 2); i += n) { + pr_info("%s: 0x%lx: ", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + (i<<2))); + n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); + for (j = 1; j < n; j++) + pr_info("%s: 0x%lx: 0x%08x [ arg #%d ]\n", + btv->c.v4l2_dev.name, + (unsigned long)(risc->dma + ((i+j)<<2)), + risc->cpu[i+j], j); + if (0 == risc->cpu[i]) + break; + } +} + +static void bttv_print_riscaddr(struct bttv *btv) +{ + pr_info(" main: %08llx\n", (unsigned long long)btv->main.dma); + pr_info(" vbi : o=%08llx e=%08llx\n", + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); + pr_info(" cap : o=%08llx e=%08llx\n", + btv->curr.top + ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->curr.bottom + ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + pr_info(" scr : o=%08llx e=%08llx\n", + btv->screen ? (unsigned long long)btv->screen->top.dma : 0, + btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); + bttv_risc_disasm(btv, &btv->main); +} + +/* ----------------------------------------------------------------------- */ +/* irq handler */ + +static char *irq_name[] = { + "FMTCHG", // format change detected (525 vs. 625) + "VSYNC", // vertical sync (new field) + "HSYNC", // horizontal sync + "OFLOW", // chroma/luma AGC overflow + "HLOCK", // horizontal lock changed + "VPRES", // video presence changed + "6", "7", + "I2CDONE", // hw irc operation finished + "GPINT", // gpio port triggered irq + "10", + "RISCI", // risc instruction triggered irq + "FBUS", // pixel data fifo dropped data (high pci bus latencies) + "FTRGT", // pixel data fifo overrun + "FDSR", // fifo data stream resyncronisation + "PPERR", // parity error (data transfer) + "RIPERR", // parity error (read risc instructions) + "PABORT", // pci abort + "OCERR", // risc instruction error + "SCERR", // syncronisation error +}; + +static void bttv_print_irqbits(u32 print, u32 mark) +{ + unsigned int i; + + pr_cont("bits:"); + for (i = 0; i < ARRAY_SIZE(irq_name); i++) { + if (print & (1 << i)) + pr_cont(" %s", irq_name[i]); + if (mark & (1 << i)) + pr_cont("*"); + } +} + +static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) +{ + pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", + btv->c.nr, + (unsigned long)btv->main.dma, + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), + (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), + (unsigned long)rc); + + if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { + pr_notice("%d: Oh, there (temporarily?) is no input signal. " + "Ok, then this is harmless, don't worry ;)\n", + btv->c.nr); + return; + } + pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n", + btv->c.nr); + pr_notice("%d: Lets try to catch the culpit red-handed ...\n", + btv->c.nr); + dump_stack(); +} + +static int +bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) +{ + struct bttv_buffer *item; + + memset(set,0,sizeof(*set)); + + /* capture request ? */ + if (!list_empty(&btv->capture)) { + set->frame_irq = 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); + /* Mike Isely - Only check + * and set up the bottom field in the logic + * below. Don't ever do the top field. This + * of course means that if we set up the + * bottom field in the above code that we'll + * actually skip a field. But that's OK. + * Having processed only a single buffer this + * time, then the next time around the first + * available buffer should be for a top field. + * That will then cause us here to set up a + * top then a bottom field in the normal way. + * The alternative to this understanding is + * that we set up the second available buffer + * as a top field, but that's out of order + * since this driver always processes the top + * field first - the effect will be the two + * buffers being returned in the wrong order, + * with the second buffer also being delayed + * by one field time (owing to the fifo nature + * of videobuf). Worse still, we'll be stuck + * doing fields out of order now every time + * until something else causes a field to be + * dropped. By effectively forcing a field to + * drop this way then we always get back into + * sync within a single frame time. (Out of + * order fields can screw up deinterlacing + * algorithms.) */ + if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { + if (NULL == set->bottom && + V4L2_FIELD_BOTTOM == item->vb.field) { + set->bottom = item; + } + if (NULL != set->top && NULL != set->bottom) + set->top_irq = 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("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", + btv->c.nr, set->top, set->bottom, + btv->screen, set->frame_irq, set->top_irq); + return 0; +} + +static void +bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, + struct bttv_buffer_set *curr, unsigned int state) +{ + struct timeval ts; + + do_gettimeofday(&ts); + + if (wakeup->top == wakeup->bottom) { + if (NULL != wakeup->top && curr->top != wakeup->top) { + if (irq_debug > 1) + pr_debug("%d: wakeup: both=%p\n", + btv->c.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 > 1) + pr_debug("%d: wakeup: top=%p\n", + btv->c.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 > 1) + pr_debug("%d: wakeup: bottom=%p\n", + btv->c.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_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, + unsigned int state) +{ + struct timeval ts; + + if (NULL == wakeup) + return; + + do_gettimeofday(&ts); + wakeup->vb.ts = ts; + wakeup->vb.field_count = btv->field_count; + wakeup->vb.state = state; + wake_up(&wakeup->vb.done); +} + +static void bttv_irq_timeout(unsigned long data) +{ + struct bttv *btv = (struct bttv *)data; + struct bttv_buffer_set old,new; + struct bttv_buffer *ovbi; + struct bttv_buffer *item; + unsigned long flags; + + if (bttv_verbose) { + pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", + btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, + btread(BT848_RISC_COUNT)); + bttv_print_irqbits(btread(BT848_INT_STAT),0); + pr_cont("\n"); + } + + spin_lock_irqsave(&btv->s_lock,flags); + + /* deactivate stuff */ + memset(&new,0,sizeof(new)); + old = btv->curr; + ovbi = btv->cvbi; + btv->curr = new; + btv->cvbi = NULL; + btv->loop_irq = 0; + bttv_buffer_activate_video(btv, &new); + bttv_buffer_activate_vbi(btv, NULL); + bttv_set_dma(btv, 0); + + /* wake up */ + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); + + /* cancel all outstanding capture / vbi requests */ + while (!list_empty(&btv->capture)) { + item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = VIDEOBUF_ERROR; + wake_up(&item->vb.done); + } + while (!list_empty(&btv->vcapture)) { + item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + list_del(&item->vb.queue); + item->vb.state = VIDEOBUF_ERROR; + wake_up(&item->vb.done); + } + + btv->errors++; + spin_unlock_irqrestore(&btv->s_lock,flags); +} + +static void +bttv_irq_wakeup_top(struct bttv *btv) +{ + struct bttv_buffer *wakeup = btv->curr.top; + + if (NULL == wakeup) + return; + + spin_lock(&btv->s_lock); + btv->curr.top_irq = 0; + btv->curr.top = NULL; + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + + do_gettimeofday(&wakeup->vb.ts); + wakeup->vb.field_count = btv->field_count; + wakeup->vb.state = VIDEOBUF_DONE; + wake_up(&wakeup->vb.done); + spin_unlock(&btv->s_lock); +} + +static inline int is_active(struct btcx_riscmem *risc, u32 rc) +{ + if (rc < risc->dma) + return 0; + if (rc > risc->dma + risc->size) + return 0; + return 1; +} + +static void +bttv_irq_switch_video(struct bttv *btv) +{ + struct bttv_buffer_set new; + struct bttv_buffer_set old; + dma_addr_t rc; + + spin_lock(&btv->s_lock); + + /* new buffer set */ + bttv_irq_next_video(btv, &new); + rc = btread(BT848_RISC_COUNT); + if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) || + (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) { + btv->framedrop++; + if (debug_latency) + bttv_irq_debug_low_latency(btv, rc); + spin_unlock(&btv->s_lock); + return; + } + + /* switch over */ + old = btv->curr; + btv->curr = new; + btv->loop_irq &= ~1; + bttv_buffer_activate_video(btv, &new); + bttv_set_dma(btv, 0); + + /* switch input */ + if (UNSET != btv->new_input) { + video_mux(btv,btv->new_input); + btv->new_input = UNSET; + } + + /* wake up finished buffers */ + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); + spin_unlock(&btv->s_lock); +} + +static void +bttv_irq_switch_vbi(struct bttv *btv) +{ + struct bttv_buffer *new = NULL; + struct bttv_buffer *old; + u32 rc; + + spin_lock(&btv->s_lock); + + if (!list_empty(&btv->vcapture)) + new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); + old = btv->cvbi; + + rc = btread(BT848_RISC_COUNT); + if (NULL != old && (is_active(&old->top, rc) || + is_active(&old->bottom, rc))) { + btv->framedrop++; + if (debug_latency) + bttv_irq_debug_low_latency(btv, rc); + spin_unlock(&btv->s_lock); + return; + } + + /* switch */ + btv->cvbi = new; + btv->loop_irq &= ~4; + bttv_buffer_activate_vbi(btv, new); + bttv_set_dma(btv, 0); + + bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); + spin_unlock(&btv->s_lock); +} + +static irqreturn_t bttv_irq(int irq, void *dev_id) +{ + u32 stat,astat; + u32 dstat; + int count; + struct bttv *btv; + int handled = 0; + + 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) + break; + handled = 1; + btwrite(stat,BT848_INT_STAT); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (irq_debug) { + pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ", + btv->c.nr, count, btv->field_count, + stat>>28, btread(BT848_RISC_COUNT)); + bttv_print_irqbits(stat,astat); + if (stat & BT848_INT_HLOCK) + pr_cont(" HLOC => %s", + dstat & BT848_DSTATUS_HLOC + ? "yes" : "no"); + if (stat & BT848_INT_VPRES) + pr_cont(" PRES => %s", + dstat & BT848_DSTATUS_PRES + ? "yes" : "no"); + if (stat & BT848_INT_FMTCHG) + pr_cont(" NUML => %s", + dstat & BT848_DSTATUS_NUML + ? "625" : "525"); + pr_cont("\n"); + } + + if (astat&BT848_INT_VSYNC) + btv->field_count++; + + if ((astat & BT848_INT_GPINT) && btv->remote) { + bttv_input_irq(btv); + } + + if (astat & BT848_INT_I2CDONE) { + btv->i2c_done = stat; + wake_up(&btv->i2c_queue); + } + + if ((astat & BT848_INT_RISCI) && (stat & (4<<28))) + bttv_irq_switch_vbi(btv); + + if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) + bttv_irq_wakeup_top(btv); + + if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) + bttv_irq_switch_video(btv); + + if ((astat & BT848_INT_HLOCK) && btv->opt_automute) + audio_mute(btv, btv->mute); /* trigger automute */ + + if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { + pr_info("%d: %s%s @ %08x,", + btv->c.nr, + (astat & BT848_INT_SCERR) ? "SCERR" : "", + (astat & BT848_INT_OCERR) ? "OCERR" : "", + btread(BT848_RISC_COUNT)); + bttv_print_irqbits(stat,astat); + pr_cont("\n"); + if (bttv_debug) + bttv_print_riscaddr(btv); + } + if (fdsr && astat & BT848_INT_FDSR) { + pr_info("%d: FDSR @ %08x\n", + btv->c.nr, btread(BT848_RISC_COUNT)); + if (bttv_debug) + bttv_print_riscaddr(btv); + } + + count++; + if (count > 4) { + + if (count > 8 || !(astat & BT848_INT_GPINT)) { + btwrite(0, BT848_INT_MASK); + + pr_err("%d: IRQ lockup, cleared int mask [", + btv->c.nr); + } else { + pr_err("%d: IRQ lockup, clearing GPINT from int mask [", + btv->c.nr); + + btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), + BT848_INT_MASK); + }; + + bttv_print_irqbits(stat,astat); + + pr_cont("]\n"); + } + } + btv->irq_total++; + if (handled) + btv->irq_me++; + return IRQ_RETVAL(handled); +} + + +/* ----------------------------------------------------------------------- */ +/* initialitation */ + +static struct video_device *vdev_init(struct bttv *btv, + const struct video_device *template, + const char *type_name) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->v4l2_dev = &btv->c.v4l2_dev; + vfd->release = video_device_release; + vfd->debug = bttv_debug; + video_set_drvdata(vfd, btv); + snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", + btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", + type_name, bttv_tvcards[btv->c.type].name); + return vfd; +} + +static void bttv_unregister_video(struct bttv *btv) +{ + if (btv->video_dev) { + if (video_is_registered(btv->video_dev)) + video_unregister_device(btv->video_dev); + else + video_device_release(btv->video_dev); + btv->video_dev = NULL; + } + if (btv->vbi_dev) { + if (video_is_registered(btv->vbi_dev)) + video_unregister_device(btv->vbi_dev); + else + video_device_release(btv->vbi_dev); + btv->vbi_dev = NULL; + } + if (btv->radio_dev) { + if (video_is_registered(btv->radio_dev)) + video_unregister_device(btv->radio_dev); + else + video_device_release(btv->radio_dev); + btv->radio_dev = NULL; + } +} + +/* register video4linux devices */ +static int __devinit bttv_register_video(struct bttv *btv) +{ + if (no_overlay > 0) + pr_notice("Overlay support disabled\n"); + + /* video */ + btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); + + if (NULL == btv->video_dev) + goto err; + if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, + video_nr[btv->c.nr]) < 0) + goto err; + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->video_dev)); + if (device_create_file(&btv->video_dev->dev, + &dev_attr_card)<0) { + pr_err("%d: device_create_file 'card' failed\n", btv->c.nr); + goto err; + } + + /* vbi */ + btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); + + if (NULL == btv->vbi_dev) + goto err; + if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, + vbi_nr[btv->c.nr]) < 0) + goto err; + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->vbi_dev)); + + if (!btv->has_radio) + return 0; + /* radio */ + btv->radio_dev = vdev_init(btv, &radio_template, "radio"); + if (NULL == btv->radio_dev) + goto err; + if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, + radio_nr[btv->c.nr]) < 0) + goto err; + pr_info("%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->radio_dev)); + + /* all done */ + return 0; + + err: + bttv_unregister_video(btv); + return -1; +} + + +/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ +/* response on cards with no firmware is not enabled by OF */ +static void pci_set_command(struct pci_dev *dev) +{ +#if defined(__powerpc__) + unsigned int cmd; + + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif +} + +static int __devinit bttv_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int result; + unsigned char lat; + struct bttv *btv; + + if (bttv_num == BTTV_MAX) + return -ENOMEM; + pr_info("Bt8xx card found (%d)\n", bttv_num); + bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); + if (btv == NULL) { + pr_err("out of memory\n"); + return -ENOMEM; + } + btv->c.nr = bttv_num; + snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name), + "bttv%d", btv->c.nr); + + /* initialize structs / fill in defaults */ + mutex_init(&btv->lock); + spin_lock_init(&btv->s_lock); + spin_lock_init(&btv->gpio_lock); + init_waitqueue_head(&btv->i2c_queue); + INIT_LIST_HEAD(&btv->c.subs); + INIT_LIST_HEAD(&btv->capture); + INIT_LIST_HEAD(&btv->vcapture); + v4l2_prio_init(&btv->prio); + + init_timer(&btv->timeout); + btv->timeout.function = bttv_irq_timeout; + btv->timeout.data = (unsigned long)btv; + + btv->i2c_rc = -1; + btv->tuner_type = UNSET; + btv->new_input = UNSET; + btv->has_radio=radio[btv->c.nr]; + + /* pci stuff (init, get irq/mmio, ... */ + btv->c.pci = dev; + btv->id = dev->device; + if (pci_enable_device(dev)) { + pr_warn("%d: Can't enable device\n", btv->c.nr); + return -EIO; + } + if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + pr_warn("%d: No suitable DMA available\n", btv->c.nr); + return -EIO; + } + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + btv->c.v4l2_dev.name)) { + pr_warn("%d: can't request iomem (0x%llx)\n", + btv->c.nr, + (unsigned long long)pci_resource_start(dev, 0)); + return -EBUSY; + } + pci_set_master(dev); + pci_set_command(dev); + + result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); + if (result < 0) { + pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); + goto fail0; + } + + btv->revision = dev->revision; + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n", + bttv_num, btv->id, btv->revision, pci_name(dev), + btv->c.pci->irq, lat, + (unsigned long long)pci_resource_start(dev, 0)); + schedule(); + + btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); + if (NULL == btv->bt848_mmio) { + pr_err("%d: ioremap() failed\n", btv->c.nr); + result = -EIO; + goto fail1; + } + + /* identify card */ + bttv_idcard(btv); + + /* disable irqs, register irq handler */ + btwrite(0, BT848_INT_MASK); + result = request_irq(btv->c.pci->irq, bttv_irq, + IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); + if (result < 0) { + pr_err("%d: can't get IRQ %d\n", + bttv_num, btv->c.pci->irq); + goto fail1; + } + + if (0 != bttv_handle_chipset(btv)) { + result = -EIO; + goto fail2; + } + + /* init options from insmod args */ + btv->opt_combfilter = combfilter; + btv->opt_lumafilter = lumafilter; + btv->opt_automute = automute; + btv->opt_chroma_agc = chroma_agc; + btv->opt_adc_crush = adc_crush; + btv->opt_vcr_hack = vcr_hack; + btv->opt_whitecrush_upper = whitecrush_upper; + btv->opt_whitecrush_lower = whitecrush_lower; + btv->opt_uv_ratio = uv_ratio; + btv->opt_full_luma_range = full_luma_range; + btv->opt_coring = coring; + + /* fill struct bttv with some useful defaults */ + btv->init.btv = btv; + btv->init.ov.w.width = 320; + btv->init.ov.w.height = 240; + btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + btv->init.width = 320; + btv->init.height = 240; + btv->input = 0; + + /* initialize hardware */ + if (bttv_gpio) + bttv_gpio_tracking(btv,"pre-init"); + + bttv_risc_init_main(btv); + init_bt848(btv); + + /* gpio */ + btwrite(0x00, BT848_GPIO_REG_INP); + btwrite(0x00, BT848_GPIO_OUT_EN); + if (bttv_verbose) + bttv_gpio_tracking(btv,"init"); + + /* needs to be done before i2c is registered */ + bttv_init_card1(btv); + + /* register i2c + gpio */ + init_bttv_i2c(btv); + + /* some card-specific stuff (needs working i2c) */ + bttv_init_card2(btv); + bttv_init_tuner(btv); + init_irqreg(btv); + + /* register video4linux + input */ + if (!bttv_tvcards[btv->c.type].no_video) { + bttv_register_video(btv); + bt848_bright(btv,32768); + bt848_contrast(btv, 27648); + bt848_hue(btv,32768); + bt848_sat(btv,32768); + audio_mute(btv, 1); + set_input(btv, 0, btv->tvnorm); + bttv_crop_reset(&btv->crop[0], btv->tvnorm); + btv->crop[1] = btv->crop[0]; /* current = default */ + disclaim_vbi_lines(btv); + disclaim_video_lines(btv); + } + + /* add subdevices and autoload dvb-bt8xx if needed */ + if (bttv_tvcards[btv->c.type].has_dvb) { + bttv_sub_add_device(&btv->c, "dvb"); + request_modules(btv); + } + + if (!disable_ir) { + init_bttv_i2c_ir(btv); + bttv_input_init(btv); + } + + /* everything is fine */ + bttv_num++; + return 0; + +fail2: + free_irq(btv->c.pci->irq,btv); + +fail1: + v4l2_device_unregister(&btv->c.v4l2_dev); + +fail0: + if (btv->bt848_mmio) + iounmap(btv->bt848_mmio); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); + return result; +} + +static void __devexit bttv_remove(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + + if (bttv_verbose) + pr_info("%d: unloading\n", btv->c.nr); + + if (bttv_tvcards[btv->c.type].has_dvb) + flush_request_modules(btv); + + /* shutdown everything (DMA+IRQs) */ + btand(~15, BT848_GPIO_DMA_CTL); + btwrite(0, BT848_INT_MASK); + btwrite(~0x0, BT848_INT_STAT); + btwrite(0x0, BT848_GPIO_OUT_EN); + if (bttv_gpio) + bttv_gpio_tracking(btv,"cleanup"); + + /* tell gpio modules we are leaving ... */ + btv->shutdown=1; + bttv_input_fini(btv); + bttv_sub_del_devices(&btv->c); + + /* unregister i2c_bus + input */ + fini_bttv_i2c(btv); + + /* unregister video4linux */ + bttv_unregister_video(btv); + + /* free allocated memory */ + btcx_riscmem_free(btv->c.pci,&btv->main); + + /* free ressources */ + free_irq(btv->c.pci->irq,btv); + iounmap(btv->bt848_mmio); + release_mem_region(pci_resource_start(btv->c.pci,0), + pci_resource_len(btv->c.pci,0)); + + v4l2_device_unregister(&btv->c.v4l2_dev); + bttvs[btv->c.nr] = NULL; + kfree(btv); + + return; +} + +#ifdef CONFIG_PM +static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + struct bttv_buffer_set idle; + unsigned long flags; + + dprintk("%d: suspend %d\n", btv->c.nr, state.event); + + /* stop dma + irqs */ + spin_lock_irqsave(&btv->s_lock,flags); + memset(&idle, 0, sizeof(idle)); + btv->state.video = btv->curr; + btv->state.vbi = btv->cvbi; + btv->state.loop_irq = btv->loop_irq; + btv->curr = idle; + btv->loop_irq = 0; + bttv_buffer_activate_video(btv, &idle); + bttv_buffer_activate_vbi(btv, NULL); + bttv_set_dma(btv, 0); + btwrite(0, BT848_INT_MASK); + spin_unlock_irqrestore(&btv->s_lock,flags); + + /* save bt878 state */ + btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); + btv->state.gpio_data = gpio_read(); + + /* save pci state */ + pci_save_state(pci_dev); + if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + pci_disable_device(pci_dev); + btv->state.disabled = 1; + } + return 0; +} + +static int bttv_resume(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct bttv *btv = to_bttv(v4l2_dev); + unsigned long flags; + int err; + + dprintk("%d: resume\n", btv->c.nr); + + /* restore pci state */ + if (btv->state.disabled) { + err=pci_enable_device(pci_dev); + if (err) { + pr_warn("%d: Can't enable device\n", btv->c.nr); + return err; + } + btv->state.disabled = 0; + } + err=pci_set_power_state(pci_dev, PCI_D0); + if (err) { + pci_disable_device(pci_dev); + pr_warn("%d: Can't enable device\n", btv->c.nr); + btv->state.disabled = 1; + return err; + } + + pci_restore_state(pci_dev); + + /* restore bt878 state */ + bttv_reinit_bt848(btv); + gpio_inout(0xffffff, btv->state.gpio_enable); + gpio_write(btv->state.gpio_data); + + /* restart dma */ + spin_lock_irqsave(&btv->s_lock,flags); + btv->curr = btv->state.video; + btv->cvbi = btv->state.vbi; + btv->loop_irq = btv->state.loop_irq; + bttv_buffer_activate_video(btv, &btv->curr); + bttv_buffer_activate_vbi(btv, btv->cvbi); + bttv_set_dma(btv, 0); + spin_unlock_irqrestore(&btv->s_lock,flags); + return 0; +} +#endif + +static struct pci_device_id bttv_pci_tbl[] = { + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 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 = __devexit_p(bttv_remove), +#ifdef CONFIG_PM + .suspend = bttv_suspend, + .resume = bttv_resume, +#endif +}; + +static int __init bttv_init_module(void) +{ + int ret; + + bttv_num = 0; + + pr_info("driver version %s loaded\n", BTTV_VERSION); + if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) + gbuffers = 2; + if (gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; + if (bttv_verbose) + pr_info("using %d buffers with %dk (%d pages) each for capture\n", + gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); + + bttv_check_chipset(); + + ret = bus_register(&bttv_sub_bus_type); + if (ret < 0) { + pr_warn("bus_register error: %d\n", ret); + return ret; + } + ret = pci_register_driver(&bttv_pci_driver); + if (ret < 0) + bus_unregister(&bttv_sub_bus_type); + + return ret; +} + +static void __exit bttv_cleanup_module(void) +{ + pci_unregister_driver(&bttv_pci_driver); + bus_unregister(&bttv_sub_bus_type); +} + +module_init(bttv_init_module); +module_exit(bttv_cleanup_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c new file mode 100644 index 000000000000..922e8233fd0b --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-gpio.c @@ -0,0 +1,189 @@ +/* + + bttv-gpio.c -- gpio sub drivers + + sysfs-based sub driver interface for bttv + mainly intended for gpio access + + + Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999-2003 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "bttvp.h" + +/* ----------------------------------------------------------------------- */ +/* internal: the bttv "bus" */ + +static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) +{ + struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); + int len = strlen(sub->wanted); + + if (0 == strncmp(dev_name(dev), sub->wanted, len)) + return 1; + return 0; +} + +static int bttv_sub_probe(struct device *dev) +{ + struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); + struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); + + return sub->probe ? sub->probe(sdev) : -ENODEV; +} + +static int bttv_sub_remove(struct device *dev) +{ + struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); + struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); + + if (sub->remove) + sub->remove(sdev); + return 0; +} + +struct bus_type bttv_sub_bus_type = { + .name = "bttv-sub", + .match = &bttv_sub_bus_match, + .probe = bttv_sub_probe, + .remove = bttv_sub_remove, +}; + +static void release_sub_device(struct device *dev) +{ + struct bttv_sub_device *sub = to_bttv_sub_dev(dev); + kfree(sub); +} + +int bttv_sub_add_device(struct bttv_core *core, char *name) +{ + struct bttv_sub_device *sub; + int err; + + sub = kzalloc(sizeof(*sub),GFP_KERNEL); + if (NULL == sub) + return -ENOMEM; + + sub->core = core; + sub->dev.parent = &core->pci->dev; + sub->dev.bus = &bttv_sub_bus_type; + sub->dev.release = release_sub_device; + dev_set_name(&sub->dev, "%s%d", name, core->nr); + + err = device_register(&sub->dev); + if (0 != err) { + kfree(sub); + return err; + } + pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); + list_add_tail(&sub->list,&core->subs); + return 0; +} + +int bttv_sub_del_devices(struct bttv_core *core) +{ + struct bttv_sub_device *sub, *save; + + list_for_each_entry_safe(sub, save, &core->subs, list) { + list_del(&sub->list); + device_unregister(&sub->dev); + } + return 0; +} + +/* ----------------------------------------------------------------------- */ +/* external: sub-driver register/unregister */ + +int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) +{ + sub->drv.bus = &bttv_sub_bus_type; + snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); + return driver_register(&sub->drv); +} +EXPORT_SYMBOL(bttv_sub_register); + +int bttv_sub_unregister(struct bttv_sub_driver *sub) +{ + driver_unregister(&sub->drv); + return 0; +} +EXPORT_SYMBOL(bttv_sub_unregister); + +/* ----------------------------------------------------------------------- */ +/* external: gpio access functions */ + +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_OUT_EN); + data = data & ~mask; + data = data | (mask & outbits); + btwrite(data,BT848_GPIO_OUT_EN); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} + +u32 bttv_gpio_read(struct bttv_core *core) +{ + struct bttv *btv = container_of(core, struct bttv, c); + u32 value; + + value = btread(BT848_GPIO_DATA); + return value; +} + +void bttv_gpio_write(struct bttv_core *core, u32 value) +{ + struct bttv *btv = container_of(core, struct bttv, c); + + btwrite(value,BT848_GPIO_DATA); +} + +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) +{ + struct bttv *btv = container_of(core, struct bttv, c); + unsigned long flags; + u32 data; + + spin_lock_irqsave(&btv->gpio_lock,flags); + data = btread(BT848_GPIO_DATA); + data = data & ~mask; + data = data | (mask & bits); + btwrite(data,BT848_GPIO_DATA); + spin_unlock_irqrestore(&btv->gpio_lock,flags); +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c new file mode 100644 index 000000000000..580c8e682392 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -0,0 +1,397 @@ +/* + + bttv-i2c.c -- all the i2c code is here + + 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-2003 Gerd Knorr + + (c) 2005 Mauro Carvalho Chehab + - Multituner support and i2c address binding + + 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include "bttvp.h" +#include +#include +#include + +static int i2c_debug; +static int i2c_hw; +static int i2c_scan; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); +module_param(i2c_hw, int, 0444); +MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " + "instead of software bitbang"); +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +static unsigned int i2c_udelay = 5; +module_param(i2c_udelay, int, 0444); +MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs " + "(should be 5 or higher). Lower value means higher bus speed."); + +/* ----------------------------------------------------------------------- */ +/* I2C functions - bitbanging adapter (software i2c) */ + +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 struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = { + .setsda = bttv_bit_setsda, + .setscl = bttv_bit_setscl, + .getsda = bttv_bit_getsda, + .getscl = bttv_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - hardware i2c */ + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static int +bttv_i2c_wait_done(struct bttv *btv) +{ + int rc = 0; + + /* timeout */ + if (wait_event_interruptible_timeout(btv->i2c_queue, + btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS) + rc = -EIO; + + if (btv->i2c_done & BT848_INT_RACK) + rc = 1; + btv->i2c_done = 0; + return rc; +} + +#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ + BT848_I2C_SCL | BT848_I2C_SDA) + +static int +bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + int retval,cnt; + + /* sanity checks */ + if (0 == msg->len) + return -EINVAL; + + /* start, address + first byte */ + xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; + if (msg->len > 1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) { + pr_cont(" addr << 1, msg->buf[0]); + } + + for (cnt = 1; cnt < msg->len; cnt++ ) { + /* following bytes */ + xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + if (i2c_debug) + pr_cont(" %02x", msg->buf[cnt]); + } + if (!(xmit & BT878_I2C_NOSTOP)) + pr_cont(">\n"); + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + pr_cont(" ERR: %d\n",retval); + return retval; +} + +static int +bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) +{ + u32 xmit; + u32 cnt; + int retval; + + for (cnt = 0; cnt < msg->len; cnt++) { + xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; + if (cnt < msg->len-1) + xmit |= BT848_I2C_W3B; + if (cnt < msg->len-1 || !last) + xmit |= BT878_I2C_NOSTOP; + if (cnt) + xmit |= BT878_I2C_NOSTART; + + if (i2c_debug) { + if (!(xmit & BT878_I2C_NOSTART)) + pr_cont(" addr << 1) +1); + } + + btwrite(xmit, BT848_I2C); + retval = bttv_i2c_wait_done(btv); + if (retval < 0) + goto err; + if (retval == 0) + goto eio; + msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; + if (i2c_debug) { + pr_cont(" =%02x", msg->buf[cnt]); + } + if (i2c_debug && !(xmit & BT878_I2C_NOSTOP)) + pr_cont(" >\n"); + } + + + return msg->len; + + eio: + retval = -EIO; + err: + if (i2c_debug) + pr_cont(" ERR: %d\n",retval); + return retval; +} + +static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); + struct bttv *btv = to_bttv(v4l2_dev); + int retval = 0; + int i; + + if (i2c_debug) + pr_debug("bt-i2c:"); + + btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); + for (i = 0 ; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { + /* read */ + retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } else { + /* write */ + retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); + if (retval < 0) + goto err; + } + } + return num; + + err: + return retval; +} + +static const struct i2c_algorithm bttv_algo = { + .master_xfer = bttv_i2c_xfer, + .functionality = functionality, +}; + +/* ----------------------------------------------------------------------- */ +/* I2C functions - common stuff */ + +/* read I2C */ +int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +{ + unsigned char buffer = 0; + + if (0 != btv->i2c_rc) + return -1; + if (bttv_verbose && NULL != probe_for) + pr_info("%d: i2c: checking for %s @ 0x%02x... ", + btv->c.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) + pr_cont("not found\n"); + } else + pr_warn("%d: i2c read 0x%x: error\n", + btv->c.nr, addr); + return -1; + } + if (bttv_verbose && NULL != probe_for) + pr_cont("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_rc) + 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) +{ + memset(eedata, 0, 256); + if (0 != btv->i2c_rc) + return; + btv->i2c_client.addr = addr >> 1; + tveeprom_read(&btv->i2c_client, eedata, 256); +} + +static char *i2c_devs[128] = { + [ 0x1c >> 1 ] = "lgdt330x", + [ 0x30 >> 1 ] = "IR (hauppauge)", + [ 0x80 >> 1 ] = "msp34xx", + [ 0x86 >> 1 ] = "tda9887", + [ 0xa0 >> 1 ] = "eeprom", + [ 0xc0 >> 1 ] = "tuner (analog)", + [ 0xc2 >> 1 ] = "tuner (analog)", +}; + +static void do_i2c_scan(char *name, struct i2c_client *c) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { + c->addr = i; + rc = i2c_master_recv(c,&buf,0); + if (rc < 0) + continue; + pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", + name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + } +} + +/* init + register i2c adapter */ +int __devinit init_bttv_i2c(struct bttv *btv) +{ + strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); + + if (i2c_hw) + btv->use_i2c_hw = 1; + if (btv->use_i2c_hw) { + /* bt878 */ + strlcpy(btv->c.i2c_adap.name, "bt878", + sizeof(btv->c.i2c_adap.name)); + btv->c.i2c_adap.algo = &bttv_algo; + } else { + /* bt848 */ + /* Prevents usage of invalid delay values */ + if (i2c_udelay<5) + i2c_udelay=5; + + strlcpy(btv->c.i2c_adap.name, "bttv", + sizeof(btv->c.i2c_adap.name)); + memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, + sizeof(bttv_i2c_algo_bit_template)); + btv->i2c_algo.udelay = i2c_udelay; + btv->i2c_algo.data = btv; + btv->c.i2c_adap.algo_data = &btv->i2c_algo; + } + btv->c.i2c_adap.owner = THIS_MODULE; + + btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; + snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), + "bt%d #%d [%s]", btv->id, btv->c.nr, + btv->use_i2c_hw ? "hw" : "sw"); + + i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev); + btv->i2c_client.adapter = &btv->c.i2c_adap; + + + if (btv->use_i2c_hw) { + btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); + } else { + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap); + } + if (0 == btv->i2c_rc && i2c_scan) + do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); + + return btv->i2c_rc; +} diff --git a/drivers/media/pci/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c new file mode 100644 index 000000000000..a6a540dc9e4b --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-if.c @@ -0,0 +1,121 @@ +/* + + bttv-if.c -- old gpio interface to other kernel modules + don't use in new code, will go away in 2.7 + have a look at bttv-gpio.c instead. + + 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-2003 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 "bttvp.h" + +EXPORT_SYMBOL(bttv_get_pcidev); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); + +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +struct pci_dev* bttv_get_pcidev(unsigned int card) +{ + if (card >= bttv_num) + return NULL; + if (!bttvs[card]) + return NULL; + + return bttvs[card]->c.pci; +} + + +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]; + if (!btv) + return -ENODEV; + + gpio_inout(mask,data); + if (bttv_gpio) + bttv_gpio_tracking(btv,"extern enable"); + 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) + return -ENODEV; + + if(btv->shutdown) { + return -ENODEV; + } + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + *data = gpio_read(); + 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]; + if (!btv) + return -ENODEV; + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + gpio_bits(mask,data); + if (bttv_gpio) + bttv_gpio_tracking(btv,"extern write"); + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c new file mode 100644 index 000000000000..ef4c7cd41982 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -0,0 +1,589 @@ +/* + * + * Copyright (c) 2003 Gerd Knorr + * Copyright (c) 2003 Pavel Machek + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "bttv.h" +#include "bttvp.h" + + +static int ir_debug; +module_param(ir_debug, int, 0644); + +static int ir_rc5_remote_gap = 885; +module_param(ir_rc5_remote_gap, int, 0644); + +#undef dprintk +#define dprintk(fmt, ...) \ +do { \ + if (ir_debug >= 1) \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +#define DEVNAME "bttv-input" + +#define MODULE_NAME "bttv" + +/* ---------------------------------------------------------------------- */ + +static void ir_handle_key(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + u32 gpio,data; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + if (ir->polling) { + if (ir->last_gpio == gpio) + return; + ir->last_gpio = gpio; + } + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + dprintk("irq gpio=0x%x code=%d | %s%s%s\n", + gpio, data, + ir->polling ? "poll" : "irq", + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || + (ir->mask_keyup && !(gpio & ir->mask_keyup))) { + rc_keydown_notimeout(ir->dev, data, 0); + } else { + /* HACK: Probably, ir->mask_keydown is missing + for this board */ + if (btv->c.type == BTTV_BOARD_WINFAST2000) + rc_keydown_notimeout(ir->dev, data, 0); + + rc_keyup(ir->dev); + } +} + +static void ir_enltv_handle_key(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + u32 gpio, data, keyup; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + + /* Check if it is keyup */ + keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + + if ((ir->last_gpio & 0x7f) != data) { + dprintk("gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "up/down"); + + rc_keydown_notimeout(ir->dev, data, 0); + if (keyup) + rc_keyup(ir->dev); + } else { + if ((ir->last_gpio & 1 << 31) == keyup) + return; + + dprintk("(cnt) gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "down"); + + if (keyup) + rc_keyup(ir->dev); + else + rc_keydown_notimeout(ir->dev, data, 0); + } + + ir->last_gpio = data | keyup; +} + +static int bttv_rc5_irq(struct bttv *btv); + +void bttv_input_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + + if (ir->rc5_gpio) + bttv_rc5_irq(btv); + else if (!ir->polling) + ir_handle_key(btv); +} + +static void bttv_input_timer(unsigned long data) +{ + struct bttv *btv = (struct bttv*)data; + struct bttv_ir *ir = btv->remote; + + if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) + ir_enltv_handle_key(btv); + else + ir_handle_key(btv); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +} + +/* + * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying + * on the rc-core way. As we need to be sure that both IRQ transitions are + * properly triggered, Better to touch it only with this hardware for + * testing. + */ + +#define RC5_START(x) (((x) >> 12) & 3) +#define RC5_TOGGLE(x) (((x) >> 11) & 1) +#define RC5_ADDR(x) (((x) >> 6) & 31) +#define RC5_INSTR(x) ((x) & 63) + +/* decode raw bit pattern to RC5 code */ +static u32 bttv_rc5_decode(unsigned int code) +{ + unsigned int org_code = code; + unsigned int pair; + unsigned int rc5 = 0; + int i; + + for (i = 0; i < 14; ++i) { + pair = code & 0x3; + code >>= 2; + + rc5 <<= 1; + switch (pair) { + case 0: + case 2: + break; + case 1: + rc5 |= 1; + break; + case 3: + dprintk("rc5_decode(%x) bad code\n", + org_code); + return 0; + } + } + dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " + "instr=%x\n", rc5, org_code, RC5_START(rc5), + RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); + return rc5; +} + +static void bttv_rc5_timer_end(unsigned long data) +{ + struct bttv_ir *ir = (struct bttv_ir *)data; + struct timeval tv; + u32 gap; + u32 rc5 = 0; + + /* get time */ + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + /* signal we're ready to start a new code */ + ir->active = false; + + /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ + if (gap < 28000) { + dprintk("spurious timer_end\n"); + return; + } + + if (ir->last_bit < 20) { + /* ignore spurious codes (caused by light/other remotes) */ + dprintk("short code: %x\n", ir->code); + } else { + ir->code = (ir->code << ir->shift_by) | 1; + rc5 = bttv_rc5_decode(ir->code); + + /* two start bits? */ + if (RC5_START(rc5) != ir->start) { + pr_info(DEVNAME ":" + " rc5 start bits invalid: %u\n", RC5_START(rc5)); + + /* right address? */ + } else if (RC5_ADDR(rc5) == ir->addr) { + u32 toggle = RC5_TOGGLE(rc5); + u32 instr = RC5_INSTR(rc5); + + /* Good code */ + rc_keydown(ir->dev, instr, toggle); + dprintk("instruction %x, toggle %x\n", + instr, toggle); + } + } +} + +static int bttv_rc5_irq(struct bttv *btv) +{ + struct bttv_ir *ir = btv->remote; + struct timeval tv; + u32 gpio; + u32 gap; + unsigned long current_jiffies; + + /* read gpio port */ + gpio = bttv_gpio_read(&btv->c); + + /* get time of bit */ + current_jiffies = jiffies; + do_gettimeofday(&tv); + + /* avoid overflow with gap >1s */ + if (tv.tv_sec - ir->base_time.tv_sec > 1) { + gap = 200000; + } else { + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + } + + dprintk("RC5 IRQ: gap %d us for %s\n", + gap, (gpio & 0x20) ? "mark" : "space"); + + /* remote IRQ? */ + if (!(gpio & 0x20)) + return 0; + + /* active code => add bit */ + if (ir->active) { + /* only if in the code (otherwise spurious IRQ or timer + late) */ + if (ir->last_bit < 28) { + ir->last_bit = (gap - ir_rc5_remote_gap / 2) / + ir_rc5_remote_gap; + ir->code |= 1 << ir->last_bit; + } + /* starting new code */ + } else { + ir->active = true; + ir->code = 0; + ir->base_time = tv; + ir->last_bit = 0; + + mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30)); + } + + /* toggle GPIO pin 4 to reset the irq */ + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + return 1; +} + +/* ---------------------------------------------------------------------- */ + +static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) +{ + if (ir->polling) { + setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv); + ir->timer.expires = jiffies + msecs_to_jiffies(1000); + add_timer(&ir->timer); + } else if (ir->rc5_gpio) { + /* set timer_end for code completion */ + setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir); + ir->shift_by = 1; + ir->start = 3; + ir->addr = 0x0; + ir->rc5_remote_gap = ir_rc5_remote_gap; + } +} + +static void bttv_ir_stop(struct bttv *btv) +{ + if (btv->remote->polling) + del_timer_sync(&btv->remote->timer); + + if (btv->remote->rc5_gpio) { + u32 gpio; + + del_timer_sync(&btv->remote->timer); + + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + } +} + +/* + * Get_key functions used by I2C remotes + */ + +static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char b; + + /* poll IR chip */ + if (1 != i2c_master_recv(ir->c, &b, 1)) { + dprintk("read error\n"); + return -EIO; + } + + /* ignore 0xaa */ + if (b==0xaa) + return 0; + dprintk("key %02x\n", b); + + /* + * NOTE: + * lirc_i2c maps the pv951 code as: + * addr = 0x61D6 + * cmd = bit_reverse (b) + * So, it seems that this device uses NEC extended + * I decided to not fix the table, due to two reasons: + * 1) Without the actual device, this is only a guess; + * 2) As the addr is not reported via I2C, nor can be changed, + * the device is bound to the vendor-provided RC. + */ + + *ir_key = b; + *ir_raw = b; + return 1; +} + +/* Instantiate the I2C IR receiver device, if present */ +void __devinit init_bttv_i2c_ir(struct bttv *btv) +{ + const unsigned short addr_list[] = { + 0x1a, 0x18, 0x64, 0x30, 0x71, + I2C_CLIENT_END + }; + struct i2c_board_info info; + + if (0 != btv->i2c_rc) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&btv->init_data, 0, sizeof(btv->init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + + switch (btv->c.type) { + case BTTV_BOARD_PV951: + btv->init_data.name = "PV951"; + btv->init_data.get_key = get_key_pv951; + btv->init_data.ir_codes = RC_MAP_PV951; + info.addr = 0x4b; + break; + default: + /* + * The external IR receiver is at i2c address 0x34 (0x35 for + * reads). Future Hauppauge cards will have an internal + * receiver at 0x30 (0x31 for reads). In theory, both can be + * fitted, and Hauppauge suggest an external overrides an + * internal. + * That's why we probe 0x1a (~0x34) first. CB + */ + + i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); + return; + } + + if (btv->init_data.name) + info.platform_data = &btv->init_data; + i2c_new_device(&btv->c.i2c_adap, &info); + + return; +} + +int __devexit fini_bttv_i2c(struct bttv *btv) +{ + if (0 != btv->i2c_rc) + return 0; + + return i2c_del_adapter(&btv->c.i2c_adap); +} + +int bttv_input_init(struct bttv *btv) +{ + struct bttv_ir *ir; + char *ir_codes = NULL; + struct rc_dev *rc; + int err = -ENOMEM; + + if (!btv->has_remote) + return -ENODEV; + + ir = kzalloc(sizeof(*ir),GFP_KERNEL); + rc = rc_allocate_device(); + if (!ir || !rc) + goto err_out_free; + + /* detect & configure */ + switch (btv->c.type) { + case BTTV_BOARD_AVERMEDIA: + case BTTV_BOARD_AVPHONE98: + case BTTV_BOARD_AVERMEDIA98: + ir_codes = RC_MAP_AVERMEDIA; + ir->mask_keycode = 0xf88000; + ir->mask_keydown = 0x010000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_AVDVBT_761: + case BTTV_BOARD_AVDVBT_771: + ir_codes = RC_MAP_AVERMEDIA_DVBT; + ir->mask_keycode = 0x0f00c0; + ir->mask_keydown = 0x000020; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_PXELVWPLTVPAK: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x003e00; + ir->mask_keyup = 0x010000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_PV_M4900: + case BTTV_BOARD_PV_BT878P_9B: + case BTTV_BOARD_PV_BT878P_PLUS: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + + case BTTV_BOARD_WINFAST2000: + ir_codes = RC_MAP_WINFAST; + ir->mask_keycode = 0x1f8; + break; + case BTTV_BOARD_MAGICTVIEW061: + case BTTV_BOARD_MAGICTVIEW063: + ir_codes = RC_MAP_WINFAST; + ir->mask_keycode = 0x0008e000; + ir->mask_keydown = 0x00200000; + break; + case BTTV_BOARD_APAC_VIEWCOMP: + ir_codes = RC_MAP_APAC_VIEWCOMP; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x008000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_ASKEY_CPH03X: + case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: + case BTTV_BOARD_CONTVFMI: + ir_codes = RC_MAP_PIXELVIEW; + ir->mask_keycode = 0x001F00; + ir->mask_keyup = 0x006000; + ir->polling = 50; // ms + break; + case BTTV_BOARD_NEBULA_DIGITV: + ir_codes = RC_MAP_NEBULA; + ir->rc5_gpio = true; + break; + case BTTV_BOARD_MACHTV_MAGICTV: + ir_codes = RC_MAP_APAC_VIEWCOMP; + ir->mask_keycode = 0x001F00; + ir->mask_keyup = 0x004000; + ir->polling = 50; /* ms */ + break; + case BTTV_BOARD_KOZUMI_KTV_01C: + ir_codes = RC_MAP_PCTV_SEDNA; + ir->mask_keycode = 0x001f00; + ir->mask_keyup = 0x006000; + ir->polling = 50; /* ms */ + break; + case BTTV_BOARD_ENLTV_FM_2: + ir_codes = RC_MAP_ENCORE_ENLTV2; + ir->mask_keycode = 0x00fd00; + ir->mask_keyup = 0x000080; + ir->polling = 1; /* ms */ + ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), + ir->mask_keycode); + break; + } + if (NULL == ir_codes) { + dprintk("Ooops: IR config error [card=%d]\n", btv->c.type); + err = -ENODEV; + goto err_out_free; + } + + if (ir->rc5_gpio) { + u32 gpio; + /* enable remote irq */ + bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + bttv_gpio_write(&btv->c, gpio | (1 << 4)); + } else { + /* init hardware-specific stuff */ + bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); + } + + /* init input device */ + ir->dev = rc; + + snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", + btv->c.type); + snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", + pci_name(btv->c.pci)); + + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_PCI; + rc->input_id.version = 1; + if (btv->c.pci->subsystem_vendor) { + rc->input_id.vendor = btv->c.pci->subsystem_vendor; + rc->input_id.product = btv->c.pci->subsystem_device; + } else { + rc->input_id.vendor = btv->c.pci->vendor; + rc->input_id.product = btv->c.pci->device; + } + rc->dev.parent = &btv->c.pci->dev; + rc->map_name = ir_codes; + rc->driver_name = MODULE_NAME; + + btv->remote = ir; + bttv_ir_start(btv, ir); + + /* all done */ + err = rc_register_device(rc); + if (err) + goto err_out_stop; + + return 0; + + err_out_stop: + bttv_ir_stop(btv); + btv->remote = NULL; + err_out_free: + rc_free_device(rc); + kfree(ir); + return err; +} + +void bttv_input_fini(struct bttv *btv) +{ + if (btv->remote == NULL) + return; + + bttv_ir_stop(btv); + rc_unregister_device(btv->remote->dev); + kfree(btv->remote); + btv->remote = NULL; +} diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c new file mode 100644 index 000000000000..82cc47d2e3fa --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -0,0 +1,909 @@ +/* + + bttv-risc.c -- interfaces to other kernel modules + + bttv risc code handling + - memory management + - generation + + (c) 2000-2003 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bttvp.h" + +#define VCR_HACK_LINES 4 + +/* ---------------------------------------------------------- */ +/* risc code generators */ + +int +bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int padding, unsigned int skip_lines, + unsigned int store_lines) +{ + u32 instructions,line,todo; + struct scatterlist *sg; + __le32 *rp; + int rc; + + /* estimate risc mem: worst case is one write per page border + + one write per scan line + sync + jump (all 2 dwords). padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + instructions = skip_lines * 4; + instructions += (1 + ((bpl + padding) * store_lines) + / PAGE_SIZE + store_lines) * 8; + instructions += 2 * 8; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0) + return rc; + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(rp++) = cpu_to_le32(0); + + while (skip_lines-- > 0) { + *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL | + BT848_RISC_EOL | bpl); + } + + /* scan lines */ + sg = sglist; + for (line = 0; line < store_lines; line++) { + if ((btv->opt_vcr_hack) && + (line >= (store_lines - VCR_HACK_LINES))) + continue; + while (offset && offset >= sg_dma_len(sg)) { + offset -= sg_dma_len(sg); + sg++; + } + if (bpl <= sg_dma_len(sg)-offset) { + /* fits into current chunk */ + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + BT848_RISC_EOL|bpl); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + offset+=bpl; + } else { + /* scanline needs to be splitted */ + todo = bpl; + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| + (sg_dma_len(sg)-offset)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + todo -= (sg_dma_len(sg)-offset); + offset = 0; + sg++; + while (todo > sg_dma_len(sg)) { + *(rp++)=cpu_to_le32(BT848_RISC_WRITE| + sg_dma_len(sg)); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + todo -= sg_dma_len(sg); + sg++; + } + *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| + todo); + *(rp++)=cpu_to_le32(sg_dma_address(sg)); + offset += todo; + } + offset += padding; + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +static int +bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + 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) +{ + unsigned int instructions,line,todo,ylen,chroma; + __le32 *rp; + u32 ri; + struct scatterlist *ysg; + struct scatterlist *usg; + struct scatterlist *vsg; + int topfield = (0 == yoffset); + 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 = ((3 + (ybpl + ypadding) * ylines * 2) + / PAGE_SIZE) + ylines; + instructions += 2; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) + return rc; + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(rp++) = cpu_to_le32(0); + + /* scan lines */ + ysg = sglist; + usg = sglist; + vsg = sglist; + for (line = 0; line < ylines; line++) { + if ((btv->opt_vcr_hack) && + (line >= (ylines - VCR_HACK_LINES))) + continue; + switch (vshift) { + case 0: + chroma = 1; + break; + case 1: + if (topfield) + chroma = ((line & 1) == 0); + else + chroma = ((line & 1) == 1); + break; + case 2: + if (topfield) + chroma = ((line & 3) == 0); + else + chroma = ((line & 3) == 2); + break; + default: + chroma = 0; + break; + } + + for (todo = ybpl; todo > 0; todo -= ylen) { + /* go to next sg entry if needed */ + while (yoffset && yoffset >= sg_dma_len(ysg)) { + yoffset -= sg_dma_len(ysg); + ysg++; + } + while (uoffset && uoffset >= sg_dma_len(usg)) { + uoffset -= sg_dma_len(usg); + usg++; + } + while (voffset && voffset >= sg_dma_len(vsg)) { + voffset -= sg_dma_len(vsg); + vsg++; + } + + /* calculate max number of bytes we can write */ + ylen = todo; + if (yoffset + ylen > sg_dma_len(ysg)) + ylen = sg_dma_len(ysg) - yoffset; + if (chroma) { + if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) + ylen = (sg_dma_len(usg) - uoffset) << hshift; + if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) + ylen = (sg_dma_len(vsg) - voffset) << hshift; + ri = BT848_RISC_WRITE123; + } else { + ri = BT848_RISC_WRITE1S23; + } + if (ybpl == todo) + ri |= BT848_RISC_SOL; + if (ylen == todo) + ri |= BT848_RISC_EOL; + + /* write risc instruction */ + *(rp++)=cpu_to_le32(ri | ylen); + *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | + (ylen >> hshift)); + *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); + yoffset += ylen; + if (chroma) { + *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); + uoffset += ylen >> hshift; + *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); + voffset += ylen >> hshift; + } + } + yoffset += ypadding; + if (chroma) { + uoffset += cpadding; + voffset += cpadding; + } + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +static int +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 dwords, rc, line, maxy, start, end; + unsigned skip, nskips; + struct btcx_skiplist *skips; + __le32 *rp; + u32 ri,ra; + u32 addr; + + /* skip list for window clipping */ + if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) + return -ENOMEM; + + /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions + + sync + jump (all 2 dwords) */ + dwords = (3 * ov->nclips + 2) * + ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height); + dwords += 4; + if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) { + kfree(skips); + return rc; + } + + /* sync instruction */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(rp++) = cpu_to_le32(0); + + addr = (unsigned long)btv->fbuf.base; + addr += btv->fbuf.fmt.bytesperline * ov->w.top; + addr += (fmt->depth >> 3) * ov->w.left; + + /* scan lines */ + for (maxy = -1, line = 0; line < ov->w.height; + line++, addr += btv->fbuf.fmt.bytesperline) { + if ((btv->opt_vcr_hack) && + (line >= (ov->w.height - VCR_HACK_LINES))) + continue; + if ((line%2) == 0 && skip_even) + continue; + if ((line%2) == 1 && skip_odd) + continue; + + /* calculate clipping */ + if (line > maxy) + 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) { + if (skip >= nskips) { + ri = BT848_RISC_WRITE; + end = ov->w.width; + } else if (start < skips[skip].start) { + ri = BT848_RISC_WRITE; + end = skips[skip].start; + } else { + ri = BT848_RISC_SKIP; + end = skips[skip].end; + skip++; + } + if (BT848_RISC_WRITE == ri) + ra = addr + (fmt->depth>>3)*start; + else + ra = 0; + + if (0 == start) + ri |= BT848_RISC_SOL; + if (ov->w.width == end) + ri |= BT848_RISC_EOL; + ri |= (fmt->depth>>3) * (end-start); + + *(rp++)=cpu_to_le32(ri); + if (0 != ra) + *(rp++)=cpu_to_le32(ra); + } + } + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + kfree(skips); + return 0; +} + +/* ---------------------------------------------------------- */ + +static void +bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo, + int width, int height, int interleaved, + const struct bttv_tvnorm *tvnorm) +{ + u32 xsf, sr; + int vdelay; + + int swidth = tvnorm->swidth; + int totalwidth = tvnorm->totalwidth; + int scaledtwidth = tvnorm->scaledtwidth; + + if (btv->input == btv->dig) { + swidth = 720; + totalwidth = 858; + scaledtwidth = 858; + } + + vdelay = tvnorm->vdelay; + + xsf = (width*scaledtwidth)/swidth; + geo->hscale = ((totalwidth*4096UL)/xsf-4096); + geo->hdelay = tvnorm->hdelayx1; + geo->hdelay = (geo->hdelay*width)/swidth; + geo->hdelay &= 0x3fe; + sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; + geo->vscale = (0x10000UL-sr) & 0x1fff; + geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | + ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); + geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; + 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); + geo->comb = (width < 769) ? 1 : 0; + } else { + geo->vtc = 0; + geo->comb = 0; + } +} + +static void +bttv_calc_geo (struct bttv * btv, + struct bttv_geometry * geo, + unsigned int width, + unsigned int height, + int both_fields, + const struct bttv_tvnorm * tvnorm, + const struct v4l2_rect * crop) +{ + unsigned int c_width; + unsigned int c_height; + u32 sr; + + if ((crop->left == tvnorm->cropcap.defrect.left + && crop->top == tvnorm->cropcap.defrect.top + && crop->width == tvnorm->cropcap.defrect.width + && crop->height == tvnorm->cropcap.defrect.height + && width <= tvnorm->swidth /* see PAL-Nc et al */) + || btv->input == btv->dig) { + bttv_calc_geo_old(btv, geo, width, height, + both_fields, tvnorm); + return; + } + + /* For bug compatibility the image size checks permit scale + factors > 16. See bttv_crop_calc_limits(). */ + c_width = min((unsigned int) crop->width, width * 16); + c_height = min((unsigned int) crop->height, height * 16); + + geo->width = width; + geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096; + /* Even to store Cb first, odd for Cr. */ + geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1; + + geo->sheight = c_height; + geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY; + sr = c_height >> !both_fields; + sr = (sr * 512U + (height >> 1)) / height - 512; + geo->vscale = (0x10000UL - sr) & 0x1fff; + geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0; + geo->vtotal = tvnorm->vtotal; + + geo->crop = (((geo->width >> 8) & 0x03) | + ((geo->hdelay >> 6) & 0x0c) | + ((geo->sheight >> 4) & 0x30) | + ((geo->vdelay >> 2) & 0xc0)); + + if (btv->opt_combfilter) { + geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); + geo->comb = (width < 769) ? 1 : 0; + } else { + geo->vtc = 0; + geo->comb = 0; + } +} + +static void +bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) +{ + int off = odd ? 0x80 : 0x00; + + if (geo->comb) + btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + else + btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); + + btwrite(geo->vtc, BT848_E_VTC+off); + btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); + btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); + btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); + btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); + btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); + btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); + 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); +} + +/* ---------------------------------------------------------- */ +/* risc group / risc main loop / dma management */ + +void +bttv_set_dma(struct bttv *btv, int override) +{ + unsigned long cmd; + int capctl; + + btv->cap_ctl = 0; + if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; + if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; + if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; + + capctl = 0; + capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ + capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ + capctl |= override; + + d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n", + btv->c.nr,capctl,btv->loop_irq, + btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, + btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, + btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, + btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); + + cmd = BT848_RISC_JUMP; + if (btv->loop_irq) { + cmd |= BT848_RISC_IRQ; + cmd |= (btv->loop_irq & 0x0f) << 16; + cmd |= (~btv->loop_irq & 0x0f) << 20; + } + if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { + mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); + } else { + del_timer(&btv->timeout); + } + btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); + + btaor(capctl, ~0x0f, BT848_CAP_CTL); + if (capctl) { + if (btv->dma_on) + return; + btwrite(btv->main.dma, BT848_RISC_STRT_ADD); + btor(3, BT848_GPIO_DMA_CTL); + btv->dma_on = 1; + } else { + if (!btv->dma_on) + return; + btand(~3, BT848_GPIO_DMA_CTL); + btv->dma_on = 0; + } + return; +} + +int +bttv_risc_init_main(struct bttv *btv) +{ + int rc; + + if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) + return rc; + dprintk("%d: risc main @ %08llx\n", + btv->c.nr, (unsigned long long)btv->main.dma); + + btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | + BT848_FIFO_STATUS_VRE); + btv->main.cpu[1] = cpu_to_le32(0); + btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); + + /* top field */ + btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); + btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); + + btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | + BT848_FIFO_STATUS_VRO); + btv->main.cpu[9] = cpu_to_le32(0); + + /* bottom field */ + btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); + btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); + + /* jump back to top field */ + btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); + btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); + + return 0; +} + +int +bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, + int irqflags) +{ + unsigned long cmd; + unsigned long next = btv->main.dma + ((slot+2) << 2); + + if (NULL == risc) { + d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot); + btv->main.cpu[slot+1] = cpu_to_le32(next); + } else { + d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n", + btv->c.nr, risc, slot, + (unsigned long long)risc->dma, irqflags); + cmd = BT848_RISC_JUMP; + 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); + } + return 0; +} + +void +bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) +{ + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + BUG_ON(in_interrupt()); + videobuf_waiton(q, &buf->vb, 0, 0); + videobuf_dma_unmap(q->dev, dma); + videobuf_dma_free(dma); + btcx_riscmem_free(btv->c.pci,&buf->bottom); + btcx_riscmem_free(btv->c.pci,&buf->top); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +int +bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi) +{ + struct btcx_riscmem *top; + struct btcx_riscmem *bottom; + int top_irq_flags; + int bottom_irq_flags; + + top = NULL; + bottom = NULL; + top_irq_flags = 0; + bottom_irq_flags = 0; + + if (vbi) { + unsigned int crop, vdelay; + + vbi->vb.state = VIDEOBUF_ACTIVE; + list_del(&vbi->vb.queue); + + /* VDELAY is start of video, end of VBI capturing. */ + crop = btread(BT848_E_CROP); + vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); + + if (vbi->geo.vdelay > vdelay) { + vdelay = vbi->geo.vdelay & 0xfe; + crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); + + btwrite(vdelay, BT848_E_VDELAY_LO); + btwrite(crop, BT848_E_CROP); + btwrite(vdelay, BT848_O_VDELAY_LO); + btwrite(crop, BT848_O_CROP); + } + + if (vbi->vbi_count[0] > 0) { + top = &vbi->top; + top_irq_flags = 4; + } + + if (vbi->vbi_count[1] > 0) { + top_irq_flags = 0; + bottom = &vbi->bottom; + bottom_irq_flags = 4; + } + } + + bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); + bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); + + return 0; +} + +int +bttv_buffer_activate_video(struct bttv *btv, + struct bttv_buffer_set *set) +{ + /* video capture */ + if (NULL != set->top && NULL != set->bottom) { + if (set->top == set->bottom) { + set->top->vb.state = VIDEOBUF_ACTIVE; + if (set->top->vb.queue.next) + list_del(&set->top->vb.queue); + } else { + set->top->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = VIDEOBUF_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->top_irq); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, + set->frame_irq); + btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), + ~0xff, BT848_COLOR_FMT); + btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), + ~0x0f, BT848_COLOR_CTL); + } else if (NULL != set->top) { + set->top->vb.state = VIDEOBUF_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, + set->frame_irq); + 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 = VIDEOBUF_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, + set->frame_irq); + 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); + } + return 0; +} + +/* ---------------------------------------------------------- */ + +/* calculate geometry, build risc code */ +int +bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) +{ + const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + dprintk("%d: buffer field: %s format: %s size: %dx%d\n", + btv->c.nr, v4l2_field_names[buf->vb.field], + buf->fmt->name, buf->vb.width, buf->vb.height); + + /* packed pixel modes */ + if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { + int bpl = (buf->fmt->depth >> 3) * buf->vb.width; + int bpf = bpl * (buf->vb.height >> 1); + + bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, + V4L2_FIELD_HAS_BOTH(buf->vb.field), + tvnorm,&buf->crop); + + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_risc_packed(btv,&buf->top,dma->sglist, + /* offset */ 0,bpl, + /* padding */ 0,/* skip_lines */ 0, + buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + 0,bpl,0,0,buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + bttv_risc_packed(btv,&buf->top,dma->sglist, + 0,bpl,bpl,0,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + bpl,bpl,bpl,0,buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + bttv_risc_packed(btv,&buf->top,dma->sglist, + 0,bpl,0,0,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,dma->sglist, + bpf,bpl,0,0,buf->vb.height >> 1); + break; + default: + BUG(); + } + } + + /* planar modes */ + if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { + int uoffset, voffset; + int ypadding, cpadding, lines; + + /* calculate chroma offsets */ + uoffset = buf->vb.width * buf->vb.height; + voffset = buf->vb.width * buf->vb.height; + if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { + /* Y-Cr-Cb plane order */ + uoffset >>= buf->fmt->hshift; + uoffset >>= buf->fmt->vshift; + uoffset += voffset; + } else { + /* Y-Cb-Cr plane order */ + voffset >>= buf->fmt->hshift; + voffset >>= buf->fmt->vshift; + voffset += uoffset; + } + + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,/* both_fields */ 0, + tvnorm,&buf->crop); + bttv_risc_planar(btv, &buf->top, dma->sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_BOTTOM: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,0, + tvnorm,&buf->crop); + bttv_risc_planar(btv, &buf->bottom, dma->sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_INTERLACED: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,1, + tvnorm,&buf->crop); + lines = buf->vb.height >> 1; + ypadding = buf->vb.width; + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, + dma->sglist, + 0,buf->vb.width,ypadding,lines, + uoffset,voffset, + buf->fmt->hshift, + buf->fmt->vshift, + cpadding); + bttv_risc_planar(btv,&buf->bottom, + dma->sglist, + ypadding,buf->vb.width,ypadding,lines, + uoffset+cpadding, + voffset+cpadding, + buf->fmt->hshift, + buf->fmt->vshift, + cpadding); + break; + case V4L2_FIELD_SEQ_TB: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,1, + tvnorm,&buf->crop); + lines = buf->vb.height >> 1; + ypadding = buf->vb.width; + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, + 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, + 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(); + } + } + + /* raw data */ + if (buf->fmt->flags & FORMAT_FLAGS_RAW) { + /* build risc code */ + buf->vb.field = V4L2_FIELD_SEQ_TB; + bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, + 1,tvnorm,&buf->crop); + bttv_risc_packed(btv, &buf->top, dma->sglist, + /* offset */ 0, RAW_BPL, /* padding */ 0, + /* skip_lines */ 0, RAW_LINES); + bttv_risc_packed(btv, &buf->bottom, dma->sglist, + buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); + } + + /* copy format info */ + buf->btformat = buf->fmt->btformat; + buf->btswap = buf->fmt->btswap; + return 0; +} + +/* ---------------------------------------------------------- */ + +/* calculate geometry, build risc code */ +int +bttv_overlay_risc(struct bttv *btv, + struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf) +{ + /* check interleave, bottom+top fields */ + dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", + btv->c.nr, v4l2_field_names[buf->vb.field], + fmt->name, ov->w.width, ov->w.height); + + /* calculate geometry */ + bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, + V4L2_FIELD_HAS_BOTH(ov->field), + &bttv_tvnorms[ov->tvnorm],&buf->crop); + + /* build risc code */ + switch (ov->field) { + case V4L2_FIELD_TOP: + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); + break; + case V4L2_FIELD_INTERLACED: + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); + break; + default: + BUG(); + } + + /* copy format info */ + buf->btformat = fmt->btformat; + buf->btswap = fmt->btswap; + buf->vb.field = ov->field; + return 0; +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c new file mode 100644 index 000000000000..b433267d9aa9 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -0,0 +1,459 @@ +/* + + bttv - Bt848 frame grabber driver + vbi interface + + (c) 2002 Gerd Knorr + + Copyright (C) 2005, 2006 Michael H. Schimek + Sponsored by OPQ Systems AB + + 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bttvp.h" + +/* Offset from line sync pulse leading edge (0H) to start of VBI capture, + in fCLKx2 pixels. According to the datasheet, VBI capture starts + VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET + is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be + (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is + Just Plain Wrong. The real value appears to be different for + different revisions of the bt8x8 chips, and to be affected by the + horizontal scaling factor. Experimentally, the value is measured + to be about 244. */ +#define VBI_OFFSET 244 + +/* 2048 for compatibility with earlier driver versions. The driver + really stores 1024 + tvnorm->vbipack * 4 samples per line in the + buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI + is 0x1FF DWORDs) and VBI read()s store a frame counter in the last + four bytes of the VBI image. */ +#define VBI_BPL 2048 + +/* Compatibility. */ +#define VBI_DEFLINES 16 + +static unsigned int vbibufs = 4; +static unsigned int vbi_debug; + +module_param(vbibufs, int, 0444); +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4"); +MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); + +#ifdef dprintk +# undef dprintk +#endif +#define dprintk(fmt, ...) \ +do { \ + if (vbi_debug) \ + pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__); \ +} while (0) + +#define IMAGE_SIZE(fmt) \ + (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) + +/* ----------------------------------------------------------------------- */ +/* vbi risc code + mm */ + +static int vbi_buffer_setup(struct videobuf_queue *q, + unsigned int *count, unsigned int *size) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + + if (0 == *count) + *count = vbibufs; + + *size = IMAGE_SIZE(&fh->vbi_fmt.fmt); + + dprintk("setup: samples=%u start=%d,%d count=%u,%u\n", + fh->vbi_fmt.fmt.samples_per_line, + fh->vbi_fmt.fmt.start[0], + fh->vbi_fmt.fmt.start[1], + fh->vbi_fmt.fmt.count[0], + fh->vbi_fmt.fmt.count[1]); + + return 0; +} + +static int vbi_buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + const struct bttv_tvnorm *tvnorm; + unsigned int skip_lines0, skip_lines1, min_vdelay; + int redo_dma_risc; + int rc; + + buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + tvnorm = fh->vbi_fmt.tvnorm; + + /* There's no VBI_VDELAY register, RISC must skip the lines + we don't want. With default parameters we skip zero lines + as earlier driver versions did. The driver permits video + standard changes while capturing, so we use vbi_fmt.tvnorm + instead of btv->tvnorm to skip zero lines after video + standard changes as well. */ + + skip_lines0 = 0; + skip_lines1 = 0; + + if (fh->vbi_fmt.fmt.count[0] > 0) + skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0] + - tvnorm->vbistart[0])); + if (fh->vbi_fmt.fmt.count[1] > 0) + skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1] + - tvnorm->vbistart[1])); + + redo_dma_risc = 0; + + if (buf->vbi_skip[0] != skip_lines0 || + buf->vbi_skip[1] != skip_lines1 || + buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] || + buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) { + buf->vbi_skip[0] = skip_lines0; + buf->vbi_skip[1] = skip_lines1; + buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0]; + buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1]; + redo_dma_risc = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + redo_dma_risc = 1; + if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) + goto fail; + } + + if (redo_dma_risc) { + unsigned int bpl, padding, offset; + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + + bpl = 2044; /* max. vbipack */ + padding = VBI_BPL - bpl; + + if (fh->vbi_fmt.fmt.count[0] > 0) { + rc = bttv_risc_packed(btv, &buf->top, + dma->sglist, + /* offset */ 0, bpl, + padding, skip_lines0, + fh->vbi_fmt.fmt.count[0]); + if (0 != rc) + goto fail; + } + + if (fh->vbi_fmt.fmt.count[1] > 0) { + offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; + + rc = bttv_risc_packed(btv, &buf->bottom, + dma->sglist, + offset, bpl, + padding, skip_lines1, + fh->vbi_fmt.fmt.count[1]); + if (0 != rc) + goto fail; + } + } + + /* VBI capturing ends at VDELAY, start of video capturing, + no matter where the RISC program ends. VDELAY minimum is 2, + bounds.top is the corresponding first field line number + times two. VDELAY counts half field lines. */ + min_vdelay = MIN_VDELAY; + if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top) + min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top; + + /* For bttv_buffer_activate_vbi(). */ + buf->geo.vdelay = min_vdelay; + + buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.field = field; + dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", + vb, &buf->top, &buf->bottom, + v4l2_field_names[buf->vb.field]); + return 0; + + fail: + bttv_dma_free(q,btv,buf); + return rc; +} + +static void +vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + + dprintk("queue %p\n",vb); + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue,&btv->vcapture); + if (NULL == btv->cvbi) { + fh->btv->loop_irq |= 4; + bttv_set_dma(btv,0x0c); + } +} + +static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct bttv_fh *fh = q->priv_data; + struct bttv *btv = fh->btv; + struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); + + dprintk("free %p\n",vb); + bttv_dma_free(q,fh->btv,buf); +} + +struct videobuf_queue_ops bttv_vbi_qops = { + .buf_setup = vbi_buffer_setup, + .buf_prepare = vbi_buffer_prepare, + .buf_queue = vbi_buffer_queue, + .buf_release = vbi_buffer_release, +}; + +/* ----------------------------------------------------------------------- */ + +static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, + __s32 crop_start) +{ + __s32 min_start, max_start, max_end, f2_offset; + unsigned int i; + + /* For compatibility with earlier driver versions we must pretend + the VBI and video capture window may overlap. In reality RISC + magic aborts VBI capturing at the first line of video capturing, + leaving the rest of the buffer unchanged, usually all zero. + VBI capturing must always start before video capturing. >> 1 + because cropping counts field lines times two. */ + min_start = tvnorm->vbistart[0]; + max_start = (crop_start >> 1) - 1; + max_end = (tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height) >> 1; + + if (min_start > max_start) + return -EBUSY; + + BUG_ON(max_start >= max_end); + + f->sampling_rate = tvnorm->Fsc; + f->samples_per_line = VBI_BPL; + f->sample_format = V4L2_PIX_FMT_GREY; + f->offset = VBI_OFFSET; + + f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0]; + + for (i = 0; i < 2; ++i) { + if (0 == f->count[i]) { + /* No data from this field. We leave f->start[i] + alone because VIDIOCSVBIFMT is w/o and EINVALs + when a driver does not support exactly the + requested parameters. */ + } else { + s64 start, count; + + start = clamp(f->start[i], min_start, max_start); + /* s64 to prevent overflow. */ + count = (s64) f->start[i] + f->count[i] - start; + f->start[i] = start; + f->count[i] = clamp(count, (s64) 1, + max_end - start); + } + + min_start += f2_offset; + max_start += f2_offset; + max_end += f2_offset; + } + + if (0 == (f->count[0] | f->count[1])) { + /* As in earlier driver versions. */ + f->start[0] = tvnorm->vbistart[0]; + f->start[1] = tvnorm->vbistart[1]; + f->count[0] = 1; + f->count[1] = 1; + } + + f->flags = 0; + + f->reserved[0] = 0; + f->reserved[1] = 0; + + return 0; +} + +int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_tvnorm *tvnorm; + __s32 crop_start; + + mutex_lock(&btv->lock); + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + crop_start = btv->crop_start; + + mutex_unlock(&btv->lock); + + return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); +} + + +int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_tvnorm *tvnorm; + __s32 start1, end; + int rc; + + mutex_lock(&btv->lock); + + rc = -EBUSY; + if (fh->resources & RESOURCE_VBI) + goto fail; + + tvnorm = &bttv_tvnorms[btv->tvnorm]; + + rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); + if (0 != rc) + goto fail; + + start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + + tvnorm->vbistart[0]; + + /* First possible line of video capturing. Should be + max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 + when capturing both fields. But for compatibility we must + pretend the VBI and video capture window may overlap, + so end = start + 1, the lowest possible value, times two + because vbi_fmt.end counts field lines times two. */ + end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; + + mutex_lock(&fh->vbi.vb_lock); + + fh->vbi_fmt.fmt = frt->fmt.vbi; + fh->vbi_fmt.tvnorm = tvnorm; + fh->vbi_fmt.end = end; + + mutex_unlock(&fh->vbi.vb_lock); + + rc = 0; + + fail: + mutex_unlock(&btv->lock); + + return rc; +} + + +int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +{ + struct bttv_fh *fh = f; + const struct bttv_tvnorm *tvnorm; + + frt->fmt.vbi = fh->vbi_fmt.fmt; + + tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; + + if (tvnorm != fh->vbi_fmt.tvnorm) { + __s32 max_end; + unsigned int i; + + /* As in vbi_buffer_prepare() this imitates the + behaviour of earlier driver versions after video + standard changes, with default parameters anyway. */ + + max_end = (tvnorm->cropcap.bounds.top + + tvnorm->cropcap.bounds.height) >> 1; + + frt->fmt.vbi.sampling_rate = tvnorm->Fsc; + + for (i = 0; i < 2; ++i) { + __s32 new_start; + + new_start = frt->fmt.vbi.start[i] + + tvnorm->vbistart[i] + - fh->vbi_fmt.tvnorm->vbistart[i]; + + frt->fmt.vbi.start[i] = min(new_start, max_end - 1); + frt->fmt.vbi.count[i] = + min((__s32) frt->fmt.vbi.count[i], + max_end - frt->fmt.vbi.start[i]); + + max_end += tvnorm->vbistart[1] + - tvnorm->vbistart[0]; + } + } + return 0; +} + +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) +{ + const struct bttv_tvnorm *tvnorm; + unsigned int real_samples_per_line; + unsigned int real_count; + + tvnorm = &bttv_tvnorms[norm]; + + f->fmt.sampling_rate = tvnorm->Fsc; + f->fmt.samples_per_line = VBI_BPL; + f->fmt.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.offset = VBI_OFFSET; + f->fmt.start[0] = tvnorm->vbistart[0]; + f->fmt.start[1] = tvnorm->vbistart[1]; + f->fmt.count[0] = VBI_DEFLINES; + f->fmt.count[1] = VBI_DEFLINES; + f->fmt.flags = 0; + f->fmt.reserved[0] = 0; + f->fmt.reserved[1] = 0; + + /* For compatibility the buffer size must be 2 * VBI_DEFLINES * + VBI_BPL regardless of the current video standard. */ + real_samples_per_line = 1024 + tvnorm->vbipack * 4; + real_count = ((tvnorm->cropcap.defrect.top >> 1) + - tvnorm->vbistart[0]); + + BUG_ON(real_samples_per_line > VBI_BPL); + BUG_ON(real_count > VBI_DEFLINES); + + f->tvnorm = tvnorm; + + /* See bttv_vbi_fmt_set(). */ + f->end = tvnorm->vbistart[0] * 2 + 2; +} + +/* ----------------------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h new file mode 100644 index 000000000000..79a11240a590 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttv.h @@ -0,0 +1,376 @@ +/* + * + * bttv - Bt848 frame grabber driver + * + * card ID's and external interfaces of the bttv driver + * basically stuff needed by other drivers (i2c, lirc, ...) + * and is supported not to change much over time. + * + * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr + * + */ + +#ifndef _BTTV_H_ +#define _BTTV_H_ + +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------- */ +/* exported by bttv-cards.c */ + +#define BTTV_BOARD_UNKNOWN 0x00 +#define BTTV_BOARD_MIRO 0x01 +#define BTTV_BOARD_HAUPPAUGE 0x02 +#define BTTV_BOARD_STB 0x03 +#define BTTV_BOARD_INTEL 0x04 +#define BTTV_BOARD_DIAMOND 0x05 +#define BTTV_BOARD_AVERMEDIA 0x06 +#define BTTV_BOARD_MATRIX_VISION 0x07 +#define BTTV_BOARD_FLYVIDEO 0x08 +#define BTTV_BOARD_TURBOTV 0x09 +#define BTTV_BOARD_HAUPPAUGE878 0x0a +#define BTTV_BOARD_MIROPRO 0x0b +#define BTTV_BOARD_ADSTECH_TV 0x0c +#define BTTV_BOARD_AVERMEDIA98 0x0d +#define BTTV_BOARD_VHX 0x0e +#define BTTV_BOARD_ZOLTRIX 0x0f +#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 +#define BTTV_BOARD_WINVIEW_601 0x11 +#define BTTV_BOARD_AVEC_INTERCAP 0x12 +#define BTTV_BOARD_LIFE_FLYKIT 0x13 +#define BTTV_BOARD_CEI_RAFFLES 0x14 +#define BTTV_BOARD_CONFERENCETV 0x15 +#define BTTV_BOARD_PHOEBE_TVMAS 0x16 +#define BTTV_BOARD_MODTEC_205 0x17 +#define BTTV_BOARD_MAGICTVIEW061 0x18 +#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 +#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a +#define BTTV_BOARD_MAXI 0x1b +#define BTTV_BOARD_TERRATV 0x1c +#define BTTV_BOARD_PXC200 0x1d +#define BTTV_BOARD_FLYVIDEO_98 0x1e +#define BTTV_BOARD_IPROTV 0x1f +#define BTTV_BOARD_INTEL_C_S_PCI 0x20 +#define BTTV_BOARD_TERRATVALUE 0x21 +#define BTTV_BOARD_WINFAST2000 0x22 +#define BTTV_BOARD_CHRONOS_VS2 0x23 +#define BTTV_BOARD_TYPHOON_TVIEW 0x24 +#define BTTV_BOARD_PXELVWPLTVPRO 0x25 +#define BTTV_BOARD_MAGICTVIEW063 0x26 +#define BTTV_BOARD_PINNACLE 0x27 +#define BTTV_BOARD_STB2 0x28 +#define BTTV_BOARD_AVPHONE98 0x29 +#define BTTV_BOARD_PV951 0x2a +#define BTTV_BOARD_ONAIR_TV 0x2b +#define BTTV_BOARD_SIGMA_TVII_FM 0x2c +#define BTTV_BOARD_MATRIX_VISION2 0x2d +#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e +#define BTTV_BOARD_TERRATVRADIO 0x2f +#define BTTV_BOARD_DYNALINK 0x30 +#define BTTV_BOARD_GVBCTV3PCI 0x31 +#define BTTV_BOARD_PXELVWPLTVPAK 0x32 +#define BTTV_BOARD_EAGLE 0x33 +#define BTTV_BOARD_PINNACLEPRO 0x34 +#define BTTV_BOARD_TVIEW_RDS_FM 0x35 +#define BTTV_BOARD_LIFETEC_9415 0x36 +#define BTTV_BOARD_BESTBUY_EASYTV 0x37 +#define BTTV_BOARD_FLYVIDEO_98FM 0x38 +#define BTTV_BOARD_GRANDTEC 0x39 +#define BTTV_BOARD_ASKEY_CPH060 0x3a +#define BTTV_BOARD_ASKEY_CPH03X 0x3b +#define BTTV_BOARD_MM100PCTV 0x3c +#define BTTV_BOARD_GMV1 0x3d +#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e +#define BTTV_BOARD_ATI_TVWONDER 0x3f +#define BTTV_BOARD_ATI_TVWONDERVE 0x40 +#define BTTV_BOARD_FLYVIDEO2000 0x41 +#define BTTV_BOARD_TERRATVALUER 0x42 +#define BTTV_BOARD_GVBCTV4PCI 0x43 +#define BTTV_BOARD_VOODOOTV_FM 0x44 +#define BTTV_BOARD_AIMMS 0x45 +#define BTTV_BOARD_PV_BT878P_PLUS 0x46 +#define BTTV_BOARD_FLYVIDEO98EZ 0x47 +#define BTTV_BOARD_PV_BT878P_9B 0x48 +#define BTTV_BOARD_SENSORAY311_611 0x49 +#define BTTV_BOARD_RV605 0x4a +#define BTTV_BOARD_POWERCLR_MTV878 0x4b +#define BTTV_BOARD_WINDVR 0x4c +#define BTTV_BOARD_GRANDTEC_MULTI 0x4d +#define BTTV_BOARD_KWORLD 0x4e +#define BTTV_BOARD_DSP_TCVIDEO 0x4f +#define BTTV_BOARD_HAUPPAUGEPVR 0x50 +#define BTTV_BOARD_GVBCTV5PCI 0x51 +#define BTTV_BOARD_OSPREY1x0 0x52 +#define BTTV_BOARD_OSPREY1x0_848 0x53 +#define BTTV_BOARD_OSPREY101_848 0x54 +#define BTTV_BOARD_OSPREY1x1 0x55 +#define BTTV_BOARD_OSPREY1x1_SVID 0x56 +#define BTTV_BOARD_OSPREY2xx 0x57 +#define BTTV_BOARD_OSPREY2x0_SVID 0x58 +#define BTTV_BOARD_OSPREY2x0 0x59 +#define BTTV_BOARD_OSPREY500 0x5a +#define BTTV_BOARD_OSPREY540 0x5b +#define BTTV_BOARD_OSPREY2000 0x5c +#define BTTV_BOARD_IDS_EAGLE 0x5d +#define BTTV_BOARD_PINNACLESAT 0x5e +#define BTTV_BOARD_FORMAC_PROTV 0x5f +#define BTTV_BOARD_MACHTV 0x60 +#define BTTV_BOARD_EURESYS_PICOLO 0x61 +#define BTTV_BOARD_PV150 0x62 +#define BTTV_BOARD_AD_TVK503 0x63 +#define BTTV_BOARD_HERCULES_SM_TV 0x64 +#define BTTV_BOARD_PACETV 0x65 +#define BTTV_BOARD_IVC200 0x66 +#define BTTV_BOARD_XGUARD 0x67 +#define BTTV_BOARD_NEBULA_DIGITV 0x68 +#define BTTV_BOARD_PV143 0x69 +#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a +#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b +#define BTTV_BOARD_VD009_MINIDIN 0x6c +#define BTTV_BOARD_VD009_COMBI 0x6d +#define BTTV_BOARD_IVC100 0x6e +#define BTTV_BOARD_IVC120 0x6f +#define BTTV_BOARD_PC_HDTV 0x70 +#define BTTV_BOARD_TWINHAN_DST 0x71 +#define BTTV_BOARD_WINFASTVC100 0x72 +#define BTTV_BOARD_TEV560 0x73 +#define BTTV_BOARD_SIMUS_GVC1100 0x74 +#define BTTV_BOARD_NGSTV_PLUS 0x75 +#define BTTV_BOARD_LMLBT4 0x76 +#define BTTV_BOARD_TEKRAM_M205 0x77 +#define BTTV_BOARD_CONTVFMI 0x78 +#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 +#define BTTV_BOARD_SPIRIT_TV 0x7a +#define BTTV_BOARD_AVDVBT_771 0x7b +#define BTTV_BOARD_AVDVBT_761 0x7c +#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d +#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e +#define BTTV_BOARD_APAC_VIEWCOMP 0x7f +#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 +#define BTTV_BOARD_VGEAR_MYVCD 0x81 +#define BTTV_BOARD_SUPER_TV 0x82 +#define BTTV_BOARD_TIBET_CS16 0x83 +#define BTTV_BOARD_KODICOM_4400R 0x84 +#define BTTV_BOARD_KODICOM_4400R_SL 0x85 +#define BTTV_BOARD_ADLINK_RTV24 0x86 +#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +#define BTTV_BOARD_ACORP_Y878F 0x88 +#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 +#define BTTV_BOARD_PV_BT878P_2E 0x8a +#define BTTV_BOARD_PV_M4900 0x8b +#define BTTV_BOARD_OSPREY440 0x8c +#define BTTV_BOARD_ASOUND_SKYEYE 0x8d +#define BTTV_BOARD_SABRENT_TVFM 0x8e +#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f +#define BTTV_BOARD_MACHTV_MAGICTV 0x90 +#define BTTV_BOARD_SSAI_SECURITY 0x91 +#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 +#define BTTV_BOARD_VOODOOTV_200 0x93 +#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 +#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 +#define BTTV_BOARD_GEOVISION_GV600 0x96 +#define BTTV_BOARD_KOZUMI_KTV_01C 0x97 +#define BTTV_BOARD_ENLTV_FM_2 0x98 +#define BTTV_BOARD_VD012 0x99 +#define BTTV_BOARD_VD012_X1 0x9a +#define BTTV_BOARD_VD012_X2 0x9b +#define BTTV_BOARD_IVCE8784 0x9c +#define BTTV_BOARD_GEOVISION_GV800S 0x9d +#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e +#define BTTV_BOARD_PV183 0x9f +#define BTTV_BOARD_TVT_TD3116 0xa0 +#define BTTV_BOARD_APOSONIC_WDVR 0xa1 + +/* more card-specific defines */ +#define PT2254_L_CHANNEL 0x10 +#define PT2254_R_CHANNEL 0x08 +#define PT2254_DBS_IN_2 0x400 +#define PT2254_DBS_IN_10 0x20000 +#define WINVIEW_PT2254_CLK 0x40 +#define WINVIEW_PT2254_DATA 0x20 +#define WINVIEW_PT2254_STROBE 0x80 + +struct bttv_core { + /* device structs */ + struct v4l2_device v4l2_dev; + struct pci_dev *pci; + struct i2c_adapter i2c_adap; + struct list_head subs; /* struct bttv_sub_device */ + + /* device config */ + unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ + unsigned int type; /* card type (pointer into tvcards[]) */ +}; + +struct bttv; + +struct tvcard { + char *name; + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); + + /* MUX bits for each input, two bits per input starting with the LSB */ + u32 muxsel; /* Use MUXSEL() to set */ + + u32 gpiomask; + u32 gpiomux[4]; /* Tuner, Radio, external, internal */ + u32 gpiomute; /* GPIO mute setting */ + u32 gpiomask2; /* GPIO MUX mask */ + + unsigned int tuner_type; + u8 tuner_addr; + u8 video_inputs; /* Number of inputs */ + unsigned int svhs:4; /* Which input is s-video */ +#define NO_SVHS 15 + unsigned int pll:2; +#define PLL_NONE 0 +#define PLL_28 1 +#define PLL_35 2 + + /* i2c audio flags */ + unsigned int no_msp34xx:1; + unsigned int no_tda7432:1; + unsigned int msp34xx_alt:1; + /* Note: currently no card definition needs to mark the presence + of a RDS saa6588 chip. If this is ever needed, then add a new + 'has_saa6588' bit here. */ + + unsigned int no_video:1; /* video pci function is unused */ + unsigned int has_dvb:1; + unsigned int has_remote:1; + unsigned int has_radio:1; + unsigned int has_dig_in:1; /* Has digital input (always last input) */ + unsigned int no_gpioirq:1; +}; + +extern struct tvcard bttv_tvcards[]; + +/* + * This bit of cpp voodoo is used to create a macro with a variable number of + * arguments (1 to 16). It will pack each argument into a word two bits at a + * time. It can't be a function because it needs to be compile time constant to + * initialize structures. Since each argument must fit in two bits, it's ok + * that they are changed to octal. One should not use hex number, macros, or + * anything else with this macro. Just use plain integers from 0 to 3. + */ +#define _MUXSELf(a) 0##a << 30 +#define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) +#define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) +#define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) +#define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) +#define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) +#define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) +#define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) +#define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) +#define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) +#define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) +#define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) +#define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) +#define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) +#define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) +#define MUXSEL(a, b...) (a | _MUXSEL1(b)) + +/* identification / initialization of the card */ +extern void bttv_idcard(struct bttv *btv); +extern void bttv_init_card1(struct bttv *btv); +extern void bttv_init_card2(struct bttv *btv); +extern void bttv_init_tuner(struct bttv *btv); + +/* card-specific funtions */ +extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); +extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); + +/* extra tweaks for some chipsets */ +extern void bttv_check_chipset(void); +extern int bttv_handle_chipset(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* exported by bttv-if.c */ + +/* this obsolete -- please use the sysfs-based + interface below for new code */ + +extern struct pci_dev* bttv_get_pcidev(unsigned int card); + +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error occurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error occurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error occurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + + + + +/* ---------------------------------------------------------- */ +/* sysfs/driver-moded based gpio access interface */ + +struct bttv_sub_device { + struct device dev; + struct bttv_core *core; + struct list_head list; +}; +#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) + +struct bttv_sub_driver { + struct device_driver drv; + char wanted[20]; + int (*probe)(struct bttv_sub_device *sub); + void (*remove)(struct bttv_sub_device *sub); +}; +#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) + +int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); +int bttv_sub_unregister(struct bttv_sub_driver *drv); + +/* gpio access functions */ +void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); +u32 bttv_gpio_read(struct bttv_core *core); +void bttv_gpio_write(struct bttv_core *core, u32 value); +void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); + +#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) +#define gpio_read() bttv_gpio_read(&btv->c) +#define gpio_write(value) bttv_gpio_write(&btv->c, value) +#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) + + +/* ---------------------------------------------------------- */ +/* i2c */ + +#define bttv_call_all(btv, o, f, args...) \ + v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args) + +extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); +extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both); +extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); + +extern int bttv_input_init(struct bttv *dev); +extern void bttv_input_fini(struct bttv *dev); +extern void bttv_input_irq(struct bttv *dev); + +#endif /* _BTTV_H_ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h new file mode 100644 index 000000000000..70fd4f23f605 --- /dev/null +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -0,0 +1,535 @@ +/* + + bttv - Bt848 frame grabber driver + + bttv's *private* header file -- nobody other than bttv itself + should ever include this file. + + (c) 2000-2002 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. +*/ + +#ifndef _BTTVP_H_ +#define _BTTVP_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bt848.h" +#include "bttv.h" +#include "btcx-risc.h" + +#ifdef __KERNEL__ + +#define FORMAT_FLAGS_DITHER 0x01 +#define FORMAT_FLAGS_PACKED 0x02 +#define FORMAT_FLAGS_PLANAR 0x04 +#define FORMAT_FLAGS_RAW 0x08 +#define FORMAT_FLAGS_CrCb 0x10 + +#define RISC_SLOT_O_VBI 4 +#define RISC_SLOT_O_FIELD 6 +#define RISC_SLOT_E_VBI 10 +#define RISC_SLOT_E_FIELD 12 +#define RISC_SLOT_LOOP 14 + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO_STREAM 2 +#define RESOURCE_VBI 4 +#define RESOURCE_VIDEO_READ 8 + +#define RAW_LINES 640 +#define RAW_BPL 1024 + +#define UNSET (-1U) + +/* Min. value in VDELAY register. */ +#define MIN_VDELAY 2 +/* Even to get Cb first, odd for Cr. */ +#define MAX_HDELAY (0x3FF & -2) +/* Limits scaled width, which must be a multiple of 4. */ +#define MAX_HACTIVE (0x3FF & -4) + +#define BTTV_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) +/* ---------------------------------------------------------- */ + +struct bttv_tvnorm { + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + u16 vtotal; + int sram; + /* ITU-R frame line number of the first VBI line we can + capture, of the first and second field. The last possible line + is determined by cropcap.bounds. */ + u16 vbistart[2]; + /* Horizontally this counts fCLKx1 samples following the leading + edge of the horizontal sync pulse, vertically ITU-R frame line + numbers of the first field times two (2, 4, 6, ... 524 or 624). */ + struct v4l2_cropcap cropcap; +}; +extern const struct bttv_tvnorm bttv_tvnorms[]; + +struct bttv_format { + char *name; + int fourcc; /* video4linux 2 */ + int btformat; /* BT848_COLOR_FMT_* */ + int btswap; /* BT848_COLOR_CTL_* */ + int depth; /* bit/pixel */ + int flags; + int hshift,vshift; /* for planar modes */ +}; + +struct bttv_ir { + struct rc_dev *dev; + struct timer_list timer; + + char name[32]; + char phys[32]; + + /* Usual gpio signalling */ + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + u32 polling; + u32 last_gpio; + int shift_by; + int start; // What should RC5_START() be + int addr; // What RC5_ADDR() should be. + int rc5_remote_gap; + + /* RC5 gpio */ + bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */ + u32 last_bit; /* last raw bit seen */ + u32 code; /* raw code under construction */ + struct timeval base_time; /* time of last seen code */ + bool active; /* building raw code */ +}; + + +/* ---------------------------------------------------------- */ + +struct bttv_geometry { + u8 vtc,crop,comb; + u16 width,hscale,hdelay; + u16 sheight,vscale,vdelay,vtotal; +}; + +struct bttv_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* bttv specific */ + const struct bttv_format *fmt; + unsigned int tvnorm; + int btformat; + int btswap; + struct bttv_geometry geo; + struct btcx_riscmem top; + struct btcx_riscmem bottom; + struct v4l2_rect crop; + unsigned int vbi_skip[2]; + unsigned int vbi_count[2]; +}; + +struct bttv_buffer_set { + struct bttv_buffer *top; /* top field buffer */ + struct bttv_buffer *bottom; /* bottom field buffer */ + unsigned int top_irq; + unsigned int frame_irq; +}; + +struct bttv_overlay { + unsigned int tvnorm; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; + int nclips; + int setup_ok; +}; + +struct bttv_vbi_fmt { + struct v4l2_vbi_format fmt; + + /* fmt.start[] and count[] refer to this video standard. */ + const struct bttv_tvnorm *tvnorm; + + /* Earliest possible start of video capturing with this + v4l2_vbi_format, in struct bttv_crop.rect units. */ + __s32 end; +}; + +/* bttv-vbi.c */ +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); + +struct bttv_crop { + /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ + struct v4l2_rect rect; + + /* Scaled image size limits with this crop rect. Divide + max_height, but not min_height, by two when capturing + single fields. See also bttv_crop_reset() and + bttv_crop_adjust() in bttv-driver.c. */ + __s32 min_scaled_width; + __s32 min_scaled_height; + __s32 max_scaled_width; + __s32 max_scaled_height; +}; + +struct bttv_fh { + struct bttv *btv; + int resources; +#ifdef VIDIOC_G_PRIORITY + enum v4l2_priority prio; +#endif + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + const struct bttv_format *fmt; + int width; + int height; + + /* video overlay */ + const struct bttv_format *ovfmt; + struct bttv_overlay ov; + + /* Application called VIDIOC_S_CROP. */ + int do_crop; + + /* vbi capture */ + struct videobuf_queue vbi; + /* Current VBI capture window as seen through this fh (cannot + be global for compatibility with earlier drivers). Protected + by struct bttv.lock and struct bttv_fh.vbi.lock. */ + struct bttv_vbi_fmt vbi_fmt; +}; + +/* ---------------------------------------------------------- */ +/* bttv-risc.c */ + +/* risc code generators - capture */ +int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int offset, unsigned int bpl, + unsigned int pitch, unsigned int skip_lines, + unsigned int store_lines); + +/* control dma register + risc main loop */ +void bttv_set_dma(struct bttv *btv, int override); +int bttv_risc_init_main(struct bttv *btv); +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_video(struct bttv *btv, + struct bttv_buffer_set *set); +int bttv_buffer_activate_vbi(struct bttv *btv, + struct bttv_buffer *vbi); +void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, + struct bttv_buffer *buf); + +/* overlay handling */ +int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, + const struct bttv_format *fmt, + struct bttv_buffer *buf); + + +/* ---------------------------------------------------------- */ +/* bttv-vbi.c */ + +int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); +int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); + +extern struct videobuf_queue_ops bttv_vbi_qops; + +/* ---------------------------------------------------------- */ +/* bttv-gpio.c */ + +extern struct bus_type bttv_sub_bus_type; +int bttv_sub_add_device(struct bttv_core *core, char *name); +int bttv_sub_del_devices(struct bttv_core *core); + +/* ---------------------------------------------------------- */ +/* bttv-cards.c */ + +extern int no_overlay; + +/* ---------------------------------------------------------- */ +/* bttv-input.c */ + +extern void init_bttv_i2c_ir(struct bttv *btv); +extern int fini_bttv_i2c(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* bttv-driver.c */ + +/* insmod options */ +extern unsigned int bttv_verbose; +extern unsigned int bttv_debug; +extern unsigned int bttv_gpio; +extern void bttv_gpio_tracking(struct bttv *btv, char *comment); +extern int init_bttv_i2c(struct bttv *btv); + +#define dprintk(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_debug(fmt, ##__VA_ARGS__); \ +} while (0) +#define dprintk_cont(fmt, ...) \ +do { \ + if (bttv_debug >= 1) \ + pr_cont(fmt, ##__VA_ARGS__); \ +} while (0) +#define d2printk(fmt, ...) \ +do { \ + if (bttv_debug >= 2) \ + printk(fmt, ##__VA_ARGS__); \ +} while (0) + +#define BTTV_MAX_FBUF 0x208000 +#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ +#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ + + +struct bttv_pll_info { + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_crystal; /* Crystal used for input */ + unsigned int pll_current; /* Currently programmed ofreq */ +}; + +/* for gpio-connected remote control */ +struct bttv_input { + struct input_dev *dev; + char name[32]; + char phys[32]; + u32 mask_keycode; + u32 mask_keydown; +}; + +struct bttv_suspend_state { + u32 gpio_enable; + u32 gpio_data; + int disabled; + int loop_irq; + struct bttv_buffer_set video; + struct bttv_buffer *vbi; +}; + +struct bttv { + struct bttv_core c; + + /* pci device config */ + unsigned short id; + unsigned char revision; + unsigned char __iomem *bt848_mmio; /* pointer to mmio */ + + /* card configuration info */ + unsigned int cardid; /* pci subsystem id (bt878 based ones) */ + unsigned int tuner_type; /* tuner chip type */ + unsigned int tda9887_conf; + unsigned int svhs, dig; + unsigned int has_saa6588:1; + struct bttv_pll_info pll; + int triton1; + int gpioirq; + + int use_i2c_hw; + + /* old gpio interface */ + int shutdown; + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + + /* new gpio interface */ + spinlock_t gpio_lock; + + /* i2c layer */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_rc; + int i2c_done; + wait_queue_head_t i2c_queue; + struct v4l2_subdev *sd_msp34xx; + struct v4l2_subdev *sd_tvaudio; + + /* video4linux (1) */ + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + + /* infrared remote */ + int has_remote; + struct bttv_ir *remote; + + /* I2C remote data */ + struct IR_i2c_init_data init_data; + + /* locking */ + spinlock_t s_lock; + struct mutex lock; + int resources; +#ifdef VIDIOC_G_PRIORITY + struct v4l2_prio_state prio; +#endif + + /* video state */ + unsigned int input; + unsigned int audio; + unsigned int mute; + unsigned long freq; + unsigned int tvnorm; + int hue, contrast, bright, saturation; + struct v4l2_framebuffer fbuf; + unsigned int field_count; + + /* various options */ + int opt_combfilter; + int opt_lumafilter; + int opt_automute; + int opt_chroma_agc; + int opt_adc_crush; + int opt_vcr_hack; + int opt_whitecrush_upper; + int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; + + /* radio data/state */ + int has_radio; + int radio_user; + int radio_uses_msp_demodulator; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ + int has_matchbox; + int mbox_we; + int mbox_data; + int mbox_clk; + int mbox_most; + int mbox_mask; + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + + /* risc memory management data + - must acquire s_lock before changing these + - 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 */ + struct bttv_buffer *cvbi; /* active vbi buffer */ + int loop_irq; + int new_input; + + unsigned long cap_ctl; + unsigned long dma_on; + struct timer_list timeout; + struct bttv_suspend_state state; + + /* stats */ + unsigned int errors; + unsigned int framedrop; + unsigned int irq_total; + unsigned int irq_me; + + unsigned int users; + struct bttv_fh init; + + /* used to make dvb-bt8xx autoloadable */ + struct work_struct request_module_wk; + + /* Default (0) and current (1) video capturing and overlay + cropping parameters in bttv_tvnorm.cropcap units. Protected + by bttv.lock. */ + struct bttv_crop crop[2]; + + /* Earliest possible start of video capturing in + bttv_tvnorm.cropcap line units. Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 vbi_end; + + /* Latest possible end of VBI capturing (= crop[x].rect.top when + VIDEO_RESOURCES are locked). Set by check_alloc_btres() + and free_btres(). Protected by bttv.lock. */ + __s32 crop_start; +}; + +static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct bttv, c.v4l2_dev); +} + +/* our devices */ +#define BTTV_MAX 32 +extern unsigned int bttv_num; +extern struct bttv *bttvs[BTTV_MAX]; + +static inline unsigned int bttv_muxsel(const struct bttv *btv, + unsigned int input) +{ + return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; +} + +#endif + +#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) +#define btread(adr) readl(btv->bt848_mmio+(adr)) + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +#endif /* _BTTVP_H_ */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f52799232029..f3d4228dbb0e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -619,8 +619,6 @@ menuconfig V4L_PCI_DRIVERS if V4L_PCI_DRIVERS -source "drivers/media/video/bt8xx/Kconfig" - source "drivers/media/video/cx18/Kconfig" source "drivers/media/video/cx23885/Kconfig" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 4ad5bd9246bf..df60ffacdc58 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -87,7 +87,6 @@ obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o # And now the v4l2 drivers: -obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_ZORAN) += zoran/ obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig deleted file mode 100644 index 7da5c2e1fc12..000000000000 --- a/drivers/media/video/bt8xx/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config VIDEO_BT848 - tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 - select I2C_ALGOBIT - select VIDEO_BTCX - select VIDEOBUF_DMA_SG - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_SAA6588 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - Support for BT848 based frame grabber/overlay boards. This includes - the Miro, Hauppauge and STB boards. Please read the material in - for more information. - - To compile this driver as a module, choose M here: the - module will be called bttv. - -config VIDEO_BT848_DVB - bool "DVB/ATSC Support for bt878 based TV cards" - depends on VIDEO_BT848 && DVB_CORE - select DVB_BT8XX - ---help--- - This adds support for DVB/ATSC cards based on the BT878 chip. diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile deleted file mode 100644 index f6351a25c267..000000000000 --- a/drivers/media/video/bt8xx/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for the video capture/playback device drivers. -# - -bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ - bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o bttv-audio-hook.o - -obj-$(CONFIG_VIDEO_BT848) += bttv.o - -ccflags-y += -Idrivers/media/video -ccflags-y += -Idrivers/media/tuners -ccflags-y += -Idrivers/media/dvb-core diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/video/bt8xx/bt848.h deleted file mode 100644 index c37e6acffded..000000000000 --- a/drivers/media/video/bt8xx/bt848.h +++ /dev/null @@ -1,369 +0,0 @@ -/* - bt848.h - Bt848 register offsets - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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. -*/ - -#ifndef _BT848_H_ -#define _BT848_H_ - -#ifndef PCI_VENDOR_ID_BROOKTREE -#define PCI_VENDOR_ID_BROOKTREE 0x109e -#endif -#ifndef PCI_DEVICE_ID_BT848 -#define PCI_DEVICE_ID_BT848 0x350 -#endif -#ifndef PCI_DEVICE_ID_BT849 -#define PCI_DEVICE_ID_BT849 0x351 -#endif -#ifndef PCI_DEVICE_ID_FUSION879 -#define PCI_DEVICE_ID_FUSION879 0x36c -#endif - -#ifndef PCI_DEVICE_ID_BT878 -#define PCI_DEVICE_ID_BT878 0x36e -#endif -#ifndef PCI_DEVICE_ID_BT879 -#define PCI_DEVICE_ID_BT879 0x36f -#endif - -/* Brooktree 848 registers */ - -#define BT848_DSTATUS 0x000 -#define BT848_DSTATUS_PRES (1<<7) -#define BT848_DSTATUS_HLOC (1<<6) -#define BT848_DSTATUS_FIELD (1<<5) -#define BT848_DSTATUS_NUML (1<<4) -#define BT848_DSTATUS_CSEL (1<<3) -#define BT848_DSTATUS_PLOCK (1<<2) -#define BT848_DSTATUS_LOF (1<<1) -#define BT848_DSTATUS_COF (1<<0) - -#define BT848_IFORM 0x004 -#define BT848_IFORM_HACTIVE (1<<7) -#define BT848_IFORM_MUXSEL (3<<5) -#define BT848_IFORM_MUX0 (2<<5) -#define BT848_IFORM_MUX1 (3<<5) -#define BT848_IFORM_MUX2 (1<<5) -#define BT848_IFORM_XTSEL (3<<3) -#define BT848_IFORM_XT0 (1<<3) -#define BT848_IFORM_XT1 (2<<3) -#define BT848_IFORM_XTAUTO (3<<3) -#define BT848_IFORM_XTBOTH (3<<3) -#define BT848_IFORM_NTSC 1 -#define BT848_IFORM_NTSC_J 2 -#define BT848_IFORM_PAL_BDGHI 3 -#define BT848_IFORM_PAL_M 4 -#define BT848_IFORM_PAL_N 5 -#define BT848_IFORM_SECAM 6 -#define BT848_IFORM_PAL_NC 7 -#define BT848_IFORM_AUTO 0 -#define BT848_IFORM_NORM 7 - -#define BT848_TDEC 0x008 -#define BT848_TDEC_DEC_FIELD (1<<7) -#define BT848_TDEC_FLDALIGN (1<<6) -#define BT848_TDEC_DEC_RAT (0x1f) - -#define BT848_E_CROP 0x00C -#define BT848_O_CROP 0x08C - -#define BT848_E_VDELAY_LO 0x010 -#define BT848_O_VDELAY_LO 0x090 - -#define BT848_E_VACTIVE_LO 0x014 -#define BT848_O_VACTIVE_LO 0x094 - -#define BT848_E_HDELAY_LO 0x018 -#define BT848_O_HDELAY_LO 0x098 - -#define BT848_E_HACTIVE_LO 0x01C -#define BT848_O_HACTIVE_LO 0x09C - -#define BT848_E_HSCALE_HI 0x020 -#define BT848_O_HSCALE_HI 0x0A0 - -#define BT848_E_HSCALE_LO 0x024 -#define BT848_O_HSCALE_LO 0x0A4 - -#define BT848_BRIGHT 0x028 - -#define BT848_E_CONTROL 0x02C -#define BT848_O_CONTROL 0x0AC -#define BT848_CONTROL_LNOTCH (1<<7) -#define BT848_CONTROL_COMP (1<<6) -#define BT848_CONTROL_LDEC (1<<5) -#define BT848_CONTROL_CBSENSE (1<<4) -#define BT848_CONTROL_CON_MSB (1<<2) -#define BT848_CONTROL_SAT_U_MSB (1<<1) -#define BT848_CONTROL_SAT_V_MSB (1<<0) - -#define BT848_CONTRAST_LO 0x030 -#define BT848_SAT_U_LO 0x034 -#define BT848_SAT_V_LO 0x038 -#define BT848_HUE 0x03C - -#define BT848_E_SCLOOP 0x040 -#define BT848_O_SCLOOP 0x0C0 -#define BT848_SCLOOP_CAGC (1<<6) -#define BT848_SCLOOP_CKILL (1<<5) -#define BT848_SCLOOP_HFILT_AUTO (0<<3) -#define BT848_SCLOOP_HFILT_CIF (1<<3) -#define BT848_SCLOOP_HFILT_QCIF (2<<3) -#define BT848_SCLOOP_HFILT_ICON (3<<3) - -#define BT848_SCLOOP_PEAK (1<<7) -#define BT848_SCLOOP_HFILT_MINP (1<<3) -#define BT848_SCLOOP_HFILT_MEDP (2<<3) -#define BT848_SCLOOP_HFILT_MAXP (3<<3) - - -#define BT848_OFORM 0x048 -#define BT848_OFORM_RANGE (1<<7) -#define BT848_OFORM_CORE0 (0<<5) -#define BT848_OFORM_CORE8 (1<<5) -#define BT848_OFORM_CORE16 (2<<5) -#define BT848_OFORM_CORE32 (3<<5) - -#define BT848_E_VSCALE_HI 0x04C -#define BT848_O_VSCALE_HI 0x0CC -#define BT848_VSCALE_YCOMB (1<<7) -#define BT848_VSCALE_COMB (1<<6) -#define BT848_VSCALE_INT (1<<5) -#define BT848_VSCALE_HI 15 - -#define BT848_E_VSCALE_LO 0x050 -#define BT848_O_VSCALE_LO 0x0D0 -#define BT848_TEST 0x054 -#define BT848_ADELAY 0x060 -#define BT848_BDELAY 0x064 - -#define BT848_ADC 0x068 -#define BT848_ADC_RESERVED (2<<6) -#define BT848_ADC_SYNC_T (1<<5) -#define BT848_ADC_AGC_EN (1<<4) -#define BT848_ADC_CLK_SLEEP (1<<3) -#define BT848_ADC_Y_SLEEP (1<<2) -#define BT848_ADC_C_SLEEP (1<<1) -#define BT848_ADC_CRUSH (1<<0) - -#define BT848_WC_UP 0x044 -#define BT848_WC_DOWN 0x078 - -#define BT848_E_VTC 0x06C -#define BT848_O_VTC 0x0EC -#define BT848_VTC_HSFMT (1<<7) -#define BT848_VTC_VFILT_2TAP 0 -#define BT848_VTC_VFILT_3TAP 1 -#define BT848_VTC_VFILT_4TAP 2 -#define BT848_VTC_VFILT_5TAP 3 - -#define BT848_SRESET 0x07C - -#define BT848_COLOR_FMT 0x0D4 -#define BT848_COLOR_FMT_O_RGB32 (0<<4) -#define BT848_COLOR_FMT_O_RGB24 (1<<4) -#define BT848_COLOR_FMT_O_RGB16 (2<<4) -#define BT848_COLOR_FMT_O_RGB15 (3<<4) -#define BT848_COLOR_FMT_O_YUY2 (4<<4) -#define BT848_COLOR_FMT_O_BtYUV (5<<4) -#define BT848_COLOR_FMT_O_Y8 (6<<4) -#define BT848_COLOR_FMT_O_RGB8 (7<<4) -#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) -#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) -#define BT848_COLOR_FMT_O_RAW (14<<4) -#define BT848_COLOR_FMT_E_RGB32 0 -#define BT848_COLOR_FMT_E_RGB24 1 -#define BT848_COLOR_FMT_E_RGB16 2 -#define BT848_COLOR_FMT_E_RGB15 3 -#define BT848_COLOR_FMT_E_YUY2 4 -#define BT848_COLOR_FMT_E_BtYUV 5 -#define BT848_COLOR_FMT_E_Y8 6 -#define BT848_COLOR_FMT_E_RGB8 7 -#define BT848_COLOR_FMT_E_YCrCb422 8 -#define BT848_COLOR_FMT_E_YCrCb411 9 -#define BT848_COLOR_FMT_E_RAW 14 - -#define BT848_COLOR_FMT_RGB32 0x00 -#define BT848_COLOR_FMT_RGB24 0x11 -#define BT848_COLOR_FMT_RGB16 0x22 -#define BT848_COLOR_FMT_RGB15 0x33 -#define BT848_COLOR_FMT_YUY2 0x44 -#define BT848_COLOR_FMT_BtYUV 0x55 -#define BT848_COLOR_FMT_Y8 0x66 -#define BT848_COLOR_FMT_RGB8 0x77 -#define BT848_COLOR_FMT_YCrCb422 0x88 -#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) -#define BT848_COLOR_CTL_RGB_DED (1<<5) -#define BT848_COLOR_CTL_GAMMA (1<<4) -#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) -#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) -#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) -#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) - -#define BT848_CAP_CTL 0x0DC -#define BT848_CAP_CTL_DITH_FRAME (1<<4) -#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) -#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) -#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) -#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) - -#define BT848_VBI_PACK_SIZE 0x0E0 - -#define BT848_VBI_PACK_DEL 0x0E4 -#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc -#define BT848_VBI_PACK_DEL_EXT_FRAME 2 -#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 - - -#define BT848_INT_STAT 0x100 -#define BT848_INT_MASK 0x104 - -#define BT848_INT_ETBF (1<<23) - -#define BT848_INT_RISCS (0xf<<28) -#define BT848_INT_RISC_EN (1<<27) -#define BT848_INT_RACK (1<<25) -#define BT848_INT_FIELD (1<<24) -#define BT848_INT_SCERR (1<<19) -#define BT848_INT_OCERR (1<<18) -#define BT848_INT_PABORT (1<<17) -#define BT848_INT_RIPERR (1<<16) -#define BT848_INT_PPERR (1<<15) -#define BT848_INT_FDSR (1<<14) -#define BT848_INT_FTRGT (1<<13) -#define BT848_INT_FBUS (1<<12) -#define BT848_INT_RISCI (1<<11) -#define BT848_INT_GPINT (1<<9) -#define BT848_INT_I2CDONE (1<<8) -#define BT848_INT_VPRES (1<<5) -#define BT848_INT_HLOCK (1<<4) -#define BT848_INT_OFLOW (1<<3) -#define BT848_INT_HSYNC (1<<2) -#define BT848_INT_VSYNC (1<<1) -#define BT848_INT_FMTCHG (1<<0) - - -#define BT848_GPIO_DMA_CTL 0x10C -#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) -#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) -#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) -#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) -#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) -#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) -#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) -#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) -#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) -#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) -#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) -#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) -#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) -#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) -#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) - -#define BT848_I2C 0x110 -#define BT878_I2C_MODE (1<<7) -#define BT878_I2C_RATE (1<<6) -#define BT878_I2C_NOSTOP (1<<5) -#define BT878_I2C_NOSTART (1<<4) -#define BT848_I2C_DIV (0xf<<4) -#define BT848_I2C_SYNC (1<<3) -#define BT848_I2C_W3B (1<<2) -#define BT848_I2C_SCL (1<<1) -#define BT848_I2C_SDA (1<<0) - -#define BT848_RISC_STRT_ADD 0x114 -#define BT848_GPIO_OUT_EN 0x118 -#define BT848_GPIO_REG_INP 0x11C -#define BT848_RISC_COUNT 0x120 -#define BT848_GPIO_DATA 0x200 - - -/* Bt848 RISC commands */ - -/* only for the SYNC RISC command */ -#define BT848_FIFO_STATUS_FM1 0x06 -#define BT848_FIFO_STATUS_FM3 0x0e -#define BT848_FIFO_STATUS_SOL 0x02 -#define BT848_FIFO_STATUS_EOL4 0x01 -#define BT848_FIFO_STATUS_EOL3 0x0d -#define BT848_FIFO_STATUS_EOL2 0x09 -#define BT848_FIFO_STATUS_EOL1 0x05 -#define BT848_FIFO_STATUS_VRE 0x04 -#define BT848_FIFO_STATUS_VRO 0x0c -#define BT848_FIFO_STATUS_PXV 0x00 - -#define BT848_RISC_RESYNC (1<<15) - -/* WRITE and SKIP */ -/* disable which bytes of each DWORD */ -#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 (1U<<24) -/* RISC command is last one in this line */ -#define BT848_RISC_EOL (1U<<26) -/* RISC command is first one in this line */ -#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 !! */ -#define BT848_TGLB 0x080 -#define BT848_TGCTRL 0x084 -#define BT848_FCAP 0x0E8 -#define BT848_PLL_F_LO 0x0F0 -#define BT848_PLL_F_HI 0x0F4 - -#define BT848_PLL_XCI 0x0F8 -#define BT848_PLL_X (1<<7) -#define BT848_PLL_C (1<<6) - -#define BT848_DVSIF 0x0FC - -/* Bt878 register */ - -#define BT878_DEVCTRL 0x40 -#define BT878_EN_TBFX 0x02 -#define BT878_EN_VSFX 0x04 - -#endif diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c deleted file mode 100644 index 2364d16586b3..000000000000 --- a/drivers/media/video/bt8xx/bttv-audio-hook.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttv-audio-hook.h" - -#include - -/* ----------------------------------------------------------------------- */ -/* winview */ - -void winview_volume(struct bttv *btv, __u16 volume) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x300; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x200; -/* if (t->audmode & V4L2_TUNER_MODE_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) { - if (t->audmode & V4L2_TUNER_MODE_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x30: - t->rxsubchans = V4L2_TUNER_SUB_LANG2; - break; - case 0x50: - t->rxsubchans = V4L2_TUNER_SUB_LANG1; - break; - case 0x60: - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 0x70: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - break; - default: - t->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - } - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Mario Medina Nussbaum - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ - -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x02; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1; - return; - } -} - - -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x01; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - t->audmode = V4L2_TUNER_MODE_MONO; - return; - } - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ - val = 0x0080; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ - val = 0x0880; - if ((t->audmode & V4L2_TUNER_MODE_LANG1) || - (t->audmode & V4L2_TUNER_MODE_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x080000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - - -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x410000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x01; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x0000; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki - */ -void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) - val = 0x040000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) - val = 0; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - val = 0x100000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa - */ -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x00180000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h deleted file mode 100644 index 159d07adeff8..000000000000 --- a/drivers/media/video/bt8xx/bttv-audio-hook.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttvp.h" - -void winview_volume (struct bttv *btv, __u16 volume); - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); - diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c deleted file mode 100644 index 38952faaffda..000000000000 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ /dev/null @@ -1,4895 +0,0 @@ -/* - - bttv-cards.c - - this file has configuration informations - card-specific stuff - like the big tvcards array for the most part - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2001 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bttvp.h" -#include -#include -#include "bttv-audio-hook.h" - -/* fwd decl */ -static void boot_msp34xx(struct bttv *btv, int pin); -static void hauppauge_eeprom(struct bttv *btv); -static void avermedia_eeprom(struct bttv *btv); -static void osprey_eeprom(struct bttv *btv, const u8 ee[256]); -static void modtec_eeprom(struct bttv *btv); -static void init_PXC200(struct bttv *btv); -static void init_RTV24(struct bttv *btv); - -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 void ivc120_muxsel(struct bttv *btv, unsigned int input); -static void gvc1100_muxsel(struct bttv *btv, unsigned int input); - -static void PXC200_muxsel(struct bttv *btv, unsigned int input); - -static void picolo_tetra_muxsel(struct bttv *btv, unsigned int input); -static void picolo_tetra_init(struct bttv *btv); - -static void tibetCS16_muxsel(struct bttv *btv, unsigned int input); -static void tibetCS16_init(struct bttv *btv); - -static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input); -static void kodicom4400r_init(struct bttv *btv); - -static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input); -static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input); - -static void geovision_muxsel(struct bttv *btv, unsigned int input); - -static void phytec_muxsel(struct bttv *btv, unsigned int input); - -static void gv800s_muxsel(struct bttv *btv, unsigned int input); -static void gv800s_init(struct bttv *btv); - -static void td3116_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); -static void identify_by_eeprom(struct bttv *btv, - unsigned char eeprom_data[256]); -static int __devinit pvr_boot(struct bttv *btv); - -/* config variables */ -static unsigned int triton1; -static unsigned int vsfx; -static unsigned int latency = UNSET; -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 }; -static unsigned int svhs[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int remote[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET }; -static unsigned int audiodev[BTTV_MAX]; -static unsigned int saa6588[BTTV_MAX]; -static struct bttv *master[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = NULL }; -static unsigned int autoload = UNSET; -static unsigned int gpiomask = UNSET; -static unsigned int audioall = UNSET; -static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET }; - -/* insmod options */ -module_param(triton1, int, 0444); -module_param(vsfx, int, 0444); -module_param(no_overlay, int, 0444); -module_param(latency, int, 0444); -module_param(gpiomask, int, 0444); -module_param(audioall, int, 0444); -module_param(autoload, int, 0444); - -module_param_array(card, int, NULL, 0444); -module_param_array(pll, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(svhs, int, NULL, 0444); -module_param_array(remote, int, NULL, 0444); -module_param_array(audiodev, int, NULL, 0444); -module_param_array(audiomux, int, NULL, 0444); - -MODULE_PARM_DESC(triton1,"set ETBF pci config bit " - "[enable bug compatibility for triton1 + others]"); -MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " - "[yet another chipset flaw workaround]"); -MODULE_PARM_DESC(latency,"pci latency timer"); -MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); -MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); -MODULE_PARM_DESC(tuner,"specify installed tuner type"); -MODULE_PARM_DESC(autoload, "obsolete option, please do not use anymore"); -MODULE_PARM_DESC(audiodev, "specify audio device:\n" - "\t\t-1 = no audio\n" - "\t\t 0 = autodetect (default)\n" - "\t\t 1 = msp3400\n" - "\t\t 2 = tda7432\n" - "\t\t 3 = tvaudio"); -MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); -MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" - " [some VIA/SIS chipsets are known to have problem with overlay]"); - -/* ----------------------------------------------------------------------- */ -/* list of card IDs for bt878+ cards */ - -static struct CARD { - unsigned id; - int cardnr; - char *name; -} cards[] __devinitdata = { - { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" }, - { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" }, - { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" }, - { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" }, - { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" }, - { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" }, - { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" }, - { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" }, - { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" }, - - { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" }, - { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, - - { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" }, - { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" }, - { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, - { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, - { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, - { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, - { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, - { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, - - { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, - /* some cards ship with byteswapped IDs ... */ - { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, - { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" }, - /* this seems to happen as well ... */ - { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" }, - - { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" }, - { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" }, - { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" }, - - { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, - { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" }, - { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, - { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" }, - { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" }, - { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" }, - { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" }, - - { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" }, - { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" }, - { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" }, - { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" }, - - { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" }, - { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" }, - { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" }, - { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" }, - - { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" }, - { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" }, - /* clashes with FlyVideo - *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */ - { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" }, - { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */ - { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */ - { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */ - - { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, - { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, - { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, - - { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" }, - { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" }, - { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" }, - { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" }, - { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" }, - - { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" }, - { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" }, - { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" }, - { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" }, - - { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" }, - { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" }, - { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" }, - { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" }, - - { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" }, - { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" }, - { 0xa1550800, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550801, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550802, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa1550803, BTTV_BOARD_IVC200, "IVC-200" }, - { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" }, - { 0xf0500000, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500001, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500002, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - { 0xf0500003, BTTV_BOARD_IVCE8784, "IVCE-8784" }, - - { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" }, - { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" }, - - { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, - { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" }, - { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" }, - { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" }, - { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" }, - { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" }, - - { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" }, - { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" }, - - { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, - { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" }, - { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" }, - { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, - { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, - { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, - { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" }, - { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" }, - - { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" }, - { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" }, - - { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" }, - { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" }, - { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" }, - { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" }, - - { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, - - { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, - { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, - - /* likely broken, vendor id doesn't match the other magic views ... - * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ - - /* Duplicate PCI ID, reconfigure for this board during the eeprom read. - * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ - - { 0x109e036e, BTTV_BOARD_CONCEPTRONIC_CTVFMI2, "Conceptronic CTVFMi v2"}, - - /* DVB cards (using pci function .1 for mpeg data xfer) */ - { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, - { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, - { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, - { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, - { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, - { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, - { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, - { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, - { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, - { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, - { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, - { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, - { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, - { 0x763d800a, BTTV_BOARD_GEOVISION_GV800S, "GeoVision GV-800(S) (master)" }, - { 0x763d800b, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - { 0x763d800c, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - { 0x763d800d, BTTV_BOARD_GEOVISION_GV800S_SL, "GeoVision GV-800(S) (slave)" }, - - { 0x15401830, BTTV_BOARD_PV183, "Provideo PV183-1" }, - { 0x15401831, BTTV_BOARD_PV183, "Provideo PV183-2" }, - { 0x15401832, BTTV_BOARD_PV183, "Provideo PV183-3" }, - { 0x15401833, BTTV_BOARD_PV183, "Provideo PV183-4" }, - { 0x15401834, BTTV_BOARD_PV183, "Provideo PV183-5" }, - { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, - { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, - { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, - { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" }, - { 0x02280279, BTTV_BOARD_APOSONIC_WDVR, "Aposonic W-DVR" }, - { 0, -1, NULL } -}; - -/* ----------------------------------------------------------------------- */ -/* array with description for bt848 / bt878 tv/grabber cards */ - -struct tvcard bttv_tvcards[] = { - /* ---- card 0x00 ---------------------------------- */ - [BTTV_BOARD_UNKNOWN] = { - .name = " *** UNKNOWN/GENERIC *** ", - .video_inputs = 4, - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MIRO] = { - .name = "MIRO PCTV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_HAUPPAUGE] = { - .name = "Hauppauge (bt848)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_STB] = { - .name = "STB, Gateway P/N 6000699 (bt848)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 4, 0, 2, 3 }, - .gpiomute = 1, - .no_msp34xx = 1, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - - /* ---- card 0x04 ---------------------------------- */ - [BTTV_BOARD_INTEL] = { - .name = "Intel Create and Share PCI/ Smart Video Recorder III", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_DIAMOND] = { - .name = "Diamond DTV2000", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0, 1, 0, 1 }, - .gpiomute = 3, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AVERMEDIA] = { - .name = "AVerMedia TVPhone", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomask = 0x0f, - .gpiomux = { 0x0c, 0x04, 0x08, 0x04 }, - /* 0x04 for some cards ?? */ - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tvphone_audio, - .has_remote = 1, - }, - [BTTV_BOARD_MATRIX_VISION] = { - .name = "MATRIX-Vision MV-Delta", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x08 ---------------------------------- */ - [BTTV_BOARD_FLYVIDEO] = { - .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xc00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0xc00, 0x800, 0x400 }, - .gpiomute = 0xc00, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TURBOTV] = { - .name = "IMS/IXmicro TurboTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 2, 3 }, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_HAUPPAUGE878] = { - .name = "Hauppauge (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0f, /* old: 7 */ - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MIROPRO] = { - .name = "MIRO PCTV pro", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3014f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20001,0x10001, 0, 0 }, - .gpiomute = 10, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x0c ---------------------------------- */ - [BTTV_BOARD_ADSTECH_TV] = { - .name = "ADS Technologies Channel Surfer TV (bt848)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 14, 11, 7 }, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AVERMEDIA98] = { - .name = "AVerMedia TVCapture 98", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 14, 11, 7 }, - .msp34xx_alt = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tv_stereo_audio, - .no_gpioirq = 1, - }, - [BTTV_BOARD_VHX] = { - .name = "Aimslab Video Highway Xtreme (VHX)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 2, 1, 3 }, /* old: {0, 1, 2, 3, 4} */ - .gpiomute = 4, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ZOLTRIX] = { - .name = "Zoltrix TV-Max", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 1, 0 }, - .gpiomute = 10, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x10 ---------------------------------- */ - [BTTV_BOARD_PIXVIEWPLAYTV] = { - .name = "Prolink Pixelview PlayTV (bt878)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1), - /* 2003-10-20 by "Anton A. Arapov" */ - .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, - .gpiomute = 0x002000, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_WINVIEW_601] = { - .name = "Leadtek WinView 601", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x8300f8, - .muxsel = MUXSEL(2, 3, 1, 1, 0), - .gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 }, - .gpiomute = 0xcfa007, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .volume_gpio = winview_volume, - .has_radio = 1, - }, - [BTTV_BOARD_AVEC_INTERCAP] = { - .name = "AVEC Intercapture", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0, 0, 0 }, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_LIFE_FLYKIT] = { - .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x8dff00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x14 ---------------------------------- */ - [BTTV_BOARD_CEI_RAFFLES] = { - .name = "CEI Raffles Card", - .video_inputs = 3, - /* .audio_inputs= 3, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 1), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_CONFERENCETV] = { - .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50", - .video_inputs = 4, - /* .audio_inputs= 2, tuner, line in */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_PHOEBE_TVMAS] = { - .name = "Askey CPH050/ Phoebe Tv Master + FM", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xc00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 0x800, 0x400 }, - .gpiomute = 0xc00, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MODTEC_205] = { - .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .has_dig_in = 1, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 0), /* input 2 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0, 0, 0, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ALPS_TSBB5_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x18 ---------------------------------- */ - [BTTV_BOARD_MAGICTVIEW061] = { - .name = "Askey CPH05X/06X (bt878) [many vendors]", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = {0x400, 0x400, 0x400, 0x400 }, - .gpiomute = 0xc00, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - .has_radio = 1, /* not every card has radio */ - }, - [BTTV_BOARD_VOBIS_BOOSTAR] = { - .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1f0fff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, - .gpiomute = 0x40000, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, - }, - [BTTV_BOARD_HAUPPAUG_WCAM] = { - .name = "Hauppauge WinCam newer (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 7, - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MAXI] = { - .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50", - .video_inputs = 4, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_SECAM, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x1c ---------------------------------- */ - [BTTV_BOARD_TERRATV] = { - .name = "Terratec TerraTV+ Version 1.1 (bt878)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1f0fff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0x00000 }, - .gpiomute = 0x40000, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, - /* GPIO wiring: - External 20 pin connector (for Active Radio Upgrade board) - gpio00: i2c-sda - gpio01: i2c-scl - gpio02: om5610-data - gpio03: om5610-clk - gpio04: om5610-wre - gpio05: om5610-stereo - gpio06: rds6588-davn - gpio07: Pin 7 n.c. - gpio08: nIOW - gpio09+10: nIOR, nSEL ?? (bt878) - gpio09: nIOR (bt848) - gpio10: nSEL (bt848) - Sound Routing: - gpio16: u2-A0 (1st 4052bt) - gpio17: u2-A1 - gpio18: u2-nEN - gpio19: u4-A0 (2nd 4052) - gpio20: u4-A1 - u4-nEN - GND - Btspy: - 00000 : Cdrom (internal audio input) - 10000 : ext. Video audio input - 20000 : TV Mono - a0000 : TV Mono/2 - 1a0000 : TV Stereo - 30000 : Radio - 40000 : Mute - */ - - }, - [BTTV_BOARD_PXC200] = { - /* Jannik Fritsch */ - .name = "Imagenation PXC200", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 1, /* was: 4 */ - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = PXC200_muxsel, - - }, - [BTTV_BOARD_FLYVIDEO_98] = { - .name = "Lifeview FlyVideo 98 LR50", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x1800, /* 0x8dfe00 */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x0800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_IPROTV] = { - .name = "Formac iProTV, Formac ProTV I (bt848)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 1, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0, 0, 0 }, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x20 ---------------------------------- */ - [BTTV_BOARD_INTEL_C_S_PCI] = { - .name = "Intel Create and Share PCI/ Smart Video Recorder III", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0 }, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TERRATVALUE] = { - .name = "Terratec TerraTValue Version Bt878", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xffff00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x500, 0, 0x300, 0x900 }, - .gpiomute = 0x900, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_WINFAST2000] = { - .name = "Leadtek WinFast 2000/ WinFast 2000 XP", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - /* TV, CVid, SVid, CVid over SVid connector */ - .muxsel = MUXSEL(2, 3, 1, 1, 0), - /* Alexander Varakin [stereo version] */ - .gpiomask = 0xb33000, - .gpiomux = { 0x122000,0x1000,0x0000,0x620000 }, - .gpiomute = 0x800000, - /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) - gpio23 -- hef4052:nEnable (0x800000) - gpio12 -- hef4052:A1 - gpio13 -- hef4052:A0 - 0x0000: external audio - 0x1000: FM - 0x2000: TV - 0x3000: n.c. - Note: There exists another variant "Winfast 2000" with tv stereo !? - Note: eeprom only contains FF and pci subsystem id 107d:6606 - */ - .pll = PLL_28, - .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= winfast2000_audio, - .has_remote = 1, - }, - [BTTV_BOARD_CHRONOS_VS2] = { - .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x24 ---------------------------------- */ - [BTTV_BOARD_TYPHOON_TVIEW] = { - .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1800, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0x800, 0x1000, 0x1000 }, - .gpiomute = 0x1800, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - [BTTV_BOARD_PXELVWPLTVPRO] = { - .name = "Prolink PixelView PlayTV pro", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xff, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, - .gpiomute = 0x29, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MAGICTVIEW063] = { - .name = "Askey CPH06X TView99", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x551e00, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0x551400, 0x551200, 0, 0 }, - .gpiomute = 0x551c00, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - [BTTV_BOARD_PINNACLE] = { - .name = "Pinnacle PCTV Studio/Rave", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0xd0001, 0, 0 }, - .gpiomute = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x28 ---------------------------------- */ - [BTTV_BOARD_STB2] = { - .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 4, 0, 2, 3 }, - .gpiomute = 1, - .no_msp34xx = 1, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_AVPHONE98] = { - .name = "AVerMedia TVPhone 98", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 13, 4, 11, 7 }, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - .audio_mode_gpio= avermedia_tvphone_audio, - }, - [BTTV_BOARD_PV951] = { - .name = "ProVideo PV951", /* pic16c54 */ - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0, 0}, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ONAIR_TV] = { - .name = "Little OnAir TV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00b, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 }, - .gpiomute = 0xff3ffc, - .no_msp34xx = 1, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x2c ---------------------------------- */ - [BTTV_BOARD_SIGMA_TVII_FM] = { - .name = "Sigma TVII-FM", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 0, 2 }, - .gpiomute = 3, - .no_msp34xx = 1, - .pll = PLL_NONE, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MATRIX_VISION2] = { - .name = "MATRIX-Vision MV-Delta 2", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ZOLTRIX_GENIE] = { - .name = "Zoltrix Genie TV/FM", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xbcf03f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0 }, - .gpiomute = 0xbcb03f, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4039FR5_NTSC, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TERRATVRADIO] = { - .name = "Terratec TV/Radio+", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x70000, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20000, 0x30000, 0x10000, 0 }, - .gpiomute = 0x40000, - .no_msp34xx = 1, - .pll = PLL_35, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - - /* ---- card 0x30 ---------------------------------- */ - [BTTV_BOARD_DYNALINK] = { - .name = "Askey CPH03x/ Dynalink Magic TView", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = {2,0,0,0 }, - .gpiomute = 1, - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GVBCTV3PCI] = { - .name = "IODATA GV-BCTV3/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x010f00, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = {0x10000, 0, 0x10000, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ALPS_TSHC6_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, - }, - [BTTV_BOARD_PXELVWPLTVPAK] = { - .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .has_dig_in = 1, - .gpiomask = 0xAA0000, - .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0x20000, 0, 0x80000, 0x80000 }, - .gpiomute = 0xa8000, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - /* GPIO wiring: (different from Rev.4C !) - GPIO17: U4.A0 (first hef4052bt) - GPIO19: U4.A1 - GPIO20: U5.A1 (second hef4052bt) - GPIO21: U4.nEN - GPIO22: BT832 Reset Line - GPIO23: A5,A0, U5,nEN - Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 - */ - }, - [BTTV_BOARD_EAGLE] = { - .name = "Eagle Wireless Capricorn2 (bt878A)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 0, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .pll = PLL_28, - .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x34 ---------------------------------- */ - [BTTV_BOARD_PINNACLEPRO] = { - /* David Härdeman */ - .name = "Pinnacle PCTV Studio Pro", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 0xd0001, 0, 0 }, - .gpiomute = 10, - /* sound path (5 sources): - MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable) - 0= ext. Audio IN - 1= from MUX2 - 2= Mono TV sound from Tuner - 3= not connected - MUX2 (mask 0x30000): - 0,2,3= from MSP34xx - 1= FM stereo Radio from Tuner */ - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TVIEW_RDS_FM] = { - /* Claas Langbehn , - Sven Grothklags */ - .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 0x1c, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0x10, 8 }, - .gpiomute = 4, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - [BTTV_BOARD_LIFETEC_9415] = { - /* Tim Röstermundt - in de.comp.os.unix.linux.hardware: - options bttv card=0 pll=1 radio=1 gpiomask=0x18e0 - gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff - options tuner type=5 */ - .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x18e0, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, - .gpiomute = 0x18e0, - /* For cards with tda9820/tda9821: - 0x0000: Tuner normal stereo - 0x0080: Tuner A2 SAP (second audio program = Zweikanalton) - 0x0880: Tuner A2 stereo */ - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_BESTBUY_EASYTV] = { - /* Miguel Angel Alvarez - old Easy TV BT848 version (model CPH031) */ - .name = "Askey CPH031/ BESTBUY Easy TV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xF, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x38 ---------------------------------- */ - [BTTV_BOARD_FLYVIDEO_98FM] = { - /* Gordon Heydon */ - [BTTV_BOARD_GRANDTEC] = { - .name = "GrandTec 'Grand Video Capture' (Bt848)", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .gpiomask = 0, - .muxsel = MUXSEL(3, 1), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_35, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ASKEY_CPH060] = { - /* Daniel Herrington */ - .name = "Askey CPH060/ Phoebe TV Master Only (No FM)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x400, 0x400, 0x400, 0x400 }, - .gpiomute = 0x800, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4036FY5_NTSC, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ASKEY_CPH03X] = { - /* Matti Mottus */ - .name = "Askey CPH03x TV Capturer", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x03000F, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - - /* ---- card 0x3c ---------------------------------- */ - [BTTV_BOARD_MM100PCTV] = { - /* Philip Blundell */ - .name = "Modular Technology MM100PCTV", - .video_inputs = 2, - /* .audio_inputs= 2, */ - .svhs = NO_SVHS, - .gpiomask = 11, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 1 }, - .gpiomute = 8, - .pll = PLL_35, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GMV1] = { - /* Adrian Cox - new Easy TV BT878 version (model CPH061) - special thanks to Informatica Mieres for providing the card */ - .name = "Askey CPH061/ BESTBUY Easy TV (bt878)", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0xFF, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 1, 0, 4, 4 }, - .gpiomute = 9, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_ATI_TVWONDER] = { - /* Lukas Gebauer */ - .name = "ATI TV-Wonder", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0xf03f, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0xbffe, 0, 0xbfff, 0 }, - .gpiomute = 0xbffe, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x40 ---------------------------------- */ - [BTTV_BOARD_ATI_TVWONDERVE] = { - /* Lukas Gebauer */ - .name = "ATI TV-Wonder VE", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 1, - .muxsel = MUXSEL(2, 3, 0, 1), - .gpiomux = { 0, 0, 1, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_FLYVIDEO2000] = { - /* DeeJay */ - .name = "IODATA GV-BCTV4/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x010f00, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = {0x10000, 0, 0x10000, 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, - }, - - /* ---- card 0x44 ---------------------------------- */ - [BTTV_BOARD_VOODOOTV_FM] = { - .name = "3Dfx VoodooTV FM (Euro)", - /* try "insmod msp3400 simple=0" if you have - * sound problems with this card. */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x4f8a00, - /* 0x100000: 1=MSP enabled (0=disable again) - * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ - .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, - .gpiomute = 0x947fff, - /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ - .muxsel = MUXSEL(2, 3, 0, 1), - .tuner_type = TUNER_MT2032, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_VOODOOTV_200] = { - .name = "VoodooTV 200 (USA)", - /* try "insmod msp3400 simple=0" if you have - * sound problems with this card. */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0x4f8a00, - /* 0x100000: 1=MSP enabled (0=disable again) - * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */ - .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, - .gpiomute = 0x947fff, - /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ - .muxsel = MUXSEL(2, 3, 0, 1), - .tuner_type = TUNER_MT2032, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - [BTTV_BOARD_AIMMS] = { - /* Philip Blundell */ - .name = "Active Imaging AIMMS", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .muxsel = MUXSEL(2), - .gpiomask = 0 - }, - [BTTV_BOARD_PV_BT878P_PLUS] = { - /* Tomasz Pyra */ - .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)", - .video_inputs = 3, - /* .audio_inputs= 4, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 11, 7 }, /* TV and Radio with same GPIO ! */ - .gpiomute = 13, - .pll = PLL_28, - .tuner_type = TUNER_LG_PAL_I_FM, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - /* GPIO wiring: - GPIO0: U4.A0 (hef4052bt) - GPIO1: U4.A1 - GPIO2: U4.A1 (second hef4052bt) - GPIO3: U4.nEN, U5.A0, A5.nEN - GPIO8-15: vrd866b ? - */ - }, - [BTTV_BOARD_FLYVIDEO98EZ] = { - .name = "Lifeview FlyVideo 98EZ (capture only) LR51", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 2, - /* AV1, AV2, SVHS, CVid adapter on SVHS */ - .muxsel = MUXSEL(2, 3, 1, 1), - .pll = PLL_28, - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x48 ---------------------------------- */ - [BTTV_BOARD_PV_BT878P_9B] = { - /* Dariusz Kowalewski */ - .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x01, 0x00, 0x03, 0x03 }, - .gpiomute = 0x09, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ - .has_radio = 1, /* Note: not all cards have radio */ - .has_remote = 1, - /* GPIO wiring: - GPIO0: A0 hef4052 - GPIO1: A1 hef4052 - GPIO3: nEN hef4052 - GPIO8-15: vrd866b - GPIO20,22,23: R30,R29,R28 - */ - }, - [BTTV_BOARD_SENSORAY311_611] = { - /* Clay Kunz */ - /* you must jumper JP5 for the 311 card (PC/104+) to work */ - .name = "Sensoray 311/611", - .video_inputs = 5, - /* .audio_inputs= 0, */ - .svhs = 4, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0, 0), - .gpiomux = { 0 }, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_RV605] = { - /* Miguel Freitas */ - .name = "RemoteVision MX (RV605)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x00, - .gpiomask2 = 0x07ff, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .no_msp34xx = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = rv605_muxsel, - }, - [BTTV_BOARD_POWERCLR_MTV878] = { - .name = "Powercolor MTV878/ MTV878R/ MTV878F", - .video_inputs = 3, - /* .audio_inputs= 2, */ - .svhs = 2, - .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */ - .muxsel = MUXSEL(2, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 4, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - }, - - /* ---- card 0x4c ---------------------------------- */ - [BTTV_BOARD_WINDVR] = { - /* Masaki Suzuki */ - .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x140007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= windvr_audio, - }, - [BTTV_BOARD_GRANDTEC_MULTI] = { - .name = "GrandTec Multi Capture Card (Bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_KWORLD] = { - .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF", - .video_inputs = 4, - /* .audio_inputs= 3, */ - .svhs = 2, - .gpiomask = 7, - /* Tuner, SVid, SVHS, SVid to SVHS connector */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 4, 4 },/* Yes, this tuner uses the same audio output for TV and FM radio! - * This card lacks external Audio In, so we mute it on Ext. & Int. - * The PCB can take a sbx1637/sbx1673, wiring unknown. - * This card lacks PCI subsystem ID, sigh. - * gpiomux =1: lower volume, 2+3: mute - * btwincap uses 0x80000/0x80003 - */ - .gpiomute = 4, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and - radio signal strength indicators work fine. */ - .has_radio = 1, - /* GPIO Info: - GPIO0,1: HEF4052 A0,A1 - GPIO2: HEF4052 nENABLE - GPIO3-7: n.c. - GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card] - GPIO14,15: ?? - GPIO16-21: n.c. - GPIO22,23: ?? - ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/ - }, - [BTTV_BOARD_DSP_TCVIDEO] = { - /* Arthur Tetzlaff-Deas, DSP Design Ltd */ - .name = "DSP Design TCVIDEO", - .video_inputs = 4, - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x50 ---------------------------------- */ - [BTTV_BOARD_HAUPPAUGEPVR] = { - .name = "Hauppauge WinTV PVR", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 0, 1, 1), - .pll = PLL_28, - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - - .gpiomask = 7, - .gpiomux = {7}, - }, - [BTTV_BOARD_GVBCTV5PCI] = { - .name = "IODATA GV-BCTV5/PCI", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0f0f80, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = {0x030000, 0x010000, 0, 0 }, - .gpiomute = 0x020000, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv5pci_audio, - .has_radio = 1, - }, - [BTTV_BOARD_OSPREY1x0] = { - .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ - .video_inputs = 4, /* id-inputs-clock */ - /* .audio_inputs= 0, */ - .svhs = 3, - .muxsel = MUXSEL(3, 2, 0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x0_848] = { - .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x54 ---------------------------------- */ - [BTTV_BOARD_OSPREY101_848] = { - .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(3, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x1] = { - .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ - .video_inputs = 1, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY1x1_SVID] = { - .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY2xx] = { - .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ - .video_inputs = 1, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x58 ---------------------------------- */ - [BTTV_BOARD_OSPREY2x0_SVID] = { - .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY2x0] = { - .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY500] = { - .name = "Osprey 500", /* 500 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - [BTTV_BOARD_OSPREY540] = { - .name = "Osprey 540", /* 540 */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - - /* ---- card 0x5C ---------------------------------- */ - [BTTV_BOARD_OSPREY2000] = { - .name = "Osprey 2000", /* 2000 */ - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = 1, - .muxsel = MUXSEL(2, 3), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */ - }, - [BTTV_BOARD_IDS_EAGLE] = { - /* M G Berberich */ - .name = "IDS Eagle", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 2, 2, 2), - .muxsel_hook = eagle_muxsel, - .no_msp34xx = 1, - .pll = PLL_28, - }, - [BTTV_BOARD_PINNACLESAT] = { - .name = "Pinnacle PCTV Sat", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel = MUXSEL(3, 1), - .pll = PLL_28, - .no_gpioirq = 1, - .has_dvb = 1, - }, - [BTTV_BOARD_FORMAC_PROTV] = { - .name = "Formac ProTV II (bt878)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 3, - .gpiomask = 2, - /* TV, Comp1, Composite over SVID con, SVID */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 2, 0, 0 }, - .pll = PLL_28, - .has_radio = 1, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* sound routing: - GPIO=0x00,0x01,0x03: mute (?) - 0x02: both TV and radio (tuner: FM1216/I) - The card has onboard audio connectors labeled "cdrom" and "board", - not soldered here, though unknown wiring. - Card lacks: external audio in, pci subsystem id. - */ - }, - - /* ---- card 0x60 ---------------------------------- */ - [BTTV_BOARD_MACHTV] = { - .name = "MachTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3}, - .gpiomute = 4, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - [BTTV_BOARD_EURESYS_PICOLO] = { - .name = "Euresys Picolo", - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 2, - .gpiomask = 0, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel = MUXSEL(2, 0, 1), - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_PV150] = { - /* Luc Van Hoeylandt */ - .name = "ProVideo PV150", /* 0x4f */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_AD_TVK503] = { - /* Hiroshi Takekawa */ - /* This card lacks subsystem ID */ - .name = "AD-TVK503", /* 0x63 */ - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x001e8007, - .muxsel = MUXSEL(2, 3, 1, 0), - /* Tuner, Radio, external, internal, off, on */ - .gpiomux = { 0x08, 0x0f, 0x0a, 0x08 }, - .gpiomute = 0x0f, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .audio_mode_gpio= adtvk503_audio, - }, - - /* ---- card 0x64 ---------------------------------- */ - [BTTV_BOARD_HERCULES_SM_TV] = { - .name = "Hercules Smart TV Stereo", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 1), - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - /* 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 - */ - }, - [BTTV_BOARD_PACETV] = { - .name = "Pace TV & Radio Card", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - /* Tuner, CVid, SVid, CVid over SVid connector */ - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomask = 0, - .no_tda7432 = 1, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - .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! - */ - }, - [BTTV_BOARD_IVC200] = { - /* Chris Willing */ - .name = "IVC-200", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2), - .pll = PLL_28, - }, - [BTTV_BOARD_IVCE8784] = { - .name = "IVCE-8784", - .video_inputs = 1, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2), - .pll = PLL_28, - }, - [BTTV_BOARD_XGUARD] = { - .name = "Grand X-Guard / Trust 814PCI", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .gpiomask2 = 0xff, - .muxsel = 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_tda7432 = 1, - .pll = PLL_28, - }, - - /* ---- card 0x68 ---------------------------------- */ - [BTTV_BOARD_NEBULA_DIGITV] = { - .name = "Nebula Electronics DigiTV", - .video_inputs = 1, - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - .has_remote = 1, - .gpiomask = 0x1b, - .no_gpioirq = 1, - }, - [BTTV_BOARD_PV143] = { - /* Jorge Boncompte - DTI2 */ - .name = "ProVideo PV143", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009X1_VD011_MINIDIN] = { - /* M.Klahr@phytec.de */ - .name = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009X1_VD011_COMBI] = { - .name = "PHYTEC VD-009-X1 VD-011 Combi (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - - /* ---- card 0x6c ---------------------------------- */ - [BTTV_BOARD_VD009_MINIDIN] = { - .name = "PHYTEC VD-009 MiniDIN (bt878)", - .video_inputs = 10, - /* .audio_inputs= 0, */ - .svhs = 9, - .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ - .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0), - .muxsel_hook = phytec_muxsel, - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD009_COMBI] = { - .name = "PHYTEC VD-009 Combi (bt878)", - .video_inputs = 10, - /* .audio_inputs= 0, */ - .svhs = 9, - .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ - .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1), - .muxsel_hook = phytec_muxsel, - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_IVC100] = { - .name = "IVC-100", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xdf, - .muxsel = MUXSEL(2, 3, 1, 0), - .pll = PLL_28, - }, - [BTTV_BOARD_IVC120] = { - /* IVC-120G - Alan Garfield */ - .name = "IVC-120G", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, /* card has no svhs */ - .no_msp34xx = 1, - .no_tda7432 = 1, - .gpiomask = 0x00, - .muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - .muxsel_hook = ivc120_muxsel, - .pll = PLL_28, - }, - - /* ---- card 0x70 ---------------------------------- */ - [BTTV_BOARD_PC_HDTV] = { - .name = "pcHDTV HD-2000 TV", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - }, - [BTTV_BOARD_TWINHAN_DST] = { - .name = "Twinhan DST + clones", - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_video = 1, - .has_dvb = 1, - }, - [BTTV_BOARD_WINFASTVC100] = { - .name = "Winfast VC100", - .video_inputs = 3, - /* .audio_inputs= 0, */ - .svhs = 1, - /* Vid In, SVid In, Vid over SVid in connector */ - .muxsel = MUXSEL(3, 1, 1, 3), - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - [BTTV_BOARD_TEV560] = { - .name = "Teppro TEV-560/InterVision IV-560", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 3, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 1, 1, 1, 1 }, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_35, - }, - - /* ---- card 0x74 ---------------------------------- */ - [BTTV_BOARD_SIMUS_GVC1100] = { - .name = "SIMUS GVC1100", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .muxsel = MUXSEL(2, 2, 2, 2), - .gpiomask = 0x3F, - .muxsel_hook = gvc1100_muxsel, - }, - [BTTV_BOARD_NGSTV_PLUS] = { - /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */ - .name = "NGS NGSTV+", - .video_inputs = 3, - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 0, 0), - .gpiomux = { 0, 0, 0, 0 }, - .gpiomute = 0x000003, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - [BTTV_BOARD_LMLBT4] = { - /* http://linuxmedialabs.com */ - .name = "LMLBT4", - .video_inputs = 4, /* IN1,IN2,IN3,IN4 */ - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TEKRAM_M205] = { - /* Helmroos Harri */ - .name = "Tekram M205 PRO", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .svhs = 2, - .gpiomask = 0x68, - .muxsel = MUXSEL(2, 3, 1), - .gpiomux = { 0x68, 0x68, 0x61, 0x61 }, - .pll = PLL_28, - }, - - /* ---- card 0x78 ---------------------------------- */ - [BTTV_BOARD_CONTVFMI] = { - /* Javier Cendan Ares */ - /* bt878 TV + FM without subsystem ID */ - .name = "Conceptronic CONTVFMi", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 3, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - .has_radio = 1, - }, - [BTTV_BOARD_PICOLO_TETRA_CHIP] = { - /*Eric DEBIEF */ - /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/ - /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ - /*0x79 in bttv.h*/ - .name = "Euresys Picolo Tetra", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/ - .no_msp34xx = 1, - .no_tda7432 = 1, - /*878A input is always MUX0, see above.*/ - .muxsel = MUXSEL(2, 2, 2, 2), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_SPIRIT_TV] = { - /* Spirit TV Tuner from http://spiritmodems.com.au */ - /* Stafford Goodsell */ - .name = "Spirit TV Tuner", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x0000000f, - .muxsel = MUXSEL(2, 1, 1), - .gpiomux = { 0x02, 0x00, 0x00, 0x00 }, - .tuner_type = TUNER_TEMIC_PAL, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - }, - [BTTV_BOARD_AVDVBT_771] = { - /* Wolfram Joost */ - .name = "AVerMedia AVerTV DVB-T 771", - .video_inputs = 2, - .svhs = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel = MUXSEL(3, 3), - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, - }, - /* ---- card 0x7c ---------------------------------- */ - [BTTV_BOARD_AVDVBT_761] = { - /* Matt Jesson */ - /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */ - .name = "AverMedia AverTV DVB-T 761", - .video_inputs = 2, - .svhs = 1, - .muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */ - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .has_dvb = 1, - .no_gpioirq = 1, - .has_remote = 1, - }, - [BTTV_BOARD_MATRIX_VISIONSQ] = { - /* andre.schwarz@matrix-vision.de */ - .name = "MATRIX Vision Sigma-SQ", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), - .muxsel_hook = sigmaSQ_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MATRIX_VISIONSLC] = { - /* andre.schwarz@matrix-vision.de */ - .name = "MATRIX Vision Sigma-SLC", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2), - .muxsel_hook = sigmaSLC_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - /* BTTV_BOARD_APAC_VIEWCOMP */ - [BTTV_BOARD_APAC_VIEWCOMP] = { - /* Attila Kondoros */ - /* bt878 TV + FM 0x00000000 subsystem ID */ - .name = "APAC Viewcomp 878(AMAX)", - .video_inputs = 2, - /* .audio_inputs= 1, */ - .svhs = NO_SVHS, - .gpiomask = 0xFF, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 10, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */ - .has_radio = 1, /* not every card has radio */ - }, - - /* ---- card 0x80 ---------------------------------- */ - [BTTV_BOARD_DVICO_DVBT_LITE] = { - /* Chris Pascoe */ - .name = "DViCO FusionHDTV DVB-T Lite", - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .no_video = 1, - .has_dvb = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VGEAR_MYVCD] = { - /* Steven */ - .name = "V-Gear MyVCD", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 0), - .gpiomux = {0x31, 0x31, 0x31, 0x31 }, - .gpiomute = 0x31, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC_M, - .tuner_addr = ADDR_UNSET, - .has_radio = 0, - }, - [BTTV_BOARD_SUPER_TV] = { - /* Rick C */ - .name = "Super TV Tuner", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - .gpiomask = 0x008007, - .gpiomux = { 0, 0x000001,0,0 }, - .has_radio = 1, - }, - [BTTV_BOARD_TIBET_CS16] = { - /* Chris Fanning */ - .name = "Tibet Systems 'Progress DVR' CS16", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .muxsel_hook = tibetCS16_muxsel, - }, - [BTTV_BOARD_KODICOM_4400R] = { - /* Bill Brack */ - /* - * Note that, because of the card's wiring, the "master" - * BT878A chip (i.e. the one which controls the analog switch - * and must use this card type) is the 2nd one detected. The - * other 3 chips should use card type 0x85, whose description - * follows this one. There is a EEPROM on the card (which is - * connected to the I2C of one of those other chips), but is - * not currently handled. There is also a facility for a - * "monitor", which is also not currently implemented. - */ - .name = "Kodicom 4400R (master)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - /* GPIO bits 0-9 used for analog switch: - * 00 - 03: camera selector - * 04 - 06: channel (controller) selector - * 07: data (1->on, 0->off) - * 08: strobe - * 09: reset - * bit 16 is input from sync separator for the channel - */ - .gpiomask = 0x0003ff, - .no_gpioirq = 1, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = kodicom4400r_muxsel, - }, - [BTTV_BOARD_KODICOM_4400R_SL] = { - /* Bill Brack */ - /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the - * one which controls the analog switch, and must use the card type) - * is the 2nd one detected. The other 3 chips should use this card - * type - */ - .name = "Kodicom 4400R (slave)", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0x010000, - .no_gpioirq = 1, - .muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = kodicom4400r_muxsel, - }, - /* ---- card 0x86---------------------------------- */ - [BTTV_BOARD_ADLINK_RTV24] = { - /* Michael Henson */ - /* Adlink RTV24 with special unlock codes */ - .name = "Adlink RTV24", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = UNSET, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - }, - /* ---- card 0x87---------------------------------- */ - [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = { - /* Michael Krufky */ - .name = "DViCO FusionHDTV 5 Lite", - .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */ - .tuner_addr = ADDR_UNSET, - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .gpiomask = 0x00e00007, - .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, - .gpiomute = 0x00c00007, - .no_msp34xx = 1, - .no_tda7432 = 1, - .has_dvb = 1, - }, - /* ---- card 0x88---------------------------------- */ - [BTTV_BOARD_ACORP_Y878F] = { - /* Mauro Carvalho Chehab */ - .name = "Acorp Y878F", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x001e00, 0, 0x018000, 0x014000 }, - .gpiomute = 0x002000, - .pll = PLL_28, - .tuner_type = TUNER_YMEC_TVF66T5_B_DFF, - .tuner_addr = 0xc1 >>1, - .has_radio = 1, - }, - /* ---- card 0x89 ---------------------------------- */ - [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = { - .name = "Conceptronic CTVFMi v2", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x001c0007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, - .gpiomute = 3, - .pll = PLL_28, - .tuner_type = TUNER_TENA_9533_DI, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - .has_radio = 1, - }, - /* ---- card 0x8a ---------------------------------- */ - [BTTV_BOARD_PV_BT878P_2E] = { - .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)", - .video_inputs = 5, - /* .audio_inputs= 1, */ - .svhs = 3, - .has_dig_in = 1, - .gpiomask = 0x01fe00, - .muxsel = MUXSEL(2, 3, 1, 1, 0), /* in 4 is digital */ - /* .digital_mode= DIGITAL_MODE_CAMERA, */ - .gpiomux = { 0x00400, 0x10400, 0x04400, 0x80000 }, - .gpiomute = 0x12400, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_LG_PAL_FM, - .tuner_addr = ADDR_UNSET, - .has_remote = 1, - }, - /* ---- card 0x8b ---------------------------------- */ - [BTTV_BOARD_PV_M4900] = { - /* Sérgio Fortier */ - .name = "Prolink PixelView PlayTV MPEG2 PV-M4900", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x21, 0x20, 0x24, 0x2c }, - .gpiomute = 0x29, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - .has_remote = 1, - }, - /* ---- card 0x8c ---------------------------------- */ - /* Has four Bt878 chips behind a PCI bridge, each chip has: - one external BNC composite input (mux 2) - three internal composite inputs (unknown muxes) - an 18-bit stereo A/D (CS5331A), which has: - one external stereo unblanced (RCA) audio connection - one (or 3?) internal stereo balanced (XLR) audio connection - input is selected via gpio to a 14052B mux - (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) - gain is controlled via an X9221A chip on the I2C bus @0x28 - sample rate is controlled via gpio to an MK1413S - (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3) - There is neither a tuner nor an svideo input. */ - [BTTV_BOARD_OSPREY440] = { - .name = "Osprey 440", - .video_inputs = 4, - /* .audio_inputs= 2, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 0, 1), /* 3,0,1 are guesses */ - .gpiomask = 0x303, - .gpiomute = 0x000, /* int + 32kHz */ - .gpiomux = { 0, 0, 0x000, 0x100}, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - /* ---- card 0x8d ---------------------------------- */ - [BTTV_BOARD_ASOUND_SKYEYE] = { - .name = "Asound Skyeye PCTV", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 15, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 2, 0, 0, 0 }, - .gpiomute = 1, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_NTSC, - .tuner_addr = ADDR_UNSET, - }, - /* ---- card 0x8e ---------------------------------- */ - [BTTV_BOARD_SABRENT_TVFM] = { - .name = "Sabrent TV-FM (bttv version)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x108007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 100000, 100002, 100002, 100000 }, - .no_msp34xx = 1, - .no_tda7432 = 1, - .pll = PLL_28, - .tuner_type = TUNER_TNF_5335MF, - .tuner_addr = ADDR_UNSET, - .has_radio = 1, - }, - /* ---- card 0x8f ---------------------------------- */ - [BTTV_BOARD_HAUPPAUGE_IMPACTVCB] = { - .name = "Hauppauge ImpactVCB (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0f, /* old: 7 */ - .muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */ - .no_msp34xx = 1, - .no_tda7432 = 1, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_MACHTV_MAGICTV] = { - /* Julian Calaby - * Slightly different from original MachTV definition (0x60) - - * FIXME: RegSpy says gpiomask should be "0x001c800f", but it - * stuffs up remote chip. Bug is a pin on the jaecs is not set - * properly (methinks) causing no keyup bits being set */ - - .name = "MagicTV", /* rebranded MachTV */ - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 7, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 3 }, - .gpiomute = 4, - .tuner_type = TUNER_TEMIC_4009FR5_PAL, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_SSAI_SECURITY] = { - .name = "SSAI Security Video Interface", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .muxsel = MUXSEL(0, 1, 2, 3), - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_SSAI_ULTRASOUND] = { - .name = "SSAI Ultrasound Video Interface", - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = 1, - .muxsel = MUXSEL(2, 0, 1, 3), - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - /* ---- card 0x94---------------------------------- */ - [BTTV_BOARD_DVICO_FUSIONHDTV_2] = { - .name = "DViCO FusionHDTV 2", - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tuner_addr = ADDR_UNSET, - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .muxsel = MUXSEL(2, 3, 1), - .gpiomask = 0x00e00007, - .gpiomux = { 0x00400005, 0, 0x00000001, 0 }, - .gpiomute = 0x00c00007, - .no_msp34xx = 1, - .no_tda7432 = 1, - }, - /* ---- card 0x95---------------------------------- */ - [BTTV_BOARD_TYPHOON_TVTUNERPCI] = { - .name = "Typhoon TV-Tuner PCI (50684)", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x3014f, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0x20001,0x10001, 0, 0 }, - .gpiomute = 10, - .pll = PLL_28, - .tuner_type = TUNER_PHILIPS_PAL_I, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GEOVISION_GV600] = { - /* emhn@usb.ve */ - .name = "Geovision GV-600", - .video_inputs = 16, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x0, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), - .muxsel_hook = geovision_muxsel, - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_KOZUMI_KTV_01C] = { - /* Mauro Lacy - * Based on MagicTV and Conceptronic CONTVFMi */ - - .name = "Kozumi KTV-01C", - .video_inputs = 3, - /* .audio_inputs= 1, */ - .svhs = 2, - .gpiomask = 0x008007, - .muxsel = MUXSEL(2, 3, 1, 1), - .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */ - .gpiomute = 3, /* CONTVFMi */ - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */ - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_ENLTV_FM_2] = { - /* Encore TV Tuner Pro ENL TV-FM-2 - Mauro Carvalho Chehab IR disabled - bit 18/17 = 00 -> mute - 01 -> enable external audio input - 10 -> internal audio input (mono?) - 11 -> internal audio input - */ - .gpiomask = 0x060040, - .muxsel = MUXSEL(2, 3, 3), - .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, - .gpiomute = 0, - .tuner_type = TUNER_TCL_MF02GIP_5N, - .tuner_addr = ADDR_UNSET, - .pll = PLL_28, - .has_radio = 1, - .has_remote = 1, - }, - [BTTV_BOARD_VD012] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0x00, - .muxsel = MUXSEL(0, 2, 3, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD012_X1] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012-X1 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(2, 3, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_VD012_X2] = { - /* D.Heer@Phytec.de */ - .name = "PHYTEC VD-012-X2 (bt878)", - .video_inputs = 4, - /* .audio_inputs= 0, */ - .svhs = 3, - .gpiomask = 0x00, - .muxsel = MUXSEL(3, 2, 1), - .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_GEOVISION_GV800S] = { - /* Bruno Christo - * - * GeoVision GV-800(S) has 4 Conexant Fusion 878A: - * 1 audio input per BT878A = 4 audio inputs - * 4 video inputs per BT878A = 16 video inputs - * This is the first BT878A chip of the GV-800(S). It's the - * "master" chip and it controls the video inputs through an - * analog multiplexer (a CD22M3494) via some GPIO pins. The - * slaves should use card type 0x9e (following this one). - * There is a EEPROM on the card which is currently not handled. - * The audio input is not working yet. - */ - .name = "Geovision GV-800(S) (master)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0xf107f, - .no_gpioirq = 1, - .muxsel = MUXSEL(2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = gv800s_muxsel, - }, - [BTTV_BOARD_GEOVISION_GV800S_SL] = { - /* Bruno Christo - * - * GeoVision GV-800(S) has 4 Conexant Fusion 878A: - * 1 audio input per BT878A = 4 audio inputs - * 4 video inputs per BT878A = 16 video inputs - * The 3 other BT878A chips are "slave" chips of the GV-800(S) - * and should use this card type. - * The audio input is not working yet. - */ - .name = "Geovision GV-800(S) (slave)", - .video_inputs = 4, - /* .audio_inputs= 1, */ - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - .svhs = NO_SVHS, - .gpiomask = 0x00, - .no_gpioirq = 1, - .muxsel = MUXSEL(2, 2, 2, 2), - .pll = PLL_28, - .no_msp34xx = 1, - .no_tda7432 = 1, - .muxsel_hook = gv800s_muxsel, - }, - [BTTV_BOARD_PV183] = { - .name = "ProVideo PV183", /* 0x9f */ - .video_inputs = 2, - /* .audio_inputs= 0, */ - .svhs = NO_SVHS, - .gpiomask = 0, - .muxsel = MUXSEL(2, 3), - .gpiomux = { 0 }, - .no_msp34xx = 1, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - .tuner_addr = ADDR_UNSET, - }, - [BTTV_BOARD_TVT_TD3116] = { - .name = "Tongwei Video Technology TD-3116", - .video_inputs = 16, - .gpiomask = 0xc00ff, - .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), - .muxsel_hook = td3116_muxsel, - .svhs = NO_SVHS, - .pll = PLL_28, - .tuner_type = TUNER_ABSENT, - }, - [BTTV_BOARD_APOSONIC_WDVR] = { - .name = "Aposonic W-DVR", - .video_inputs = 4, - .svhs = NO_SVHS, - .muxsel = MUXSEL(2, 3, 1, 0), - .tuner_type = TUNER_ABSENT, - }, - -}; - -static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); - -/* ----------------------------------------------------------------------- */ - -static unsigned char eeprom_data[256]; - -/* - * identify card - */ -void __devinit bttv_idcard(struct bttv *btv) -{ - unsigned int gpiobits; - int i,type; - - /* read PCI subsystem ID */ - btv->cardid = btv->c.pci->subsystem_device << 16; - btv->cardid |= btv->c.pci->subsystem_vendor; - - if (0 != btv->cardid && 0xffffffff != btv->cardid) { - /* look for the card */ - for (type = -1, i = 0; cards[i].id != 0; i++) - if (cards[i].id == btv->cardid) - type = i; - - if (type != -1) { - /* found it */ - pr_info("%d: detected: %s [card=%d], PCI subsystem ID is %04x:%04x\n", - btv->c.nr, cards[type].name, cards[type].cardnr, - btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - btv->c.type = cards[type].cardnr; - } else { - /* 404 */ - pr_info("%d: subsystem: %04x:%04x (UNKNOWN)\n", - btv->c.nr, btv->cardid & 0xffff, - (btv->cardid >> 16) & 0xffff); - pr_debug("please mail id, board name and the correct card= insmod option to linux-media@vger.kernel.org\n"); - } - } - - /* let the user override the autodetected type */ - if (card[btv->c.nr] < bttv_num_tvcards) - btv->c.type=card[btv->c.nr]; - - /* print which card config we are using */ - pr_info("%d: using: %s [card=%d,%s]\n", - btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type, - card[btv->c.nr] < bttv_num_tvcards - ? "insmod option" : "autodetected"); - - /* overwrite gpio stuff ?? */ - if (UNSET == audioall && UNSET == audiomux[0]) - return; - - if (UNSET != audiomux[0]) { - gpiobits = 0; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; - gpiobits |= audiomux[i]; - } - } else { - gpiobits = audioall; - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - bttv_tvcards[btv->c.type].gpiomux[i] = audioall; - } - } - bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; - pr_info("%d: gpio config override: mask=0x%x, mux=", - btv->c.nr, bttv_tvcards[btv->c.type].gpiomask); - for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { - pr_cont("%s0x%x", - i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); - } - pr_cont("\n"); -} - -/* - * (most) board specific initialisations goes here - */ - -/* Some Modular Technology cards have an eeprom, but no subsystem ID */ -static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) -{ - int type = -1; - - if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13)) - type = BTTV_BOARD_MODTEC_205; - else if (0 == strncmp(eeprom_data+20,"Picolo",7)) - type = BTTV_BOARD_EURESYS_PICOLO; - else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0) - type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */ - - if (-1 != type) { - btv->c.type = type; - pr_info("%d: detected by eeprom: %s [card=%d]\n", - btv->c.nr, bttv_tvcards[btv->c.type].name, btv->c.type); - } -} - -static void flyvideo_gpio(struct bttv *btv) -{ - int gpio, has_remote, has_radio, is_capture_only; - int is_lr90, has_tda9820_tda9821; - int tuner_type = UNSET, ttype; - - gpio_inout(0xffffff, 0); - udelay(8); /* without this we would see the 0x1800 mask */ - gpio = gpio_read(); - /* FIXME: must restore OUR_EN ??? */ - - /* all cards provide GPIO info, some have an additional eeprom - * LR50: GPIO coding can be found lower right CP1 .. CP9 - * CP9=GPIO23 .. CP1=GPIO15; when OPEN, the corresponding GPIO reads 1. - * GPIO14-12: n.c. - * LR90: GP9=GPIO23 .. GP1=GPIO15 (right above the bt878) - - * lowest 3 bytes are remote control codes (no handshake needed) - * xxxFFF: No remote control chip soldered - * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered - * Note: Some bits are Audio_Mask ! - */ - ttype = (gpio & 0x0f0000) >> 16; - switch (ttype) { - case 0x0: - tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ - break; - case 0x2: - tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ - break; - case 0x4: - tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ - break; - case 0x6: - tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ - break; - case 0xC: - tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ - break; - default: - pr_info("%d: FlyVideo_gpio: unknown tuner type\n", btv->c.nr); - break; - } - - has_remote = gpio & 0x800000; - has_radio = gpio & 0x400000; - /* unknown 0x200000; - * unknown2 0x100000; */ - is_capture_only = !(gpio & 0x008000); /* GPIO15 */ - has_tda9820_tda9821 = !(gpio & 0x004000); - is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */ - /* - * gpio & 0x001000 output bit for audio routing */ - - if (is_capture_only) - tuner_type = TUNER_ABSENT; /* No tuner present */ - - pr_info("%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio ? "yes" : "no", - has_remote ? "yes" : "no", tuner_type, gpio); - pr_info("%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90 ? "yes" : "no", - has_tda9820_tda9821 ? "yes" : "no", - is_capture_only ? "yes" : "no"); - - if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ - btv->tuner_type = tuner_type; - btv->has_radio = has_radio; - - /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 - * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 - * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if (has_tda9820_tda9821) - btv->audio_mode_gpio = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ -} - -static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, - 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; -static int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, - 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 }; - -static void miro_pinnacle_gpio(struct bttv *btv) -{ - int id,msp,gpio; - char *info; - - gpio_inout(0xffffff, 0); - gpio = gpio_read(); - id = ((gpio>>10) & 63) -1; - msp = bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx"); - if (id < 32) { - btv->tuner_type = miro_tunermap[id]; - if (0 == (gpio & 0x20)) { - btv->has_radio = 1; - if (!miro_fmtuner[id]) { - btv->has_matchbox = 1; - btv->mbox_we = (1<<6); - btv->mbox_most = (1<<7); - btv->mbox_clk = (1<<8); - btv->mbox_data = (1<<9); - btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); - } - } else { - btv->has_radio = 0; - } - if (-1 != msp) { - if (btv->c.type == BTTV_BOARD_MIRO) - btv->c.type = BTTV_BOARD_MIROPRO; - if (btv->c.type == BTTV_BOARD_PINNACLE) - btv->c.type = BTTV_BOARD_PINNACLEPRO; - } - pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->c.nr, id+1, btv->tuner_type, - !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), - (-1 == msp) ? "no" : "yes"); - } else { - /* new cards with microtune tuner */ - id = 63 - id; - btv->has_radio = 0; - switch (id) { - case 1: - info = "PAL / mono"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 2: - info = "PAL+SECAM / stereo"; - btv->has_radio = 1; - btv->tda9887_conf = TDA9887_QSS; - break; - case 3: - info = "NTSC / stereo"; - btv->has_radio = 1; - btv->tda9887_conf = TDA9887_QSS; - break; - case 4: - info = "PAL+SECAM / mono"; - btv->tda9887_conf = TDA9887_QSS; - break; - case 5: - info = "NTSC / mono"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 6: - info = "NTSC / stereo"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - case 7: - info = "PAL / stereo"; - btv->tda9887_conf = TDA9887_INTERCARRIER; - break; - default: - info = "oops: unknown card"; - break; - } - if (-1 != msp) - btv->c.type = BTTV_BOARD_PINNACLEPRO; - pr_info("%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", - btv->c.nr, id, info, btv->has_radio ? "yes" : "no"); - btv->tuner_type = TUNER_MT2032; - } -} - -/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */ -#define LM1882_SYNC_DRIVE 0x200000L - -static void init_ids_eagle(struct bttv *btv) -{ - gpio_inout(0xffffff,0xFFFF37); - gpio_write(0x200020); - - /* flash strobe inverter ?! */ - gpio_write(0x200024); - - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); - - /* set BT848 muxel to 2 */ - btaor((2)<<5, ~(2<<5), BT848_IFORM); -} - -/* Muxsel helper for the IDS Eagle. - * the eagles does not use the standard muxsel-bits but - * has its own multiplexer */ -static void eagle_muxsel(struct bttv *btv, unsigned int input) -{ - gpio_bits(3, input & 3); - - /* composite */ - /* set chroma ADC to sleep */ - btor(BT848_ADC_C_SLEEP, BT848_ADC); - /* set to composite video */ - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - - /* switch sync drive off */ - gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE); -} - -static void gvc1100_muxsel(struct bttv *btv, unsigned int input) -{ - static const int masks[] = {0x30, 0x01, 0x12, 0x23}; - gpio_write(masks[input%4]); -} - -/* LMLBT4x initialization - to allow access to GPIO bits for sensors input and - alarms output - - GPIObit | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - assignment | TI | O3|INx| O2| O1|IN4|IN3|IN2|IN1| | | - - IN - sensor inputs, INx - sensor inputs and TI XORed together - O1,O2,O3 - alarm outputs (relays) - - OUT ENABLE 1 1 0 . 1 1 0 0 . 0 0 0 0 = 0x6C0 - -*/ - -static void init_lmlbt4x(struct bttv *btv) -{ - pr_debug("LMLBT4x init\n"); - btwrite(0x000000, BT848_GPIO_REG_INP); - gpio_inout(0xffffff, 0x0006C0); - gpio_write(0x000000); -} - -static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 8; - gpio_inout( 0xf, 0xf ); - gpio_bits( 0xf, inmux ); -} - -static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 4; - gpio_inout( 3<<9, 3<<9 ); - gpio_bits( 3<<9, inmux<<9 ); -} - -static void geovision_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int inmux = input % 16; - gpio_inout(0xf, 0xf); - gpio_bits(0xf, inmux); -} - -/* - * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878. - * The first 74HC4051 has the lower 8 inputs, the second one the higher 8. - * The muxes are controlled via a 74HC373 latch which is connected to - * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch. - * Q0 of the latch is connected to the Enable (~E) input of the first - * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051. - * Q4 - Q7 are connected to the second 74HC4051 in the same way. - */ - -static void td3116_latch_value(struct bttv *btv, u32 value) -{ - gpio_bits((1<<18) | 0xff, value); - gpio_bits((1<<18) | 0xff, (1<<18) | value); - udelay(1); - gpio_bits((1<<18) | 0xff, value); -} - -static void td3116_muxsel(struct bttv *btv, unsigned int input) -{ - u32 value; - u32 highbit; - - highbit = (input & 0x8) >> 3 ; - - /* Disable outputs and set value in the mux */ - value = 0x11; /* Disable outputs */ - value |= ((input & 0x7) << 1) << (4 * highbit); - td3116_latch_value(btv, value); - - /* Enable the correct output */ - value &= ~0x11; - value |= ((highbit ^ 0x1) << 4) | highbit; - td3116_latch_value(btv, value); -} - -/* ----------------------------------------------------------------------- */ - -static void bttv_reset_audio(struct bttv *btv) -{ - /* - * BT878A has a audio-reset register. - * 1. This register is an audio reset function but it is in - * function-0 (video capture) address space. - * 2. It is enough to do this once per power-up of the card. - * 3. There is a typo in the Conexant doc -- it is not at - * 0x5B, but at 0x058. (B is an odd-number, obviously a typo!). - * --//Shrikumar 030609 - */ - if (btv->id != 878) - return; - - if (bttv_debug) - pr_debug("%d: BT878A ARESET\n", btv->c.nr); - btwrite((1<<7), 0x058); - udelay(10); - btwrite( 0, 0x058); -} - -/* initialization part one -- before registering i2c bus */ -void __devinit bttv_init_card1(struct bttv *btv) -{ - switch (btv->c.type) { - case BTTV_BOARD_HAUPPAUGE: - case BTTV_BOARD_HAUPPAUGE878: - boot_msp34xx(btv,5); - break; - case BTTV_BOARD_VOODOOTV_200: - case BTTV_BOARD_VOODOOTV_FM: - boot_msp34xx(btv,20); - break; - case BTTV_BOARD_AVERMEDIA98: - boot_msp34xx(btv,11); - break; - case BTTV_BOARD_HAUPPAUGEPVR: - pvr_boot(btv); - break; - case BTTV_BOARD_TWINHAN_DST: - case BTTV_BOARD_AVDVBT_771: - case BTTV_BOARD_PINNACLESAT: - btv->use_i2c_hw = 1; - break; - case BTTV_BOARD_ADLINK_RTV24: - init_RTV24( btv ); - break; - - } - if (!bttv_tvcards[btv->c.type].has_dvb) - bttv_reset_audio(btv); -} - -/* initialization part two -- after registering i2c bus */ -void __devinit bttv_init_card2(struct bttv *btv) -{ - btv->tuner_type = UNSET; - - if (BTTV_BOARD_UNKNOWN == btv->c.type) { - bttv_readee(btv,eeprom_data,0xa0); - identify_by_eeprom(btv,eeprom_data); - } - - switch (btv->c.type) { - case BTTV_BOARD_MIRO: - case BTTV_BOARD_MIROPRO: - case BTTV_BOARD_PINNACLE: - case BTTV_BOARD_PINNACLEPRO: - /* miro/pinnacle */ - miro_pinnacle_gpio(btv); - break; - case BTTV_BOARD_FLYVIDEO_98: - case BTTV_BOARD_MAXI: - case BTTV_BOARD_LIFE_FLYKIT: - case BTTV_BOARD_FLYVIDEO: - case BTTV_BOARD_TYPHOON_TVIEW: - case BTTV_BOARD_CHRONOS_VS2: - case BTTV_BOARD_FLYVIDEO_98FM: - case BTTV_BOARD_FLYVIDEO2000: - case BTTV_BOARD_FLYVIDEO98EZ: - case BTTV_BOARD_CONFERENCETV: - case BTTV_BOARD_LIFETEC_9415: - flyvideo_gpio(btv); - break; - case BTTV_BOARD_HAUPPAUGE: - case BTTV_BOARD_HAUPPAUGE878: - case BTTV_BOARD_HAUPPAUGEPVR: - /* pick up some config infos from the eeprom */ - bttv_readee(btv,eeprom_data,0xa0); - hauppauge_eeprom(btv); - break; - case BTTV_BOARD_AVERMEDIA98: - case BTTV_BOARD_AVPHONE98: - bttv_readee(btv,eeprom_data,0xa0); - avermedia_eeprom(btv); - break; - case BTTV_BOARD_PXC200: - init_PXC200(btv); - break; - case BTTV_BOARD_PICOLO_TETRA_CHIP: - picolo_tetra_init(btv); - break; - case BTTV_BOARD_VHX: - btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x20; - btv->mbox_most = 0; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x10; - btv->mbox_mask = 0x38; - break; - case BTTV_BOARD_VOBIS_BOOSTAR: - case BTTV_BOARD_TERRATV: - terratec_active_radio_upgrade(btv); - break; - case BTTV_BOARD_MAGICTVIEW061: - if (btv->cardid == 0x3002144f) { - btv->has_radio=1; - pr_info("%d: radio detected by subsystem id (CPH05x)\n", - btv->c.nr); - } - break; - case BTTV_BOARD_STB2: - if (btv->cardid == 0x3060121a) { - /* Fix up entry for 3DFX VoodooTV 100, - which is an OEM STB card variant. */ - btv->has_radio=0; - btv->tuner_type=TUNER_TEMIC_NTSC; - } - break; - case BTTV_BOARD_OSPREY1x0: - case BTTV_BOARD_OSPREY1x0_848: - case BTTV_BOARD_OSPREY101_848: - case BTTV_BOARD_OSPREY1x1: - case BTTV_BOARD_OSPREY1x1_SVID: - case BTTV_BOARD_OSPREY2xx: - case BTTV_BOARD_OSPREY2x0_SVID: - case BTTV_BOARD_OSPREY2x0: - case BTTV_BOARD_OSPREY440: - case BTTV_BOARD_OSPREY500: - case BTTV_BOARD_OSPREY540: - case BTTV_BOARD_OSPREY2000: - bttv_readee(btv,eeprom_data,0xa0); - osprey_eeprom(btv, eeprom_data); - break; - case BTTV_BOARD_IDS_EAGLE: - init_ids_eagle(btv); - break; - case BTTV_BOARD_MODTEC_205: - bttv_readee(btv,eeprom_data,0xa0); - modtec_eeprom(btv); - break; - case BTTV_BOARD_LMLBT4: - init_lmlbt4x(btv); - break; - case BTTV_BOARD_TIBET_CS16: - tibetCS16_init(btv); - break; - case BTTV_BOARD_KODICOM_4400R: - kodicom4400r_init(btv); - break; - case BTTV_BOARD_GEOVISION_GV800S: - gv800s_init(btv); - break; - } - - /* pll configuration */ - if (!(btv->id==848 && btv->revision==0x11)) { - /* defaults from card list */ - if (PLL_28 == bttv_tvcards[btv->c.type].pll) { - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - if (PLL_35 == bttv_tvcards[btv->c.type].pll) { - btv->pll.pll_ifreq=35468950; - btv->pll.pll_crystal=BT848_IFORM_XT1; - } - /* insmod options can override */ - switch (pll[btv->c.nr]) { - case 0: /* none */ - btv->pll.pll_crystal = 0; - btv->pll.pll_ifreq = 0; - btv->pll.pll_ofreq = 0; - break; - case 1: /* 28 MHz */ - case 28: - btv->pll.pll_ifreq = 28636363; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal = BT848_IFORM_XT0; - break; - case 2: /* 35 MHz */ - case 35: - btv->pll.pll_ifreq = 35468950; - btv->pll.pll_ofreq = 0; - btv->pll.pll_crystal = BT848_IFORM_XT1; - break; - } - } - btv->pll.pll_current = -1; - - /* tuner configuration (from card list / autodetect / insmod option) */ - if (UNSET != bttv_tvcards[btv->c.type].tuner_type) - if (UNSET == btv->tuner_type) - btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type; - if (UNSET != tuner[btv->c.nr]) - btv->tuner_type = tuner[btv->c.nr]; - - if (btv->tuner_type == TUNER_ABSENT) - pr_info("%d: tuner absent\n", btv->c.nr); - else if (btv->tuner_type == UNSET) - pr_warn("%d: tuner type unset\n", btv->c.nr); - else - pr_info("%d: tuner type=%d\n", btv->c.nr, btv->tuner_type); - - if (autoload != UNSET) { - pr_warn("%d: the autoload option is obsolete\n", btv->c.nr); - pr_warn("%d: use option msp3400, tda7432 or tvaudio to override which audio module should be used\n", - btv->c.nr); - } - - if (UNSET == btv->tuner_type) - btv->tuner_type = TUNER_ABSENT; - - btv->dig = bttv_tvcards[btv->c.type].has_dig_in ? - bttv_tvcards[btv->c.type].video_inputs - 1 : UNSET; - btv->svhs = bttv_tvcards[btv->c.type].svhs == NO_SVHS ? - UNSET : bttv_tvcards[btv->c.type].svhs; - if (svhs[btv->c.nr] != UNSET) - btv->svhs = svhs[btv->c.nr]; - if (remote[btv->c.nr] != UNSET) - btv->has_remote = remote[btv->c.nr]; - - if (bttv_tvcards[btv->c.type].has_radio) - btv->has_radio = 1; - if (bttv_tvcards[btv->c.type].has_remote) - btv->has_remote = 1; - if (!bttv_tvcards[btv->c.type].no_gpioirq) - btv->gpioirq = 1; - if (bttv_tvcards[btv->c.type].volume_gpio) - btv->volume_gpio = bttv_tvcards[btv->c.type].volume_gpio; - if (bttv_tvcards[btv->c.type].audio_mode_gpio) - btv->audio_mode_gpio = bttv_tvcards[btv->c.type].audio_mode_gpio; - - if (btv->tuner_type == TUNER_ABSENT) - return; /* no tuner or related drivers to load */ - - if (btv->has_saa6588 || saa6588[btv->c.nr]) { - /* Probe for RDS receiver chip */ - static const unsigned short addrs[] = { - 0x20 >> 1, - 0x22 >> 1, - I2C_CLIENT_END - }; - struct v4l2_subdev *sd; - - sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "saa6588", 0, addrs); - btv->has_saa6588 = (sd != NULL); - } - - /* try to detect audio/fader chips */ - - /* First check if the user specified the audio chip via a module - option. */ - - switch (audiodev[btv->c.nr]) { - case -1: - return; /* do not load any audio module */ - - case 0: /* autodetect */ - break; - - case 1: { - /* The user specified that we should probe for msp3400 */ - static const unsigned short addrs[] = { - I2C_ADDR_MSP3400 >> 1, - I2C_ADDR_MSP3400_ALT >> 1, - I2C_CLIENT_END - }; - - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", 0, addrs); - if (btv->sd_msp34xx) - return; - goto no_audio; - } - - case 2: { - /* The user specified that we should probe for tda7432 */ - static const unsigned short addrs[] = { - I2C_ADDR_TDA7432 >> 1, - I2C_CLIENT_END - }; - - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) - return; - goto no_audio; - } - - case 3: { - /* The user specified that we should probe for tvaudio */ - btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); - if (btv->sd_tvaudio) - return; - goto no_audio; - } - - default: - pr_warn("%d: unknown audiodev value!\n", btv->c.nr); - return; - } - - /* There were no overrides, so now we try to discover this through the - card definition */ - - /* probe for msp3400 first: this driver can detect whether or not - it really is a msp3400, so it will return NULL when the device - found is really something else (e.g. a tea6300). */ - if (!bttv_tvcards[btv->c.type].no_msp34xx) { - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", - 0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1)); - } else if (bttv_tvcards[btv->c.type].msp34xx_alt) { - btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "msp3400", - 0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1)); - } - - /* If we found a msp34xx, then we're done. */ - if (btv->sd_msp34xx) - return; - - /* it might also be a tda7432. */ - if (!bttv_tvcards[btv->c.type].no_tda7432) { - static const unsigned short addrs[] = { - I2C_ADDR_TDA7432 >> 1, - I2C_CLIENT_END - }; - - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) - return; - } - - /* Now see if we can find one of the tvaudio devices. */ - btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); - if (btv->sd_tvaudio) - return; - -no_audio: - pr_warn("%d: audio absent, no audio device found!\n", btv->c.nr); -} - - -/* initialize the tuner */ -void __devinit bttv_init_tuner(struct bttv *btv) -{ - int addr = ADDR_UNSET; - - if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr) - addr = bttv_tvcards[btv->c.type].tuner_addr; - - if (btv->tuner_type != TUNER_ABSENT) { - struct tuner_setup tun_setup; - - /* Load tuner module before issuing tuner config call! */ - if (btv->has_radio) - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = btv->tuner_type; - tun_setup.addr = addr; - - if (btv->has_radio) - tun_setup.mode_mask |= T_RADIO; - - bttv_call_all(btv, tuner, s_type_addr, &tun_setup); - } - - if (btv->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &btv->tda9887_conf; - - bttv_call_all(btv, tuner, s_config, &tda9887_cfg); - } -} - -/* ----------------------------------------------------------------------- */ - -static void modtec_eeprom(struct bttv *btv) -{ - if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) { - btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I; - pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr, &eeprom_data[0x1e]); - } else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) { - btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I; - pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr, &eeprom_data[0x1e]); - } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) { - btv->tuner_type=TUNER_PHILIPS_NTSC; - pr_info("%d: Modtec: Tuner autodetected by eeprom: %s\n", - btv->c.nr, &eeprom_data[0x1e]); - } else { - pr_info("%d: Modtec: Unknown TunerString: %s\n", - btv->c.nr, &eeprom_data[0x1e]); - } -} - -static void __devinit hauppauge_eeprom(struct bttv *btv) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); - btv->tuner_type = tv.tuner_type; - btv->has_radio = tv.has_radio; - - pr_info("%d: Hauppauge eeprom indicates model#%d\n", - btv->c.nr, tv.model); - - /* - * Some of the 878 boards have duplicate PCI IDs. Switch the board - * type based on model #. - */ - if(tv.model == 64900) { - pr_info("%d: Switching board type from %s to %s\n", - btv->c.nr, - bttv_tvcards[btv->c.type].name, - bttv_tvcards[BTTV_BOARD_HAUPPAUGE_IMPACTVCB].name); - btv->c.type = BTTV_BOARD_HAUPPAUGE_IMPACTVCB; - } - - /* The 61334 needs the msp3410 to do the radio demod to get sound */ - if (tv.model == 61334) - btv->radio_uses_msp_demodulator = 1; -} - -static int terratec_active_radio_upgrade(struct bttv *btv) -{ - int freq; - - btv->has_radio = 1; - btv->has_matchbox = 1; - btv->mbox_we = 0x10; - btv->mbox_most = 0x20; - btv->mbox_clk = 0x08; - btv->mbox_data = 0x04; - btv->mbox_mask = 0x3c; - - btv->mbox_iow = 1 << 8; - btv->mbox_ior = 1 << 9; - btv->mbox_csel = 1 << 10; - - freq=88000/62.5; - tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */ - if (0x1ed8 == tea5757_read(btv)) { - pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr); - btv->has_radio = 1; - btv->has_saa6588 = 1; - btv->has_matchbox = 1; - } else { - btv->has_radio = 0; - btv->has_matchbox = 0; - } - return 0; -} - - -/* ----------------------------------------------------------------------- */ - -/* - * minimal bootstrap for the WinTV/PVR -- upload altera firmware. - * - * The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have - * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be - * unpacked with unzip). - */ -#define PVR_GPIO_DELAY 10 - -#define BTTV_ALT_DATA 0x000001 -#define BTTV_ALT_DCLK 0x100000 -#define BTTV_ALT_NCONFIG 0x800000 - -static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro, - u32 microlen) -{ - u32 n; - u8 bits; - int i; - - gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG); - gpio_write(0); - udelay(PVR_GPIO_DELAY); - - gpio_write(BTTV_ALT_NCONFIG); - udelay(PVR_GPIO_DELAY); - - for (n = 0; n < microlen; n++) { - bits = micro[n]; - for (i = 0 ; i < 8 ; i++) { - gpio_bits(BTTV_ALT_DCLK,0); - if (bits & 0x01) - gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); - else - gpio_bits(BTTV_ALT_DATA,0); - gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); - bits >>= 1; - } - } - gpio_bits(BTTV_ALT_DCLK,0); - udelay(PVR_GPIO_DELAY); - - /* begin Altera init loop (Not necessary,but doesn't hurt) */ - for (i = 0 ; i < 30 ; i++) { - gpio_bits(BTTV_ALT_DCLK,0); - gpio_bits(BTTV_ALT_DCLK,BTTV_ALT_DCLK); - } - gpio_bits(BTTV_ALT_DCLK,0); - return 0; -} - -static int __devinit pvr_boot(struct bttv *btv) -{ - const struct firmware *fw_entry; - int rc; - - rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev); - if (rc != 0) { - pr_warn("%d: no altera firmware [via hotplug]\n", btv->c.nr); - return rc; - } - rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size); - pr_info("%d: altera firmware upload %s\n", - btv->c.nr, (rc < 0) ? "failed" : "ok"); - release_firmware(fw_entry); - return rc; -} - -/* ----------------------------------------------------------------------- */ -/* some osprey specific stuff */ - -static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) -{ - int i; - u32 serial = 0; - int cardid = -1; - - /* This code will nevery actually get called in this case.... */ - if (btv->c.type == BTTV_BOARD_UNKNOWN) { - /* this might be an antique... check for MMAC label in eeprom */ - if (!strncmp(ee, "MMAC", 4)) { - u8 checksum = 0; - for (i = 0; i < 21; i++) - checksum += ee[i]; - if (checksum != ee[21]) - return; - cardid = BTTV_BOARD_OSPREY1x0_848; - for (i = 12; i < 21; i++) - serial *= 10, serial += ee[i] - '0'; - } - } else { - unsigned short type; - - for (i = 4*16; i < 8*16; i += 16) { - u16 checksum = ip_compute_csum(ee + i, 16); - - if ((checksum&0xff) + (checksum>>8) == 0xff) - break; - } - if (i >= 8*16) - return; - ee += i; - - /* found a valid descriptor */ - type = get_unaligned_be16((__be16 *)(ee+4)); - - switch(type) { - /* 848 based */ - case 0x0004: - cardid = BTTV_BOARD_OSPREY1x0_848; - break; - case 0x0005: - cardid = BTTV_BOARD_OSPREY101_848; - break; - - /* 878 based */ - case 0x0012: - case 0x0013: - cardid = BTTV_BOARD_OSPREY1x0; - break; - case 0x0014: - case 0x0015: - cardid = BTTV_BOARD_OSPREY1x1; - break; - case 0x0016: - case 0x0017: - case 0x0020: - cardid = BTTV_BOARD_OSPREY1x1_SVID; - break; - case 0x0018: - case 0x0019: - case 0x001E: - case 0x001F: - cardid = BTTV_BOARD_OSPREY2xx; - break; - case 0x001A: - case 0x001B: - cardid = BTTV_BOARD_OSPREY2x0_SVID; - break; - case 0x0040: - cardid = BTTV_BOARD_OSPREY500; - break; - case 0x0050: - case 0x0056: - cardid = BTTV_BOARD_OSPREY540; - /* bttv_osprey_540_init(btv); */ - break; - case 0x0060: - case 0x0070: - case 0x00A0: - cardid = BTTV_BOARD_OSPREY2x0; - /* enable output on select control lines */ - gpio_inout(0xffffff,0x000303); - break; - case 0x00D8: - cardid = BTTV_BOARD_OSPREY440; - break; - default: - /* unknown...leave generic, but get serial # */ - pr_info("%d: osprey eeprom: unknown card type 0x%04x\n", - btv->c.nr, type); - break; - } - serial = get_unaligned_be32((__be32 *)(ee+6)); - } - - pr_info("%d: osprey eeprom: card=%d '%s' serial=%u\n", - btv->c.nr, cardid, - cardid > 0 ? bttv_tvcards[cardid].name : "Unknown", serial); - - if (cardid<0 || btv->c.type == cardid) - return; - - /* card type isn't set correctly */ - if (card[btv->c.nr] < bttv_num_tvcards) { - pr_warn("%d: osprey eeprom: Not overriding user specified card type\n", - btv->c.nr); - } else { - pr_info("%d: osprey eeprom: Changing card type from %d to %d\n", - btv->c.nr, btv->c.type, cardid); - btv->c.type = cardid; - } -} - -/* ----------------------------------------------------------------------- */ -/* AVermedia specific stuff, from bktr_card.c */ - -static int tuner_0_table[] = { - TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/, - TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/, - TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL, - TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM, - TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL, - TUNER_PHILIPS_FM1216ME_MK3 }; - -static int tuner_1_table[] = { - TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL, - TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_PAL, TUNER_TEMIC_PAL, - TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */ - TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL}; - -static void __devinit avermedia_eeprom(struct bttv *btv) -{ - int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; - - tuner_make = (eeprom_data[0x41] & 0x7); - tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; - tuner_format = (eeprom_data[0x42] & 0xf0) >> 4; - btv->has_remote = (eeprom_data[0x42] & 0x01); - - if (tuner_make == 0 || tuner_make == 2) - if (tuner_format <= 0x0a) - tuner_type = tuner_0_table[tuner_format]; - if (tuner_make == 1) - if (tuner_format <= 9) - tuner_type = tuner_1_table[tuner_format]; - - if (tuner_make == 4) - if (tuner_format == 0x09) - tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ - - pr_info("%d: Avermedia eeprom[0x%02x%02x]: tuner=", - btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); - if (tuner_type) { - btv->tuner_type = tuner_type; - pr_cont("%d", tuner_type); - } else - pr_cont("Unknown type"); - pr_cont(" radio:%s remote control:%s\n", - tuner_tv_fm ? "yes" : "no", - btv->has_remote ? "yes" : "no"); -} - -/* - * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880 - * analog demod, which is not I2C controlled like the newer and more common - * TDA9887 series. Instead is has two tri-state input pins, S0 and S1, - * that control the IF for the video and audio. Apparently, bttv GPIO - * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I - * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC). - */ -u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits) -{ - - if (btv->audio == TVAUDIO_INPUT_TUNER) { - if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN) - gpiobits |= 0x10000; - else - gpiobits &= ~0x10000; - } - - gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpiobits); - return gpiobits; -} - - -/* - * reset/enable the MSP on some Hauppauge cards - * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! - * - * Hauppauge: pin 5 - * Voodoo: pin 20 - */ -static void __devinit boot_msp34xx(struct bttv *btv, int pin) -{ - int mask = (1 << pin); - - gpio_inout(mask,mask); - gpio_bits(mask,0); - mdelay(2); - udelay(500); - gpio_bits(mask,mask); - - if (bttv_gpio) - bttv_gpio_tracking(btv,"msp34xx"); - if (bttv_verbose) - pr_info("%d: Hauppauge/Voodoo msp34xx: reset line init [%d]\n", - btv->c.nr, pin); -} - -/* ----------------------------------------------------------------------- */ -/* 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 int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x00 }; - unsigned int i; - int tmp; - u32 val; - - /* Initialise GPIO-connevted stuff */ - gpio_inout(0xffffff, (1<<13)); - gpio_write(0); - udelay(3); - gpio_write(1<<13); - /* GPIO inputs are pulled up, so no need to drive - * reset pin any longer */ - gpio_bits(0xffffff, 0); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pxc200"); - - /* 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 */ - pr_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 */ - - - pr_info("Initialising 12C508 PIC chip ...\n"); - - /* First of all, enable the clock line. This is used in the PXC200-F */ - val = btread(BT848_GPIO_DMA_CTL); - val |= BT848_GPIO_DMA_CTL_GPCLKMODE; - btwrite(val, BT848_GPIO_DMA_CTL); - - /* Then, push to 0 the reset pin long enough to reset the * - * device same as above for the reset line, but not the same - * value sent to the GPIO-connected stuff - * which one is the good one? */ - gpio_inout(0xffffff,(1<<2)); - gpio_write(0); - udelay(10); - gpio_write(1<<2); - - for (i = 0; i < ARRAY_SIZE(vals); i++) { - tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1); - if (tmp != -1) { - pr_info("I2C Write(%2.2x) = %i\nI2C Read () = %2.2x\n\n", - vals[i],tmp,bttv_I2CRead(btv,0x1F,NULL)); - } - } - - pr_info("PXC200 Initialised\n"); -} - - - -/* ----------------------------------------------------------------------- */ -/* - * The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock - * it. This apparently involves the following procedure for each 878 chip: - * - * 1) write 0x00C3FEFF to the GPIO_OUT_EN register - * - * 2) write to GPIO_DATA - * - 0x0E - * - sleep 1ms - * - 0x10 + 0x0E - * - sleep 10ms - * - 0x0E - * read from GPIO_DATA into buf (uint_32) - * - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 ) - * error. ERROR_CPLD_Check_Failed stop. - * - * 3) write to GPIO_DATA - * - write 0x4400 + 0x0E - * - sleep 10ms - * - write 0x4410 + 0x0E - * - sleep 1ms - * - write 0x0E - * read from GPIO_DATA into buf (uint_32) - * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) - * error. ERROR_CPLD_Check_Failed. - */ -/* ----------------------------------------------------------------------- */ -static void -init_RTV24 (struct bttv *btv) -{ - uint32_t dataRead = 0; - long watchdog_value = 0x0E; - - pr_info("%d: Adlink RTV-24 initialisation in progress ...\n", - btv->c.nr); - - btwrite (0x00c3feff, BT848_GPIO_OUT_EN); - - btwrite (0 + watchdog_value, BT848_GPIO_DATA); - msleep (1); - btwrite (0x10 + watchdog_value, BT848_GPIO_DATA); - msleep (10); - btwrite (0 + watchdog_value, BT848_GPIO_DATA); - - dataRead = btread (BT848_GPIO_DATA); - - if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) { - pr_info("%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n", - btv->c.nr, dataRead); - } - - btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA); - msleep (10); - btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA); - msleep (1); - btwrite (watchdog_value, BT848_GPIO_DATA); - msleep (1); - dataRead = btread (BT848_GPIO_DATA); - - if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) { - pr_info("%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n", - btv->c.nr, dataRead); - - return; - } - - pr_info("%d: Adlink RTV-24 initialisation complete\n", btv->c.nr); -} - - - -/* ----------------------------------------------------------------------- */ -/* 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 - */ - -static void bus_low(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,0); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static void bus_high(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - gpio_bits(bit,bit); - udelay(5); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } -} - -static int bus_in(struct bttv *btv, int bit) -{ - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - - gpio_bits(btv->mbox_iow | btv->mbox_csel, 0); - udelay(5); - } - return gpio_read() & (bit); -} - -/* 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 tea5757_read(struct bttv *btv) -{ - unsigned long timeout; - int value = 0; - int i; - - /* better safe than sorry */ - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 read"); - - bus_low(btv,btv->mbox_we); - bus_low(btv,btv->mbox_clk); - - udelay(10); - timeout= jiffies + msecs_to_jiffies(1000); - - /* wait for DATA line to go low; error if it doesn't */ - while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) - schedule(); - if (bus_in(btv,btv->mbox_data)) { - pr_warn("%d: tea5757: read timeout\n", btv->c.nr); - return -1; - } - - dprintk("%d: tea5757:", btv->c.nr); - for (i = 0; i < 24; i++) { - udelay(5); - bus_high(btv,btv->mbox_clk); - udelay(5); - dprintk_cont("%c", - bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-'); - bus_low(btv,btv->mbox_clk); - value <<= 1; - value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk_cont("%c", - bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M'); - } - dprintk_cont("\n"); - dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value); - return value; -} - -static int tea5757_write(struct bttv *btv, int value) -{ - int i; - int reg = value; - - gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data); - - if (btv->mbox_ior) { - gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, - btv->mbox_ior | btv->mbox_iow | btv->mbox_csel); - udelay(5); - } - if (bttv_gpio) - bttv_gpio_tracking(btv,"tea5757 write"); - - dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value); - bus_low(btv,btv->mbox_clk); - bus_high(btv,btv->mbox_we); - for (i = 0; i < 25; i++) { - if (reg & 0x1000000) - bus_high(btv,btv->mbox_data); - else - bus_low(btv,btv->mbox_data); - reg <<= 1; - bus_high(btv,btv->mbox_clk); - udelay(10); - bus_low(btv,btv->mbox_clk); - udelay(10); - } - bus_low(btv,btv->mbox_we); /* unmute !!! */ - return 0; -} - -void tea5757_set_freq(struct bttv *btv, unsigned short freq) -{ - dprintk("tea5757_set_freq %d\n",freq); - tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ -} - -/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] - * - * This is needed because rv605 don't use a normal multiplex, but a crosspoint - * switch instead (CD22M3494E). This IC can have multiple active connections - * between Xn (input) and Yn (output) pins. We need to clear any existing - * connection prior to establish a new one, pulsing the STROBE pin. - * - * The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin. - * GPIO pins are wired as: - * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller) - * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller) - * GPIO[7] - DATA (xpoint) - P1[7] (microcontroller) - * GPIO[8] - - P3[5] (microcontroller) - * GPIO[9] - RESET (xpoint) - P3[6] (microcontroller) - * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroller) - * GPINTR - - P3[4] (microcontroller) - * - * The microcontroller is a 80C32 like. It should be possible to change xpoint - * configuration either directly (as we are doing) or using the microcontroller - * which is also wired to I2C interface. I have no further info on the - * microcontroller features, one would need to disassembly the firmware. - * note: the vendor refused to give any information on this product, all - * that stuff was found using a multimeter! :) - */ -static void rv605_muxsel(struct bttv *btv, unsigned int input) -{ - static const u8 muxgpio[] = { 0x3, 0x1, 0x2, 0x4, 0xf, 0x7, 0xe, 0x0, - 0xd, 0xb, 0xc, 0x6, 0x9, 0x5, 0x8, 0xa }; - - gpio_bits(0x07f, muxgpio[input]); - - /* reset all conections */ - gpio_bits(0x200,0x200); - mdelay(1); - gpio_bits(0x200,0x000); - mdelay(1); - - /* create a new connection */ - gpio_bits(0x480,0x480); - mdelay(1); - gpio_bits(0x480,0x080); - mdelay(1); -} - -/* Tibet Systems 'Progress DVR' CS16 muxsel helper [Chris Fanning] - * - * The CS16 (available on eBay cheap) is a PCI board with four Fusion - * 878A chips, a PCI bridge, an Atmel microcontroller, four sync separator - * chips, ten eight input analog multiplexors, a not chip and a few - * other components. - * - * 16 inputs on a secondary bracket are provided and can be selected - * from each of the four capture chips. Two of the eight input - * multiplexors are used to select from any of the 16 input signals. - * - * Unsupported hardware capabilities: - * . A video output monitor on the secondary bracket can be selected from - * one of the 878A chips. - * . Another passthrough but I haven't spent any time investigating it. - * . Digital I/O (logic level connected to GPIO) is available from an - * onboard header. - * - * The on chip input mux should always be set to 2. - * GPIO[16:19] - Video input selection - * GPIO[0:3] - Video output monitor select (only available from one 878A) - * GPIO[?:?] - Digital I/O. - * - * There is an ATMEL microcontroller with an 8031 core on board. I have not - * determined what function (if any) it provides. With the microcontroller - * and sync separator chips a guess is that it might have to do with video - * switching and maybe some digital I/O. - */ -static void tibetCS16_muxsel(struct bttv *btv, unsigned int input) -{ - /* video mux */ - gpio_bits(0x0f0000, input << 16); -} - -static void tibetCS16_init(struct bttv *btv) -{ - /* enable gpio bits, mask obtained via btSpy */ - gpio_inout(0xffffff, 0x0f7fff); - gpio_write(0x0f7fff); -} - -/* - * The following routines for the Kodicom-4400r get a little mind-twisting. - * There is a "master" controller and three "slave" controllers, together - * an analog switch which connects any of 16 cameras to any of the BT87A's. - * The analog switch is controlled by the "master", but the detection order - * of the four BT878A chips is in an order which I just don't understand. - * The "master" is actually the second controller to be detected. The - * logic on the board uses logical numbers for the 4 controllers, but - * those numbers are different from the detection sequence. When working - * with the analog switch, we need to "map" from the detection sequence - * over to the board's logical controller number. This mapping sequence - * is {3, 0, 2, 1}, i.e. the first controller to be detected is logical - * unit 3, the second (which is the master) is logical unit 0, etc. - * We need to maintain the status of the analog switch (which of the 16 - * cameras is connected to which of the 4 controllers). Rather than - * add to the bttv structure for this, we use the data reserved for - * the mbox (unused for this card type). - */ - -/* - * First a routine to set the analog switch, which controls which camera - * is routed to which controller. The switch comprises an X-address - * (gpio bits 0-3, representing the camera, ranging from 0-15), and a - * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). - * A data value (gpio bit 7) of '1' enables the switch, and '0' disables - * the switch. A STROBE bit (gpio bit 8) latches the data value into the - * specified address. The idea is to set the address and data, then bring - * STROBE high, and finally bring STROBE back to low. - */ -static void kodicom4400r_write(struct bttv *btv, - unsigned char xaddr, - unsigned char yaddr, - unsigned char data) { - unsigned int udata; - - udata = (data << 7) | ((yaddr&3) << 4) | (xaddr&0xf); - gpio_bits(0x1ff, udata); /* write ADDR and DAT */ - gpio_bits(0x1ff, udata | (1 << 8)); /* strobe high */ - gpio_bits(0x1ff, udata); /* strobe low */ -} - -/* - * Next the mux select. Both the "master" and "slave" 'cards' (controllers) - * use this routine. The routine finds the "master" for the card, maps - * the controller number from the detected position over to the logical - * number, writes the appropriate data to the analog switch, and housekeeps - * the local copy of the switch information. The parameter 'input' is the - * requested camera number (0 - 15). - */ -static void kodicom4400r_muxsel(struct bttv *btv, unsigned int input) -{ - char *sw_status; - int xaddr, yaddr; - struct bttv *mctlr; - static unsigned char map[4] = {3, 0, 2, 1}; - - mctlr = master[btv->c.nr]; - if (mctlr == NULL) { /* ignore if master not yet detected */ - return; - } - yaddr = (btv->c.nr - mctlr->c.nr + 1) & 3; /* the '&' is for safety */ - yaddr = map[yaddr]; - sw_status = (char *)(&mctlr->mbox_we); - xaddr = input & 0xf; - /* Check if the controller/camera pair has changed, else ignore */ - if (sw_status[yaddr] != xaddr) - { - /* "open" the old switch, "close" the new one, save the new */ - kodicom4400r_write(mctlr, sw_status[yaddr], yaddr, 0); - sw_status[yaddr] = xaddr; - kodicom4400r_write(mctlr, xaddr, yaddr, 1); - } -} - -/* - * During initialisation, we need to reset the analog switch. We - * also preset the switch to map the 4 connectors on the card to the - * *user's* (see above description of kodicom4400r_muxsel) channels - * 0 through 3 - */ -static void kodicom4400r_init(struct bttv *btv) -{ - char *sw_status = (char *)(&btv->mbox_we); - int ix; - - gpio_inout(0x0003ff, 0x0003ff); - gpio_write(1 << 9); /* reset MUX */ - gpio_write(0); - /* Preset camera 0 to the 4 controllers */ - for (ix = 0; ix < 4; ix++) { - sw_status[ix] = ix; - kodicom4400r_write(btv, ix, ix, 1); - } - /* - * Since this is the "master", we need to set up the - * other three controller chips' pointers to this structure - * for later use in the muxsel routine. - */ - if ((btv->c.nr<1) || (btv->c.nr>BTTV_MAX-3)) - return; - master[btv->c.nr-1] = btv; - master[btv->c.nr] = btv; - master[btv->c.nr+1] = btv; - master[btv->c.nr+2] = btv; -} - -/* 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, - }; - gpio_write(masks[input%16]); -} -static void picolo_tetra_init(struct bttv *btv) -{ - /*This is the video input redirection fonctionality : I DID NOT USED IT. */ - btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */ - btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A] set to 1*/ -} -static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) -{ - - dprintk("%d : picolo_tetra_muxsel => input = %d\n", btv->c.nr, input); - /*Just set the right path in the analog multiplexers : channel 1 -> 4 ==> Analog Mux ==> MUX0*/ - /*GPIO[20]&GPIO[21] used to choose the right input*/ - btwrite (input<<20,BT848_GPIO_DATA); - -} - -/* - * ivc120_muxsel [Added by Alan Garfield ] - * - * The IVC120G security card has 4 i2c controlled TDA8540 matrix - * swichers to provide 16 channels to MUX0. The TDA8540's have - * 4 independent outputs and as such the IVC120G also has the - * optional "Monitor Out" bus. This allows the card to be looking - * at one input while the monitor is looking at another. - * - * Since I've couldn't be bothered figuring out how to add an - * independent muxsel for the monitor bus, I've just set it to - * whatever the card is looking at. - * - * OUT0 of the TDA8540's is connected to MUX0 (0x03) - * OUT1 of the TDA8540's is connected to "Monitor Out" (0x0C) - * - * TDA8540_ALT3 IN0-3 = Channel 13 - 16 (0x03) - * TDA8540_ALT4 IN0-3 = Channel 1 - 4 (0x03) - * TDA8540_ALT5 IN0-3 = Channel 5 - 8 (0x03) - * TDA8540_ALT6 IN0-3 = Channel 9 - 12 (0x03) - * - */ - -/* All 7 possible sub-ids for the TDA8540 Matrix Switcher */ -#define I2C_TDA8540 0x90 -#define I2C_TDA8540_ALT1 0x92 -#define I2C_TDA8540_ALT2 0x94 -#define I2C_TDA8540_ALT3 0x96 -#define I2C_TDA8540_ALT4 0x98 -#define I2C_TDA8540_ALT5 0x9a -#define I2C_TDA8540_ALT6 0x9c - -static void ivc120_muxsel(struct bttv *btv, unsigned int input) -{ - /* Simple maths */ - int key = input % 4; - int matrix = input / 4; - - dprintk("%d: ivc120_muxsel: Input - %02d | TDA - %02d | In - %02d\n", - btv->c.nr, input, matrix, key); - - /* Handles the input selection on the TDA8540's */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x00, - ((matrix == 3) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x00, - ((matrix == 0) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x00, - ((matrix == 1) ? (key | key << 2) : 0x00), 1); - bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x00, - ((matrix == 2) ? (key | key << 2) : 0x00), 1); - - /* Handles the output enables on the TDA8540's */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT3, 0x02, - ((matrix == 3) ? 0x03 : 0x00), 1); /* 13 - 16 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT4, 0x02, - ((matrix == 0) ? 0x03 : 0x00), 1); /* 1-4 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT5, 0x02, - ((matrix == 1) ? 0x03 : 0x00), 1); /* 5-8 */ - bttv_I2CWrite(btv, I2C_TDA8540_ALT6, 0x02, - ((matrix == 2) ? 0x03 : 0x00), 1); /* 9-12 */ - - /* 878's MUX0 is already selected for input via muxsel values */ -} - - -/* PXC200 muxsel helper - * luke@syseng.anu.edu.au - * another transplant - * from Alessandro Rubini (rubini@linux.it) - * - * There are 4 kinds of cards: - * PXC200L which is bt848 - * PXC200F which is bt848 with PIC controlling mux - * PXC200AL which is bt878 - * PXC200AF which is bt878 with PIC controlling mux - */ -#define PX_CFG_PXC200F 0x01 -#define PX_FLAG_PXC200A 0x00001000 /* a pxc200A is bt-878 based */ -#define PX_I2C_PIC 0x0f -#define PX_PXC200A_CARDID 0x200a1295 -#define PX_I2C_CMD_CFG 0x00 - -static void PXC200_muxsel(struct bttv *btv, unsigned int input) -{ - int rc; - long mux; - int bitmask; - unsigned char buf[2]; - - /* Read PIC config to determine if this is a PXC200F */ - /* PX_I2C_CMD_CFG*/ - buf[0]=0; - buf[1]=0; - rc=bttv_I2CWrite(btv,(PX_I2C_PIC<<1),buf[0],buf[1],1); - if (rc) { - pr_debug("%d: PXC200_muxsel: pic cfg write failed:%d\n", - btv->c.nr, rc); - /* not PXC ? do nothing */ - return; - } - - rc=bttv_I2CRead(btv,(PX_I2C_PIC<<1),NULL); - if (!(rc & PX_CFG_PXC200F)) { - pr_debug("%d: PXC200_muxsel: not PXC200F rc:%d\n", - btv->c.nr, rc); - return; - } - - - /* The multiplexer in the 200F is handled by the GPIO port */ - /* get correct mapping between inputs */ - /* mux = bttv_tvcards[btv->type].muxsel[input] & 3; */ - /* ** not needed!? */ - mux = input; - - /* make sure output pins are enabled */ - /* bitmask=0x30f; */ - bitmask=0x302; - /* check whether we have a PXC200A */ - if (btv->cardid == PX_PXC200A_CARDID) { - bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */ - bitmask |= 7<<4; /* the DAC */ - } - btwrite(bitmask, BT848_GPIO_OUT_EN); - - bitmask = btread(BT848_GPIO_DATA); - if (btv->cardid == PX_PXC200A_CARDID) - bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7); - else /* older device */ - bitmask = (bitmask & ~0x300) | ((mux & 3) << 8); - btwrite(bitmask,BT848_GPIO_DATA); - - /* - * Was "to be safe, set the bt848 to input 0" - * Actually, since it's ok at load time, better not messing - * with these bits (on PXC200AF you need to set mux 2 here) - * - * needed because bttv-driver sets mux before calling this function - */ - if (btv->cardid == PX_PXC200A_CARDID) - btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM); - else /* older device */ - btand(~BT848_IFORM_MUXSEL,BT848_IFORM); - - pr_debug("%d: setting input channel to:%d\n", btv->c.nr, (int)mux); -} - -static void phytec_muxsel(struct bttv *btv, unsigned int input) -{ - unsigned int mux = input % 4; - - if (input == btv->svhs) - mux = 0; - - gpio_bits(0x3, mux); -} - -/* - * GeoVision GV-800(S) functions - * Bruno Christo -*/ - -/* This is a function to control the analog switch, which determines which - * camera is routed to which controller. The switch comprises an X-address - * (gpio bits 0-3, representing the camera, ranging from 0-15), and a - * Y-address (gpio bits 4-6, representing the controller, ranging from 0-3). - * A data value (gpio bit 18) of '1' enables the switch, and '0' disables - * the switch. A STROBE bit (gpio bit 17) latches the data value into the - * specified address. There is also a chip select (gpio bit 16). - * The idea is to set the address and chip select together, bring - * STROBE high, write the data, and finally bring STROBE back to low. - */ -static void gv800s_write(struct bttv *btv, - unsigned char xaddr, - unsigned char yaddr, - unsigned char data) { - /* On the "master" 878A: - * GPIO bits 0-9 are used for the analog switch: - * 00 - 03: camera selector - * 04 - 06: 878A (controller) selector - * 16: cselect - * 17: strobe - * 18: data (1->on, 0->off) - * 19: reset - */ - const u32 ADDRESS = ((xaddr&0xf) | (yaddr&3)<<4); - const u32 CSELECT = 1<<16; - const u32 STROBE = 1<<17; - const u32 DATA = data<<18; - - gpio_bits(0x1007f, ADDRESS | CSELECT); /* write ADDRESS and CSELECT */ - gpio_bits(0x20000, STROBE); /* STROBE high */ - gpio_bits(0x40000, DATA); /* write DATA */ - gpio_bits(0x20000, ~STROBE); /* STROBE low */ -} - -/* - * GeoVision GV-800(S) muxsel - * - * Each of the 4 cards (controllers) use this function. - * The controller using this function selects the input through the GPIO pins - * of the "master" card. A pointer to this card is stored in master[btv->c.nr]. - * - * The parameter 'input' is the requested camera number (0-4) on the controller. - * The map array has the address of each input. Note that the addresses in the - * array are in the sequence the original GeoVision driver uses, that is, set - * every controller to input 0, then to input 1, 2, 3, repeat. This means that - * the physical "camera 1" connector corresponds to controller 0 input 0, - * "camera 2" corresponds to controller 1 input 0, and so on. - * - * After getting the input address, the function then writes the appropriate - * data to the analog switch, and housekeeps the local copy of the switch - * information. - */ -static void gv800s_muxsel(struct bttv *btv, unsigned int input) -{ - struct bttv *mctlr; - char *sw_status; - int xaddr, yaddr; - static unsigned int map[4][4] = { { 0x0, 0x4, 0xa, 0x6 }, - { 0x1, 0x5, 0xb, 0x7 }, - { 0x2, 0x8, 0xc, 0xe }, - { 0x3, 0x9, 0xd, 0xf } }; - input = input%4; - mctlr = master[btv->c.nr]; - if (mctlr == NULL) { - /* do nothing until the "master" is detected */ - return; - } - yaddr = (btv->c.nr - mctlr->c.nr) & 3; - sw_status = (char *)(&mctlr->mbox_we); - xaddr = map[yaddr][input] & 0xf; - - /* Check if the controller/camera pair has changed, ignore otherwise */ - if (sw_status[yaddr] != xaddr) { - /* disable the old switch, enable the new one and save status */ - gv800s_write(mctlr, sw_status[yaddr], yaddr, 0); - sw_status[yaddr] = xaddr; - gv800s_write(mctlr, xaddr, yaddr, 1); - } -} - -/* GeoVision GV-800(S) "master" chip init */ -static void gv800s_init(struct bttv *btv) -{ - char *sw_status = (char *)(&btv->mbox_we); - int ix; - - gpio_inout(0xf107f, 0xf107f); - gpio_write(1<<19); /* reset the analog MUX */ - gpio_write(0); - - /* Preset camera 0 to the 4 controllers */ - for (ix = 0; ix < 4; ix++) { - sw_status[ix] = ix; - gv800s_write(btv, ix, ix, 1); - } - - /* Inputs on the "master" controller need this brightness fix */ - bttv_I2CWrite(btv, 0x18, 0x5, 0x90, 1); - - if (btv->c.nr > BTTV_MAX-4) - return; - /* - * Store the "master" controller pointer in the master - * array for later use in the muxsel function. - */ - master[btv->c.nr] = btv; - master[btv->c.nr+1] = btv; - master[btv->c.nr+2] = btv; - master[btv->c.nr+3] = btv; -} - -/* ----------------------------------------------------------------------- */ -/* motherboard chipset specific stuff */ - -void __init bttv_check_chipset(void) -{ - int pcipci_fail = 0; - struct pci_dev *dev = NULL; - - if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */ - pcipci_fail = 1; - if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF)) - triton1 = 1; - if (pci_pci_problems & PCIPCI_VSFX) - vsfx = 1; -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) - latency = 0x0A; -#endif - - - /* print warnings about any quirks found */ - if (triton1) - pr_info("Host bridge needs ETBF enabled\n"); - if (vsfx) - pr_info("Host bridge needs VSFX enabled\n"); - if (pcipci_fail) { - pr_info("bttv and your chipset may not work together\n"); - if (!no_overlay) { - pr_info("overlay will be disabled\n"); - no_overlay = 1; - } else { - pr_info("overlay forced. Use this option at your own risk.\n"); - } - } - if (UNSET != latency) - pr_info("pci latency fixup [%d]\n", latency); - while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82441, dev))) { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - if (bttv_debug) - pr_info("Host bridge: 82441FX Natoma, bufcon=0x%02x\n", - b); - } -} - -int __devinit bttv_handle_chipset(struct bttv *btv) -{ - unsigned char command; - - if (!triton1 && !vsfx && UNSET == latency) - return 0; - - if (bttv_verbose) { - if (triton1) - pr_info("%d: enabling ETBF (430FX/VP3 compatibility)\n", - btv->c.nr); - if (vsfx && btv->id >= 878) - pr_info("%d: enabling VSFX\n", btv->c.nr); - if (UNSET != latency) - pr_info("%d: setting pci timer to %d\n", - btv->c.nr, latency); - } - - if (btv->id < 878) { - /* bt848 (mis)uses a bit in the irq mask for etbf */ - if (triton1) - btv->triton1 = BT848_INT_ETBF; - } else { - /* bt878 has a bit in the pci config space for it */ - pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command); - if (triton1) - command |= BT878_EN_TBFX; - if (vsfx) - command |= BT878_EN_VSFX; - pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command); - } - if (UNSET != latency) - pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency); - return 0; -} - - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c deleted file mode 100644 index b58ff87db771..000000000000 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ /dev/null @@ -1,4630 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - - Copyright (C) 1996,97,98 Ralph Metzler - & Marcus Metzler - (c) 1999-2002 Gerd Knorr - - some v4l2 code lines are taken from Justin's bttv2 driver which is - (c) 2000 Justin Schoeman - - V4L1 removal from: - (c) 2005-2006 Nickolay V. Shmyrev - - Fixes to be fully V4L2 compliant by - (c) 2006 Mauro Carvalho Chehab - - Cropping and overscan support - Copyright (C) 2005, 2006 Michael H. Schimek - Sponsored by OPQ Systems AB - - 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bttvp.h" -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#define BTTV_VERSION "0.9.19" - -unsigned int bttv_num; /* number of Bt848s in use */ -struct bttv *bttvs[BTTV_MAX]; - -unsigned int bttv_debug; -unsigned int bttv_verbose = 1; -unsigned int bttv_gpio; - -/* config variables */ -#ifdef __BIG_ENDIAN -static unsigned int bigendian=1; -#else -static unsigned int bigendian; -#endif -static unsigned int radio[BTTV_MAX]; -static unsigned int irq_debug; -static unsigned int gbuffers = 8; -static unsigned int gbufsize = 0x208000; -static unsigned int reset_crop = 1; - -static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 }; -static int debug_latency; -static int disable_ir; - -static unsigned int fdsr; - -/* options */ -static unsigned int combfilter; -static unsigned int lumafilter; -static unsigned int automute = 1; -static unsigned int chroma_agc; -static unsigned int adc_crush = 1; -static unsigned int whitecrush_upper = 0xCF; -static unsigned int whitecrush_lower = 0x7F; -static unsigned int vcr_hack; -static unsigned int irq_iswitch; -static unsigned int uv_ratio = 50; -static unsigned int full_luma_range; -static unsigned int coring; - -/* API features (turn on/off stuff for testing) */ -static unsigned int v4l2 = 1; - -/* insmod args */ -module_param(bttv_verbose, int, 0644); -module_param(bttv_gpio, int, 0644); -module_param(bttv_debug, int, 0644); -module_param(irq_debug, int, 0644); -module_param(debug_latency, int, 0644); -module_param(disable_ir, int, 0444); - -module_param(fdsr, int, 0444); -module_param(gbuffers, int, 0444); -module_param(gbufsize, int, 0444); -module_param(reset_crop, int, 0444); - -module_param(v4l2, int, 0644); -module_param(bigendian, int, 0644); -module_param(irq_iswitch, int, 0644); -module_param(combfilter, int, 0444); -module_param(lumafilter, int, 0444); -module_param(automute, int, 0444); -module_param(chroma_agc, int, 0444); -module_param(adc_crush, int, 0444); -module_param(whitecrush_upper, int, 0444); -module_param(whitecrush_lower, int, 0444); -module_param(vcr_hack, int, 0444); -module_param(uv_ratio, int, 0444); -module_param(full_luma_range, int, 0444); -module_param(coring, int, 0444); - -module_param_array(radio, int, NULL, 0444); -module_param_array(video_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); - -MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); -MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); -MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); -MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); -MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); -MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); -MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); -MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " - "is 1 (yes) for compatibility with older applications"); -MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); -MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); -MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); -MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); -MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); -MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); -MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); -MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); -MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); -MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); -MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(BTTV_VERSION); - -/* ----------------------------------------------------------------------- */ -/* sysfs */ - -static ssize_t show_card(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct video_device *vfd = container_of(cd, struct video_device, dev); - struct bttv *btv = video_get_drvdata(vfd); - return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); -} -static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); - -/* ----------------------------------------------------------------------- */ -/* dvb auto-load setup */ -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - request_module("dvb-bt8xx"); -} - -static void request_modules(struct bttv *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct bttv *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - - -/* ----------------------------------------------------------------------- */ -/* static data */ - -/* special timing tables from conexant... */ -static u8 SRAM_Table[][60] = -{ - /* PAL digital input over GPIO[7:0] */ - { - 45, // 45 bytes following - 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16, - 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00, - 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00, - 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37, - 0x37,0x00,0xAF,0x21,0x00 - }, - /* NTSC digital input over GPIO[7:0] */ - { - 51, // 51 bytes following - 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06, - 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00, - 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07, - 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6, - 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21, - 0x00, - }, - // TGB_NTSC392 // quartzsight - // This table has been modified to be used for Fusion Rev D - { - 0x2A, // size of table = 42 - 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24, - 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10, - 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00, - 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3, - 0x20, 0x00 - } -}; - -/* minhdelayx1 first video pixel we can capture on a line and - hdelayx1 start of active video, both relative to rising edge of - /HRESET pulse (0H) in 1 / fCLKx1. - swidth width of active video and - totalwidth total line width, both in 1 / fCLKx1. - sqwidth total line width in square pixels. - vdelay start of active video in 2 * field lines relative to - trailing edge of /VRESET pulse (VDELAY register). - sheight height of active video in 2 * field lines. - videostart0 ITU-R frame line number of the line corresponding - to vdelay in the first field. */ -#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \ - vdelay, sheight, videostart0) \ - .cropcap.bounds.left = minhdelayx1, \ - /* * 2 because vertically we count field lines times two, */ \ - /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \ - .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \ - /* 4 is a safety margin at the end of the line. */ \ - .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \ - .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \ - .cropcap.defrect.left = hdelayx1, \ - .cropcap.defrect.top = (videostart0) * 2, \ - .cropcap.defrect.width = swidth, \ - .cropcap.defrect.height = sheight, \ - .cropcap.pixelaspect.numerator = totalwidth, \ - .cropcap.pixelaspect.denominator = sqwidth, - -const struct bttv_tvnorm bttv_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 */ - { - .v4l2_id = V4L2_STD_PAL, - .name = "PAL", - .Fsc = 35468950, - .swidth = 924, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0x72, - .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - .scaledtwidth = 1135, - .hdelayx1 = 186, - .hactivex1 = 924, - .vdelay = 0x20, - .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */ - .sram = 0, - /* ITU-R frame line number of the first VBI line - we can capture, of the first and second field. - The last line is determined by cropcap.bounds. */ - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* Should be (768 * 1135 + 944 / 2) / 944. - cropcap.defrect is used for image width - checks, so we keep the old value 924. */ - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - /* bt878 (and bt848?) can capture another - line below active video. */ - .cropcap.bounds.height = (576 + 2) + 0x20 - 2, - },{ - .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, - .name = "NTSC", - .Fsc = 28636363, - .swidth = 768, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0), - .scaledtwidth = 910, - .hdelayx1 = 128, - .hactivex1 = 910, - .vdelay = 0x1a, - .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */ - .sram = 1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 128, - /* Should be (640 * 910 + 780 / 2) / 780? */ - /* swidth */ 768, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_SECAM, - .name = "SECAM", - .Fsc = 35468950, - .swidth = 924, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0xb0, - .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1), - .scaledtwidth = 1135, - .hdelayx1 = 186, - .hactivex1 = 922, - .vdelay = 0x20, - .vbipack = 255, - .sram = 0, /* like PAL, correct? */ - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_Nc, - .name = "PAL-Nc", - .Fsc = 28636363, - .swidth = 640, - .sheight = 576, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 130, - .hactivex1 = 734, - .vdelay = 0x1a, - .vbipack = 144, - .sram = -1, - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 130, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_M, - .name = "PAL-M", - .Fsc = 28636363, - .swidth = 640, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 135, - .hactivex1 = 754, - .vdelay = 0x1a, - .vbipack = 144, - .sram = -1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 135, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_PAL_N, - .name = "PAL-N", - .Fsc = 35468950, - .swidth = 768, - .sheight = 576, - .totalwidth = 1135, - .adelay = 0x7f, - .bdelay = 0x72, - .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1), - .scaledtwidth = 944, - .hdelayx1 = 186, - .hactivex1 = 922, - .vdelay = 0x20, - .vbipack = 144, - .sram = -1, - .vbistart = { 7, 320 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ (768 * 1135 + 944 / 2) / 944, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) - },{ - .v4l2_id = V4L2_STD_NTSC_M_JP, - .name = "NTSC-JP", - .Fsc = 28636363, - .swidth = 640, - .sheight = 480, - .totalwidth = 910, - .adelay = 0x68, - .bdelay = 0x5d, - .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), - .scaledtwidth = 780, - .hdelayx1 = 135, - .hactivex1 = 754, - .vdelay = 0x16, - .vbipack = 144, - .sram = -1, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 135, - /* swidth */ (640 * 910 + 780 / 2) / 780, - /* totalwidth */ 910, - /* sqwidth */ 780, - /* vdelay */ 0x16, - /* sheight */ 480, - /* videostart0 */ 23) - },{ - /* 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, - .vbistart = { 10, 273 }, - CROPCAP(/* minhdelayx1 */ 68, - /* hdelayx1 */ 186, - /* swidth */ 924, - /* totalwidth */ 1135, - /* sqwidth */ 944, - /* vdelay */ 0x1a, - /* sheight */ 480, - /* videostart0 */ 23) - } -}; -static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); - -/* ----------------------------------------------------------------------- */ -/* bttv format list - packed pixel formats must come first */ -static const struct bttv_format formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .btformat = BT848_COLOR_FMT_Y8, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "8 bpp, dithered color", - .fourcc = V4L2_PIX_FMT_HI240, - .btformat = BT848_COLOR_FMT_RGB8, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, - },{ - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .btformat = BT848_COLOR_FMT_RGB15, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .btformat = BT848_COLOR_FMT_RGB15, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .btformat = BT848_COLOR_FMT_RGB16, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .btformat = BT848_COLOR_FMT_RGB16, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .btformat = BT848_COLOR_FMT_RGB24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .btformat = BT848_COLOR_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .btformat = BT848_COLOR_FMT_RGB32, - .btswap = 0x0f, /* byte+word swap */ - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .btformat = BT848_COLOR_FMT_YUY2, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .btformat = BT848_COLOR_FMT_YUY2, - .btswap = 0x03, /* byteswap */ - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - },{ - .name = "4:2:2, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 16, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 1, - .vshift = 0, - },{ - .name = "4:2:0, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV420, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 1, - .vshift = 1, - },{ - .name = "4:2:0, planar, Y-Cr-Cb", - .fourcc = V4L2_PIX_FMT_YVU420, - .btformat = BT848_COLOR_FMT_YCrCb422, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, - .hshift = 1, - .vshift = 1, - },{ - .name = "4:1:1, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV411P, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 12, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 2, - .vshift = 0, - },{ - .name = "4:1:0, planar, Y-Cb-Cr", - .fourcc = V4L2_PIX_FMT_YUV410, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 9, - .flags = FORMAT_FLAGS_PLANAR, - .hshift = 2, - .vshift = 2, - },{ - .name = "4:1:0, planar, Y-Cr-Cb", - .fourcc = V4L2_PIX_FMT_YVU410, - .btformat = BT848_COLOR_FMT_YCrCb411, - .depth = 9, - .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb, - .hshift = 2, - .vshift = 2, - },{ - .name = "raw scanlines", - .fourcc = -1, - .btformat = BT848_COLOR_FMT_RAW, - .depth = 8, - .flags = FORMAT_FLAGS_RAW, - } -}; -static const unsigned int FORMATS = ARRAY_SIZE(formats); - -/* ----------------------------------------------------------------------- */ - -#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) -#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) -#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl bttv_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 27648, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- private --- */ - { - .id = V4L2_CID_PRIVATE_CHROMA_AGC, - .name = "chroma agc", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_COMBFILTER, - .name = "combfilter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AUTOMUTE, - .name = "automute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_LUMAFILTER, - .name = "luma decimation filter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AGC_CRUSH, - .name = "agc crush", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_VCR_HACK, - .name = "vcr hack", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, - .name = "whitecrush upper", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0xCF, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, - .name = "whitecrush lower", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0x7F, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_UV_RATIO, - .name = "uv ratio", - .minimum = 0, - .maximum = 100, - .step = 1, - .default_value = 50, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, - .name = "full luma range", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_CORING, - .name = "coring", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } - - - -}; - -static const struct v4l2_queryctrl *ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) - if (bttv_ctls[i].id == id) - return bttv_ctls+i; - - return NULL; -} - -/* ----------------------------------------------------------------------- */ -/* resource management */ - -/* - RESOURCE_ allocated by freed by - - VIDEO_READ bttv_read 1) bttv_read 2) - - VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF - VIDIOC_QBUF 1) bttv_release - VIDIOCMCAPTURE 1) - - OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off - VIDIOC_OVERLAY on VIDIOC_OVERLAY off - 3) bttv_release - - VBI VIDIOC_STREAMON VIDIOC_STREAMOFF - VIDIOC_QBUF 1) bttv_release - bttv_read, bttv_poll 1) 4) - - 1) The resource must be allocated when we enter buffer prepare functions - and remain allocated while buffers are in the DMA queue. - 2) This is a single frame read. - 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when - RESOURCE_OVERLAY is allocated. - 4) This is a continuous read, implies VIDIOC_STREAMON. - - Note this driver permits video input and standard changes regardless if - resources are allocated. -*/ - -#define VBI_RESOURCES (RESOURCE_VBI) -#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \ - RESOURCE_VIDEO_STREAM | \ - RESOURCE_OVERLAY) - -static -int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) -{ - int xbits; /* mutual exclusive resources */ - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - xbits = bit; - if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM)) - xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; - - /* is it free? */ - if (btv->resources & xbits) { - /* no, someone else uses it */ - goto fail; - } - - if ((bit & VIDEO_RESOURCES) - && 0 == (btv->resources & VIDEO_RESOURCES)) { - /* Do crop - use current, don't - use default parameters. */ - __s32 top = btv->crop[!!fh->do_crop].rect.top; - - if (btv->vbi_end > top) - goto fail; - - /* We cannot capture the same line as video and VBI data. - Claim scan lines crop[].rect.top to bottom. */ - btv->crop_start = top; - } else if (bit & VBI_RESOURCES) { - __s32 end = fh->vbi_fmt.end; - - if (end > btv->crop_start) - goto fail; - - /* Claim scan lines above fh->vbi_fmt.end. */ - btv->vbi_end = end; - } - - /* it's free, grab it */ - fh->resources |= bit; - btv->resources |= bit; - return 1; - - fail: - return 0; -} - -static -int check_btres(struct bttv_fh *fh, int bit) -{ - return (fh->resources & bit); -} - -static -int locked_btres(struct bttv *btv, int bit) -{ - return (btv->resources & bit); -} - -/* Call with btv->lock down. */ -static void -disclaim_vbi_lines(struct bttv *btv) -{ - btv->vbi_end = 0; -} - -/* Call with btv->lock down. */ -static void -disclaim_video_lines(struct bttv *btv) -{ - const struct bttv_tvnorm *tvnorm; - u8 crop; - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - btv->crop_start = tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height; - - /* VBI capturing ends at VDELAY, start of video capturing, no - matter how many lines the VBI RISC program expects. When video - capturing is off, it shall no longer "preempt" VBI capturing, - so we set VDELAY to maximum. */ - crop = btread(BT848_E_CROP) | 0xc0; - btwrite(crop, BT848_E_CROP); - btwrite(0xfe, BT848_E_VDELAY_LO); - btwrite(crop, BT848_O_CROP); - btwrite(0xfe, BT848_O_VDELAY_LO); -} - -static -void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) -{ - if ((fh->resources & bits) != bits) { - /* trying to free resources not allocated by us ... */ - pr_err("BUG! (btres)\n"); - } - fh->resources &= ~bits; - btv->resources &= ~bits; - - bits = btv->resources; - - if (0 == (bits & VIDEO_RESOURCES)) - disclaim_video_lines(btv); - - if (0 == (bits & VBI_RESOURCES)) - disclaim_vbi_lines(btv); -} - -/* ----------------------------------------------------------------------- */ -/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */ - -/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C - PLL_X = Reference pre-divider (0=1, 1=2) - PLL_C = Post divider (0=6, 1=4) - PLL_I = Integer input - PLL_F = Fractional input - - F_input = 28.636363 MHz: - PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0 -*/ - -static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout) -{ - unsigned char fl, fh, fi; - - /* prevent overflows */ - fin/=4; - fout/=4; - - fout*=12; - fi=fout/fin; - - fout=(fout%fin)*256; - fh=fout/fin; - - fout=(fout%fin)*256; - fl=fout/fin; - - btwrite(fl, BT848_PLL_F_LO); - btwrite(fh, BT848_PLL_F_HI); - btwrite(fi|BT848_PLL_X, BT848_PLL_XCI); -} - -static void set_pll(struct bttv *btv) -{ - int i; - - if (!btv->pll.pll_crystal) - return; - - if (btv->pll.pll_ofreq == btv->pll.pll_current) { - dprintk("%d: PLL: no change required\n", btv->c.nr); - return; - } - - if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) { - /* no PLL needed */ - if (btv->pll.pll_current == 0) - return; - if (bttv_verbose) - pr_info("%d: PLL can sleep, using XTAL (%d)\n", - btv->c.nr, btv->pll.pll_ifreq); - btwrite(0x00,BT848_TGCTRL); - btwrite(0x00,BT848_PLL_XCI); - btv->pll.pll_current = 0; - return; - } - - if (bttv_verbose) - pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n", - btv->c.nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); - set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); - - for (i=0; i<10; i++) { - /* Let other people run while the PLL stabilizes */ - msleep(10); - - if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { - btwrite(0,BT848_DSTATUS); - } else { - btwrite(0x08,BT848_TGCTRL); - btv->pll.pll_current = btv->pll.pll_ofreq; - if (bttv_verbose) - pr_info("PLL set ok\n"); - return; - } - } - btv->pll.pll_current = -1; - if (bttv_verbose) - pr_info("Setting PLL failed\n"); - return; -} - -/* used to switch between the bt848's analog/digital video capture modes */ -static void bt848A_set_timing(struct bttv *btv) -{ - int i, len; - int table_idx = bttv_tvnorms[btv->tvnorm].sram; - int fsc = bttv_tvnorms[btv->tvnorm].Fsc; - - if (btv->input == btv->dig) { - dprintk("%d: load digital timing table (table_idx=%d)\n", - btv->c.nr,table_idx); - - /* timing change...reset timing generator address */ - btwrite(0x00, BT848_TGCTRL); - btwrite(0x02, BT848_TGCTRL); - btwrite(0x00, BT848_TGCTRL); - - len=SRAM_Table[table_idx][0]; - for(i = 1; i <= len; i++) - btwrite(SRAM_Table[table_idx][i],BT848_TGLB); - btv->pll.pll_ofreq = 27000000; - - set_pll(btv); - btwrite(0x11, BT848_TGCTRL); - btwrite(0x41, BT848_DVSIF); - } else { - btv->pll.pll_ofreq = fsc; - set_pll(btv); - btwrite(0x0, BT848_DVSIF); - } -} - -/* ----------------------------------------------------------------------- */ - -static void bt848_bright(struct bttv *btv, int bright) -{ - int value; - - // printk("set bright: %d\n", bright); // DEBUG - btv->bright = bright; - - /* We want -128 to 127 we get 0-65535 */ - value = (bright >> 8) - 128; - btwrite(value & 0xff, BT848_BRIGHT); -} - -static void bt848_hue(struct bttv *btv, int hue) -{ - int value; - - btv->hue = hue; - - /* -128 to 127 */ - value = (hue >> 8) - 128; - btwrite(value & 0xff, BT848_HUE); -} - -static void bt848_contrast(struct bttv *btv, int cont) -{ - int value,hibit; - - btv->contrast = cont; - - /* 0-511 */ - value = (cont >> 7); - hibit = (value >> 6) & 4; - btwrite(value & 0xff, BT848_CONTRAST_LO); - btaor(hibit, ~4, BT848_E_CONTROL); - btaor(hibit, ~4, BT848_O_CONTROL); -} - -static void bt848_sat(struct bttv *btv, int color) -{ - int val_u,val_v,hibits; - - btv->saturation = color; - - /* 0-511 for the color */ - val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; - val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; - hibits = (val_u >> 7) & 2; - hibits |= (val_v >> 8) & 1; - btwrite(val_u & 0xff, BT848_SAT_U_LO); - btwrite(val_v & 0xff, BT848_SAT_V_LO); - btaor(hibits, ~3, BT848_E_CONTROL); - btaor(hibits, ~3, BT848_O_CONTROL); -} - -/* ----------------------------------------------------------------------- */ - -static int -video_mux(struct bttv *btv, unsigned int input) -{ - int mux,mask2; - - if (input >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - - /* needed by RemoteVideo MX */ - mask2 = bttv_tvcards[btv->c.type].gpiomask2; - if (mask2) - gpio_inout(mask2,mask2); - - if (input == btv->svhs) { - btor(BT848_CONTROL_COMP, BT848_E_CONTROL); - btor(BT848_CONTROL_COMP, BT848_O_CONTROL); - } else { - btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); - btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); - } - mux = bttv_muxsel(btv, input); - btaor(mux<<5, ~(3<<5), BT848_IFORM); - dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux); - - /* card specific hook */ - if(bttv_tvcards[btv->c.type].muxsel_hook) - bttv_tvcards[btv->c.type].muxsel_hook (btv, input); - return 0; -} - -static char *audio_modes[] = { - "audio: tuner", "audio: radio", "audio: extern", - "audio: intern", "audio: mute" -}; - -static int -audio_mux(struct bttv *btv, int input, int mute) -{ - int gpio_val, signal; - struct v4l2_control ctrl; - - gpio_inout(bttv_tvcards[btv->c.type].gpiomask, - bttv_tvcards[btv->c.type].gpiomask); - signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; - - btv->mute = mute; - btv->audio = input; - - /* automute */ - mute = mute || (btv->opt_automute && !signal && !btv->radio_user); - - if (mute) - gpio_val = bttv_tvcards[btv->c.type].gpiomute; - else - gpio_val = bttv_tvcards[btv->c.type].gpiomux[input]; - - switch (btv->c.type) { - case BTTV_BOARD_VOODOOTV_FM: - case BTTV_BOARD_VOODOOTV_200: - gpio_val = bttv_tda9880_setnorm(btv, gpio_val); - break; - - default: - gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val); - } - - if (bttv_gpio) - bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]); - if (in_interrupt()) - return 0; - - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = btv->mute; - bttv_call_all(btv, core, s_ctrl, &ctrl); - if (btv->sd_msp34xx) { - u32 in; - - /* Note: the inputs tuner/radio/extern/intern are translated - to msp routings. This assumes common behavior for all msp3400 - based TV cards. When this assumption fails, then the - specific MSP routing must be added to the card table. - For now this is sufficient. */ - switch (input) { - case TVAUDIO_INPUT_RADIO: - /* Some boards need the msp do to the radio demod */ - if (btv->radio_uses_msp_demodulator) { - in = MSP_INPUT_DEFAULT; - break; - } - in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_EXTERN: - in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_INTERN: - /* Yes, this is the same input as for RADIO. I doubt - if this is ever used. The only board with an INTERN - input is the BTTV_BOARD_AVERMEDIA98. I wonder how - that was tested. My guess is that the whole INTERN - input does not work. */ - in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case TVAUDIO_INPUT_TUNER: - default: - /* This is the only card that uses TUNER2, and afaik, - is the only difference between the VOODOOTV_FM - and VOODOOTV_200 */ - if (btv->c.type == BTTV_BOARD_VOODOOTV_200) - in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \ - MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER); - else - in = MSP_INPUT_DEFAULT; - break; - } - v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing, - in, MSP_OUTPUT_DEFAULT, 0); - } - if (btv->sd_tvaudio) { - v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, - input, 0, 0); - } - return 0; -} - -static inline int -audio_mute(struct bttv *btv, int mute) -{ - return audio_mux(btv, btv->audio, mute); -} - -static inline int -audio_input(struct bttv *btv, int input) -{ - return audio_mux(btv, input, btv->mute); -} - -static void -bttv_crop_calc_limits(struct bttv_crop *c) -{ - /* Scale factor min. 1:1, max. 16:1. Min. image size - 48 x 32. Scaled width must be a multiple of 4. */ - - if (1) { - /* For bug compatibility with VIDIOCGCAP and image - size checks in earlier driver versions. */ - c->min_scaled_width = 48; - c->min_scaled_height = 32; - } else { - c->min_scaled_width = - (max(48, c->rect.width >> 4) + 3) & ~3; - c->min_scaled_height = - max(32, c->rect.height >> 4); - } - - c->max_scaled_width = c->rect.width & ~3; - c->max_scaled_height = c->rect.height; -} - -static void -bttv_crop_reset(struct bttv_crop *c, unsigned int norm) -{ - c->rect = bttv_tvnorms[norm].cropcap.defrect; - bttv_crop_calc_limits(c); -} - -/* Call with btv->lock down. */ -static int -set_tvnorm(struct bttv *btv, unsigned int norm) -{ - const struct bttv_tvnorm *tvnorm; - v4l2_std_id id; - - BUG_ON(norm >= BTTV_TVNORMS); - BUG_ON(btv->tvnorm >= BTTV_TVNORMS); - - tvnorm = &bttv_tvnorms[norm]; - - if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap, - sizeof (tvnorm->cropcap))) { - bttv_crop_reset(&btv->crop[0], norm); - btv->crop[1] = btv->crop[0]; /* current = default */ - - if (0 == (btv->resources & VIDEO_RESOURCES)) { - btv->crop_start = tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height; - } - } - - btv->tvnorm = norm; - - btwrite(tvnorm->adelay, BT848_ADELAY); - btwrite(tvnorm->bdelay, BT848_BDELAY); - btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), - BT848_IFORM); - btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); - btwrite(1, BT848_VBI_PACK_DEL); - bt848A_set_timing(btv); - - switch (btv->c.type) { - case BTTV_BOARD_VOODOOTV_FM: - case BTTV_BOARD_VOODOOTV_200: - bttv_tda9880_setnorm(btv, gpio_read()); - break; - } - id = tvnorm->v4l2_id; - bttv_call_all(btv, core, s_std, id); - - return 0; -} - -/* Call with btv->lock down. */ -static void -set_input(struct bttv *btv, unsigned int input, unsigned int norm) -{ - unsigned long flags; - - btv->input = input; - if (irq_iswitch) { - spin_lock_irqsave(&btv->s_lock,flags); - if (btv->curr.frame_irq) { - /* active capture -> delayed input switch */ - btv->new_input = input; - } else { - video_mux(btv,input); - } - spin_unlock_irqrestore(&btv->s_lock,flags); - } else { - video_mux(btv,input); - } - audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ? - TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN); - set_tvnorm(btv, norm); -} - -static void init_irqreg(struct bttv *btv) -{ - /* clear status */ - btwrite(0xfffffUL, BT848_INT_STAT); - - if (bttv_tvcards[btv->c.type].no_video) { - /* i2c only */ - btwrite(BT848_INT_I2CDONE, - BT848_INT_MASK); - } else { - /* full video */ - btwrite((btv->triton1) | - (btv->gpioirq ? BT848_INT_GPINT : 0) | - BT848_INT_SCERR | - (fdsr ? BT848_INT_FDSR : 0) | - BT848_INT_RISCI | BT848_INT_OCERR | - BT848_INT_FMTCHG|BT848_INT_HLOCK| - BT848_INT_I2CDONE, - BT848_INT_MASK); - } -} - -static void init_bt848(struct bttv *btv) -{ - int val; - - if (bttv_tvcards[btv->c.type].no_video) { - /* very basic init only */ - init_irqreg(btv); - return; - } - - btwrite(0x00, BT848_CAP_CTL); - btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); - btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); - - /* set planar and packed mode trigger points and */ - /* set rising edge of inverted GPINTR pin as irq trigger */ - btwrite(BT848_GPIO_DMA_CTL_PKTP_32| - BT848_GPIO_DMA_CTL_PLTP1_16| - BT848_GPIO_DMA_CTL_PLTP23_16| - BT848_GPIO_DMA_CTL_GPINTC| - BT848_GPIO_DMA_CTL_GPINTI, - BT848_GPIO_DMA_CTL); - - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - - btwrite(0x20, BT848_E_VSCALE_HI); - btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - - btwrite(whitecrush_upper, BT848_WC_UP); - btwrite(whitecrush_lower, BT848_WC_DOWN); - - if (btv->opt_lumafilter) { - btwrite(0, BT848_E_CONTROL); - btwrite(0, BT848_O_CONTROL); - } else { - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); - - /* interrupt */ - init_irqreg(btv); -} - -static void bttv_reinit_bt848(struct bttv *btv) -{ - unsigned long flags; - - if (bttv_verbose) - pr_info("%d: reset, reinitialize\n", btv->c.nr); - spin_lock_irqsave(&btv->s_lock,flags); - btv->errors=0; - bttv_set_dma(btv,0); - spin_unlock_irqrestore(&btv->s_lock,flags); - - init_bt848(btv); - btv->pll.pll_current = -1; - set_input(btv, btv->input, btv->tvnorm); -} - -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, g_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) -{ - int err; - int val; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != err) - return err; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); - break; - case V4L2_CID_HUE: - bt848_hue(btv, c->value); - break; - case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); - break; - case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); - break; - case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_all(btv, core, s_ctrl, c); - break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, s_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - break; - case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { - btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); - btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); - } else { - btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - break; - case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); - break; - case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; - bt848_sat(btv, btv->saturation); - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); - break; - case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); - break; - default: - return -EINVAL; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -void bttv_gpio_tracking(struct bttv *btv, char *comment) -{ - unsigned int outbits, data; - outbits = btread(BT848_GPIO_OUT_EN); - data = btread(BT848_GPIO_DATA); - pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", - btv->c.nr, outbits, data & outbits, data & ~outbits, comment); -} - -static void bttv_field_count(struct bttv *btv) -{ - int need_count = 0; - - if (btv->users) - need_count++; - - if (need_count) { - /* start field counter */ - btor(BT848_INT_VSYNC,BT848_INT_MASK); - } else { - /* stop field counter */ - btand(~BT848_INT_VSYNC,BT848_INT_MASK); - btv->field_count = 0; - } -} - -static const struct bttv_format* -format_by_fourcc(int fourcc) -{ - unsigned int i; - - for (i = 0; i < FORMATS; i++) { - if (-1 == formats[i].fourcc) - continue; - if (formats[i].fourcc == fourcc) - return formats+i; - } - return NULL; -} - -/* ----------------------------------------------------------------------- */ -/* misc helpers */ - -static int -bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, - struct bttv_buffer *new) -{ - struct bttv_buffer *old; - unsigned long flags; - int retval = 0; - - dprintk("switch_overlay: enter [new=%p]\n", new); - if (new) - new->vb.state = VIDEOBUF_DONE; - spin_lock_irqsave(&btv->s_lock,flags); - old = btv->screen; - btv->screen = new; - btv->loop_irq |= 1; - bttv_set_dma(btv, 0x03); - spin_unlock_irqrestore(&btv->s_lock,flags); - if (NULL != old) { - dprintk("switch_overlay: old=%p state is %d\n", - old, old->vb.state); - bttv_dma_free(&fh->cap,btv, old); - kfree(old); - } - if (NULL == new) - free_btres_lock(btv,fh,RESOURCE_OVERLAY); - dprintk("switch_overlay: done\n"); - return retval; -} - -/* ----------------------------------------------------------------------- */ -/* video4linux (1) interface */ - -static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, - struct bttv_buffer *buf, - const struct bttv_format *fmt, - unsigned int width, unsigned int height, - enum v4l2_field field) -{ - struct bttv_fh *fh = q->priv_data; - int redo_dma_risc = 0; - struct bttv_crop c; - int norm; - int rc; - - /* check settings */ - if (NULL == fmt) - return -EINVAL; - if (fmt->btformat == BT848_COLOR_FMT_RAW) { - width = RAW_BPL; - height = RAW_LINES*2; - if (width*height > buf->vb.bsize) - return -EINVAL; - buf->vb.size = buf->vb.bsize; - - /* Make sure tvnorm and vbi_end remain consistent - until we're done. */ - - norm = btv->tvnorm; - - /* In this mode capturing always starts at defrect.top - (default VDELAY), ignoring cropping parameters. */ - if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { - return -EINVAL; - } - - c.rect = bttv_tvnorms[norm].cropcap.defrect; - } else { - norm = btv->tvnorm; - c = btv->crop[!!fh->do_crop]; - - if (width < c.min_scaled_width || - width > c.max_scaled_width || - height < c.min_scaled_height) - return -EINVAL; - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - /* btv->crop counts frame lines. Max. scale - factor is 16:1 for frames, 8:1 for fields. */ - if (height * 2 > c.max_scaled_height) - return -EINVAL; - break; - - default: - if (height > c.max_scaled_height) - return -EINVAL; - break; - } - - buf->vb.size = (width * height * fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - } - - /* alloc + fill struct bttv_buffer (if changed) */ - if (buf->vb.width != width || buf->vb.height != height || - buf->vb.field != field || - buf->tvnorm != norm || buf->fmt != fmt || - buf->crop.top != c.rect.top || - buf->crop.left != c.rect.left || - buf->crop.width != c.rect.width || - buf->crop.height != c.rect.height) { - buf->vb.width = width; - buf->vb.height = height; - buf->vb.field = field; - buf->tvnorm = norm; - buf->fmt = fmt; - buf->crop = c.rect; - redo_dma_risc = 1; - } - - /* alloc risc memory */ - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - redo_dma_risc = 1; - if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) - goto fail; - } - - if (redo_dma_risc) - if (0 != (rc = bttv_buffer_risc(btv,buf))) - goto fail; - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - bttv_dma_free(q,btv,buf); - return rc; -} - -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - struct bttv_fh *fh = q->priv_data; - - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = gbuffers; - if (*size * *count > gbuffers * gbufsize) - *count = (gbuffers * gbufsize) / *size; - return 0; -} - -static int -buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - - return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt, - fh->width, fh->height, field); -} - -static void -buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue,&btv->capture); - if (!btv->curr.frame_irq) { - btv->loop_irq |= 1; - bttv_set_dma(btv, 0x03); - } -} - -static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - struct bttv_fh *fh = q->priv_data; - - bttv_dma_free(q,fh->btv,buf); -} - -static struct videobuf_queue_ops bttv_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - unsigned int i; - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - goto err; - - for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) - break; - if (i == BTTV_TVNORMS) { - err = -EINVAL; - goto err; - } - - set_tvnorm(btv, i); - -err: - - return err; -} - -static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) - *id = V4L2_STD_625_50; - else - *id = V4L2_STD_525_60; - return 0; -} - -static int bttv_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int rc = 0; - - if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { - rc = -EINVAL; - goto err; - } - - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; - - if (btv->tuner_type != TUNER_ABSENT && i->index == 0) { - sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->tuner = 0; - } else if (i->index == btv->svhs) { - sprintf(i->name, "S-Video"); - } else { - sprintf(i->name, "Composite%d", i->index); - } - - if (i->index == btv->input) { - __u32 dstatus = btread(BT848_DSTATUS); - if (0 == (dstatus & BT848_DSTATUS_PRES)) - i->status |= V4L2_IN_ST_NO_SIGNAL; - if (0 == (dstatus & BT848_DSTATUS_HLOC)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - } - - i->std = BTTV_NORMS; - -err: - - return rc; -} - -static int bttv_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - *i = btv->input; - - return 0; -} - -static int bttv_s_input(struct file *file, void *priv, unsigned int i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - if (i > bttv_tvcards[btv->c.type].video_inputs) { - err = -EINVAL; - goto err; - } - - set_input(btv, i, btv->tvnorm); - -err: - return 0; -} - -static int bttv_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; - - if (unlikely(0 != t->index)) - return -EINVAL; - - if (unlikely(btv->tuner_type == TUNER_ABSENT)) { - err = -EINVAL; - goto err; - } - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - bttv_call_all(btv, tuner, s_tuner, t); - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 1); - -err: - - return 0; -} - -static int bttv_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; - - return 0; -} - -static int bttv_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; - - if (unlikely(f->tuner != 0)) - return -EINVAL; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; - - if (unlikely(f->type != (btv->radio_user - ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) { - err = -EINVAL; - goto err; - } - btv->freq = f->frequency; - bttv_call_all(btv, tuner, s_frequency, f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv, btv->freq); -err: - - return 0; -} - -static int bttv_log_status(struct file *file, void *f) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - bttv_call_all(btv, core, log_status); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int bttv_g_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - reg->val = btread(reg->reg); - reg->size = 1; - - return 0; -} - -static int bttv_s_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - btwrite(reg->val, reg->reg); - - return 0; -} -#endif - -/* Given cropping boundaries b and the scaled width and height of a - single field or frame, which must not exceed hardware limits, this - function adjusts the cropping parameters c. */ -static void -bttv_crop_adjust (struct bttv_crop * c, - const struct v4l2_rect * b, - __s32 width, - __s32 height, - enum v4l2_field field) -{ - __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); - __s32 max_left; - __s32 max_top; - - if (width < c->min_scaled_width) { - /* Max. hor. scale factor 16:1. */ - c->rect.width = width * 16; - } else if (width > c->max_scaled_width) { - /* Min. hor. scale factor 1:1. */ - c->rect.width = width; - - max_left = b->left + b->width - width; - max_left = min(max_left, (__s32) MAX_HDELAY); - if (c->rect.left > max_left) - c->rect.left = max_left; - } - - if (height < c->min_scaled_height) { - /* Max. vert. scale factor 16:1, single fields 8:1. */ - c->rect.height = height * 16; - } else if (frame_height > c->max_scaled_height) { - /* Min. vert. scale factor 1:1. - Top and height count field lines times two. */ - c->rect.height = (frame_height + 1) & ~1; - - max_top = b->top + b->height - c->rect.height; - if (c->rect.top > max_top) - c->rect.top = max_top; - } - - bttv_crop_calc_limits(c); -} - -/* Returns an error if scaling to a frame or single field with the given - width and height is not possible with the current cropping parameters - and width aligned according to width_mask. If adjust_size is TRUE the - function may adjust the width and/or height instead, rounding width - to (width + width_bias) & width_mask. If adjust_crop is TRUE it may - also adjust the current cropping parameters to get closer to the - desired image size. */ -static int -limit_scaled_size_lock (struct bttv_fh * fh, - __s32 * width, - __s32 * height, - enum v4l2_field field, - unsigned int width_mask, - unsigned int width_bias, - int adjust_size, - int adjust_crop) -{ - struct bttv *btv = fh->btv; - const struct v4l2_rect *b; - struct bttv_crop *c; - __s32 min_width; - __s32 min_height; - __s32 max_width; - __s32 max_height; - int rc; - - BUG_ON((int) width_mask >= 0 || - width_bias >= (unsigned int) -width_mask); - - /* Make sure tvnorm, vbi_end and the current cropping parameters - remain consistent until we're done. */ - - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - - /* Do crop - use current, don't - use default parameters. */ - c = &btv->crop[!!fh->do_crop]; - - if (fh->do_crop - && adjust_size - && adjust_crop - && !locked_btres(btv, VIDEO_RESOURCES)) { - min_width = 48; - min_height = 32; - - /* We cannot scale up. When the scaled image is larger - than crop.rect we adjust the crop.rect as required - by the V4L2 spec, hence cropcap.bounds are our limit. */ - max_width = min(b->width, (__s32) MAX_HACTIVE); - max_height = b->height; - - /* We cannot capture the same line as video and VBI data. - Note btv->vbi_end is really a minimum, see - bttv_vbi_try_fmt(). */ - if (btv->vbi_end > b->top) { - max_height -= btv->vbi_end - b->top; - rc = -EBUSY; - if (min_height > max_height) - goto fail; - } - } else { - rc = -EBUSY; - if (btv->vbi_end > c->rect.top) - goto fail; - - min_width = c->min_scaled_width; - min_height = c->min_scaled_height; - max_width = c->max_scaled_width; - max_height = c->max_scaled_height; - - adjust_crop = 0; - } - - min_width = (min_width - width_mask - 1) & width_mask; - max_width = max_width & width_mask; - - /* Max. scale factor is 16:1 for frames, 8:1 for fields. */ - min_height = min_height; - /* Min. scale factor is 1:1. */ - max_height >>= !V4L2_FIELD_HAS_BOTH(field); - - if (adjust_size) { - *width = clamp(*width, min_width, max_width); - *height = clamp(*height, min_height, max_height); - - /* Round after clamping to avoid overflow. */ - *width = (*width + width_bias) & width_mask; - - if (adjust_crop) { - bttv_crop_adjust(c, b, *width, *height, field); - - if (btv->vbi_end > c->rect.top) { - /* Move the crop window out of the way. */ - c->rect.top = btv->vbi_end; - } - } - } else { - rc = -EINVAL; - if (*width < min_width || - *height < min_height || - *width > max_width || - *height > max_height || - 0 != (*width & ~width_mask)) - goto fail; - } - - rc = 0; /* success */ - - fail: - - return rc; -} - -/* Returns an error if the given overlay window dimensions are not - possible with the current cropping parameters. If adjust_size is - TRUE the function may adjust the window width and/or height - instead, however it always rounds the horizontal position and - width as btcx_align() does. If adjust_crop is TRUE the function - may also adjust the current cropping parameters to get closer - to the desired window size. */ -static int -verify_window_lock (struct bttv_fh * fh, - struct v4l2_window * win, - int adjust_size, - int adjust_crop) -{ - enum v4l2_field field; - unsigned int width_mask; - int rc; - - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; - if (win->clipcount > 2048) - return -EINVAL; - - field = win->field; - - if (V4L2_FIELD_ANY == field) { - __s32 height2; - - height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; - field = (win->w.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_TOP; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - /* 4-byte alignment. */ - if (NULL == fh->ovfmt) - return -EINVAL; - width_mask = ~0; - switch (fh->ovfmt->depth) { - case 8: - case 24: - width_mask = ~3; - break; - case 16: - width_mask = ~1; - break; - case 32: - break; - default: - BUG(); - } - - win->w.width -= win->w.left & ~width_mask; - win->w.left = (win->w.left - width_mask - 1) & width_mask; - - rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height, - field, width_mask, - /* width_bias: round down */ 0, - adjust_size, adjust_crop); - if (0 != rc) - return rc; - - win->field = field; - return 0; -} - -static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_window *win, int fixup) -{ - struct v4l2_clip *clips = NULL; - int n,size,retval = 0; - - if (NULL == fh->ovfmt) - return -EINVAL; - if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - retval = verify_window_lock(fh, win, - /* adjust_size */ fixup, - /* adjust_crop */ fixup); - if (0 != retval) - return retval; - - /* copy clips -- luckily v4l1 + v4l2 are binary - compatible here ...*/ - n = win->clipcount; - 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)*n)) { - kfree(clips); - return -EFAULT; - } - } - - /* clip against screen */ - if (NULL != btv->fbuf.base) - n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, - &win->w, 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(); - } - - kfree(fh->ov.clips); - fh->ov.clips = clips; - fh->ov.nclips = n; - - 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; - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv,fh,new); - } - return retval; -} - -/* ----------------------------------------------------------------------- */ - -static struct videobuf_queue* bttv_queue(struct bttv_fh *fh) -{ - struct videobuf_queue* q = NULL; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &fh->cap; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - q = &fh->vbi; - break; - default: - BUG(); - } - return q; -} - -static int bttv_resource(struct bttv_fh *fh) -{ - int res = 0; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - res = RESOURCE_VIDEO_STREAM; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - res = RESOURCE_VBI; - break; - default: - BUG(); - } - return res; -} - -static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) -{ - struct videobuf_queue *q = bttv_queue(fh); - int res = bttv_resource(fh); - - if (check_btres(fh,res)) - return -EBUSY; - if (videobuf_queue_is_busy(q)) - return -EBUSY; - fh->type = type; - return 0; -} - -static void -pix_format_set_size (struct v4l2_pix_format * f, - const struct bttv_format * fmt, - unsigned int width, - unsigned int height) -{ - f->width = width; - f->height = height; - - if (fmt->flags & FORMAT_FLAGS_PLANAR) { - f->bytesperline = width; /* Y plane */ - f->sizeimage = (width * height * fmt->depth) >> 3; - } else { - f->bytesperline = (width * fmt->depth) >> 3; - f->sizeimage = height * f->bytesperline; - } -} - -static int bttv_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - pix_format_set_size(&f->fmt.pix, fh->fmt, - fh->width, fh->height); - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - - return 0; -} - -static int bttv_g_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - f->fmt.win.w = fh->ov.w; - f->fmt.win.field = fh->ov.field; - - return 0; -} - -static int bttv_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - enum v4l2_field field; - __s32 width, height; - int rc; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - - if (V4L2_FIELD_ANY == field) { - __s32 height2; - - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; - break; - default: - return -EINVAL; - } - - width = f->fmt.pix.width; - height = f->fmt.pix.height; - - rc = limit_scaled_size_lock(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 0); - if (0 != rc) - return rc; - - /* update data for the application */ - f->fmt.pix.field = field; - pix_format_set_size(&f->fmt.pix, fmt, width, height); - - return 0; -} - -static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - return verify_window_lock(fh, &f->fmt.win, - /* adjust_size */ 1, - /* adjust_crop */ 0); -} - -static int bttv_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - int retval; - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - __s32 width, height; - enum v4l2_field field; - - retval = bttv_switch_type(fh, f->type); - if (0 != retval) - return retval; - - retval = bttv_try_fmt_vid_cap(file, priv, f); - if (0 != retval) - return retval; - - width = f->fmt.pix.width; - height = f->fmt.pix.height; - field = f->fmt.pix.field; - - retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 1); - if (0 != retval) - return retval; - - f->fmt.pix.field = field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - - /* update our state informations */ - 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; - btv->init.width = f->fmt.pix.width; - btv->init.height = f->fmt.pix.height; - - return 0; -} - -static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (no_overlay > 0) { - pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - return setup_window_lock(fh, btv, &f->fmt.win, 1); -} - -static int bttv_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (0 == v4l2) - return -EINVAL; - - strlcpy(cap->driver, "bttv", sizeof(cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - /* - * No need to lock here: those vars are initialized during board - * probe and remains untouched during the rest of the driver lifecycle - */ - if (btv->has_saa6588) - cap->capabilities |= V4L2_CAP_RDS_CAPTURE; - if (btv->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) -{ - int index = -1, i; - - for (i = 0; i < FORMATS; i++) { - if (formats[i].fourcc != -1) - index++; - if ((unsigned int)index == f->index) - break; - } - if (FORMATS == i) - return -EINVAL; - - f->pixelformat = formats[i].fourcc; - strlcpy(f->description, formats[i].name, sizeof(f->description)); - - return i; -} - -static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc = bttv_enum_fmt_cap_ovr(f); - - if (rc < 0) - return rc; - - return 0; -} - -static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc; - - if (no_overlay > 0) { - pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - - rc = bttv_enum_fmt_cap_ovr(f); - - if (rc < 0) - return rc; - - if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - - return 0; -} - -static int bttv_g_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *fb = btv->fbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (fh->ovfmt) - fb->fmt.pixelformat = fh->ovfmt->fourcc; - return 0; -} - -static int bttv_overlay(struct file *file, void *f, unsigned int on) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - struct bttv_buffer *new; - int retval = 0; - - if (on) { - /* verify args */ - if (unlikely(!btv->fbuf.base)) { - return -EINVAL; - } - if (unlikely(!fh->ov.setup_ok)) { - dprintk("%d: overlay: !setup_ok\n", btv->c.nr); - retval = -EINVAL; - } - if (retval) - return retval; - } - - if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) - return -EBUSY; - - if (on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; - } - - /* switch over */ - retval = bttv_switch_overlay(btv, fh, new); - return retval; -} - -static int bttv_s_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_format *fmt; - int retval; - - if (!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - - retval = -EINVAL; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - __s32 width = fb->fmt.width; - __s32 height = fb->fmt.height; - - retval = limit_scaled_size_lock(fh, &width, &height, - V4L2_FIELD_INTERLACED, - /* width_mask */ ~3, - /* width_bias */ 2, - /* adjust_size */ 0, - /* adjust_crop */ 0); - if (0 != retval) - return retval; - } - - /* ok, accept it */ - btv->fbuf.base = fb->base; - btv->fbuf.fmt.width = fb->fmt.width; - btv->fbuf.fmt.height = fb->fmt.height; - if (0 != fb->fmt.bytesperline) - btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - - retval = 0; - fh->ovfmt = fmt; - btv->init.ovfmt = fmt; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.w.left = 0; - fh->ov.w.top = 0; - fh->ov.w.width = fb->fmt.width; - fh->ov.w.height = fb->fmt.height; - btv->init.ov.w.width = fb->fmt.width; - btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); - fh->ov.clips = NULL; - fh->ov.nclips = 0; - - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_sg_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv, fh, new); - } - } - return retval; -} - -static int bttv_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct bttv_fh *fh = priv; - return videobuf_reqbufs(bttv_queue(fh), p); -} - -static int bttv_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_querybuf(bttv_queue(fh), b); -} - -static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); - - if (!check_alloc_btres_lock(btv, fh, res)) - return -EBUSY; - - return videobuf_qbuf(bttv_queue(fh), b); -} - -static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_dqbuf(bttv_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - -static int bttv_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); - - if (!check_alloc_btres_lock(btv, fh, res)) - return -EBUSY; - return videobuf_streamon(bttv_queue(fh)); -} - - -static int bttv_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int retval; - int res = bttv_resource(fh); - - - retval = videobuf_streamoff(bttv_queue(fh)); - if (retval < 0) - return retval; - free_btres_lock(btv, fh, res); - return 0; -} - -static int bttv_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - - if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; - else { - ctrl = ctrl_by_id(c->id); - - *c = (NULL != ctrl) ? *ctrl : no_ctl; - } - - return 0; -} - -static int bttv_g_parm(struct file *file, void *f, - struct v4l2_streamparm *parm) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, - &parm->parm.capture.timeperframe); - - return 0; -} - -static int bttv_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_all(btv, tuner, g_tuner, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); - - return 0; -} - -static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *p = v4l2_prio_max(&btv->prio); - - return 0; -} - -static int bttv_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - int rc; - - rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - - return rc; -} - -static int bttv_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - *cap = bttv_tvnorms[btv->tvnorm].cropcap; - - return 0; -} - -static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - /* No fh->do_crop = 1; because btv->crop[1] may be - inconsistent with fh->width or fh->height and apps - do not expect a change here. */ - - crop->c = btv->crop[!!fh->do_crop].rect; - - return 0; -} - -static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct v4l2_rect *b; - int retval; - struct bttv_crop c; - __s32 b_left; - __s32 b_top; - __s32 b_right; - __s32 b_bottom; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - - /* Make sure tvnorm, vbi_end and the current cropping - parameters remain consistent until we're done. Note - read() may change vbi_end in check_alloc_btres_lock(). */ - retval = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != retval) { - return retval; - } - - retval = -EBUSY; - - if (locked_btres(fh->btv, VIDEO_RESOURCES)) { - return retval; - } - - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - - b_left = b->left; - b_right = b_left + b->width; - b_bottom = b->top + b->height; - - b_top = max(b->top, btv->vbi_end); - if (b_top + 32 >= b_bottom) { - return retval; - } - - /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); - c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - - c.rect.width = clamp(crop->c.width, - 48, b_right - c.rect.left); - - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); - /* Top and height must be a multiple of two. */ - c.rect.top = (c.rect.top + 1) & ~1; - - c.rect.height = clamp(crop->c.height, - 32, b_bottom - c.rect.top); - c.rect.height = (c.rect.height + 1) & ~1; - - bttv_crop_calc_limits(&c); - - btv->crop[1] = c; - - fh->do_crop = 1; - - if (fh->width < c.min_scaled_width) { - fh->width = c.min_scaled_width; - btv->init.width = c.min_scaled_width; - } else if (fh->width > c.max_scaled_width) { - fh->width = c.max_scaled_width; - btv->init.width = c.max_scaled_width; - } - - if (fh->height < c.min_scaled_height) { - fh->height = c.min_scaled_height; - btv->init.height = c.min_scaled_height; - } else if (fh->height > c.max_scaled_height) { - fh->height = c.max_scaled_height; - btv->init.height = c.max_scaled_height; - } - - return 0; -} - -static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "audio"); - return 0; -} - -static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - -static ssize_t bttv_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct bttv_fh *fh = file->private_data; - int retval = 0; - - if (fh->btv->errors) - bttv_reinit_bt848(fh->btv); - dprintk("%d: read count=%d type=%s\n", - fh->btv->c.nr, (int)count, v4l2_type_names[fh->type]); - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) { - /* VIDEO_READ in use by another fh, - or VIDEO_STREAM by any fh. */ - return -EBUSY; - } - retval = videobuf_read_one(&fh->cap, data, count, ppos, - file->f_flags & O_NONBLOCK); - free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ); - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) - return -EBUSY; - retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - break; - default: - BUG(); - } - return retval; -} - -static unsigned int bttv_poll(struct file *file, poll_table *wait) -{ - struct bttv_fh *fh = file->private_data; - struct bttv_buffer *buf; - enum v4l2_field field; - unsigned int rc = POLLERR; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbi, wait); - } - - if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { - /* streaming capture */ - if (list_empty(&fh->cap.stream)) - goto err; - buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); - } else { - /* read() capture */ - if (NULL == fh->cap.read_buf) { - /* need to capture a new frame */ - if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) - goto err; - fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize); - if (NULL == fh->cap.read_buf) - goto err; - fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; - field = videobuf_next_field(&fh->cap); - if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { - kfree (fh->cap.read_buf); - fh->cap.read_buf = NULL; - goto err; - } - fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); - fh->cap.read_off = 0; - } - buf = (struct bttv_buffer*)fh->cap.read_buf; - } - - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -err: - return rc; -} - -static int bttv_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct bttv *btv = video_drvdata(file); - struct bttv_fh *fh; - enum v4l2_buf_type type = 0; - - dprintk("open dev=%s\n", video_device_node_name(vdev)); - - if (vdev->vfl_type == VFL_TYPE_GRABBER) { - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } else if (vdev->vfl_type == VFL_TYPE_VBI) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } else { - WARN_ON(1); - return -ENODEV; - } - - dprintk("%d: open called (type=%s)\n", - btv->c.nr, v4l2_type_names[type]); - - /* allocate per filehandle data */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (unlikely(!fh)) - return -ENOMEM; - file->private_data = fh; - - *fh = btv->init; - - fh->type = type; - fh->ov.setup_ok = 0; - - v4l2_prio_open(&btv->prio, &fh->prio); - - videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, - &btv->c.pci->dev, &btv->s_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct bttv_buffer), - fh, &btv->lock); - videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, - &btv->c.pci->dev, &btv->s_lock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct bttv_buffer), - fh, &btv->lock); - set_tvnorm(btv,btv->tvnorm); - set_input(btv, btv->input, btv->tvnorm); - - btv->users++; - - /* The V4L2 spec requires one global set of cropping parameters - which only change on request. These are stored in btv->crop[1]. - However for compatibility with V4L apps and cropping unaware - V4L2 apps we now reset the cropping parameters as seen through - this fh, which is to say VIDIOC_G_CROP and scaling limit checks - will use btv->crop[0], the default cropping parameters for the - current video standard, and VIDIOC_S_FMT will not implicitely - change the cropping parameters until VIDIOC_S_CROP has been - called. */ - fh->do_crop = !reset_crop; /* module parameter */ - - /* Likewise there should be one global set of VBI capture - parameters, but for compatibility with V4L apps and earlier - driver versions each fh has its own parameters. */ - bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); - - bttv_field_count(btv); - return 0; -} - -static int bttv_release(struct file *file) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - - /* turn off overlay */ - if (check_btres(fh, RESOURCE_OVERLAY)) - bttv_switch_overlay(btv,fh,NULL); - - /* stop video capture */ - if (check_btres(fh, RESOURCE_VIDEO_STREAM)) { - videobuf_streamoff(&fh->cap); - free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM); - } - if (fh->cap.read_buf) { - buffer_release(&fh->cap,fh->cap.read_buf); - kfree(fh->cap.read_buf); - } - if (check_btres(fh, RESOURCE_VIDEO_READ)) { - free_btres_lock(btv, fh, RESOURCE_VIDEO_READ); - } - - /* stop vbi capture */ - if (check_btres(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbi); - free_btres_lock(btv,fh,RESOURCE_VBI); - } - - /* free stuff */ - - videobuf_mmap_free(&fh->cap); - videobuf_mmap_free(&fh->vbi); - v4l2_prio_close(&btv->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - btv->users--; - bttv_field_count(btv); - - if (!btv->users) - audio_mute(btv, 1); - - return 0; -} - -static int -bttv_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct bttv_fh *fh = file->private_data; - - dprintk("%d: mmap type=%s 0x%lx+%ld\n", - fh->btv->c.nr, v4l2_type_names[fh->type], - vma->vm_start, vma->vm_end - vma->vm_start); - return videobuf_mmap_mapper(bttv_queue(fh),vma); -} - -static const struct v4l2_file_operations bttv_fops = -{ - .owner = THIS_MODULE, - .open = bttv_open, - .release = bttv_release, - .unlocked_ioctl = video_ioctl2, - .read = bttv_read, - .mmap = bttv_mmap, - .poll = bttv_poll, -}; - -static const struct v4l2_ioctl_ops bttv_ioctl_ops = { - .vidioc_querycap = bttv_querycap, - .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay, - .vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay, - .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, - .vidioc_g_audio = bttv_g_audio, - .vidioc_s_audio = bttv_s_audio, - .vidioc_cropcap = bttv_cropcap, - .vidioc_reqbufs = bttv_reqbufs, - .vidioc_querybuf = bttv_querybuf, - .vidioc_qbuf = bttv_qbuf, - .vidioc_dqbuf = bttv_dqbuf, - .vidioc_s_std = bttv_s_std, - .vidioc_enum_input = bttv_enum_input, - .vidioc_g_input = bttv_g_input, - .vidioc_s_input = bttv_s_input, - .vidioc_queryctrl = bttv_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_streamon = bttv_streamon, - .vidioc_streamoff = bttv_streamoff, - .vidioc_g_tuner = bttv_g_tuner, - .vidioc_s_tuner = bttv_s_tuner, - .vidioc_g_crop = bttv_g_crop, - .vidioc_s_crop = bttv_s_crop, - .vidioc_g_fbuf = bttv_g_fbuf, - .vidioc_s_fbuf = bttv_s_fbuf, - .vidioc_overlay = bttv_overlay, - .vidioc_g_priority = bttv_g_priority, - .vidioc_s_priority = bttv_s_priority, - .vidioc_g_parm = bttv_g_parm, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, - .vidioc_log_status = bttv_log_status, - .vidioc_querystd = bttv_querystd, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = bttv_g_register, - .vidioc_s_register = bttv_s_register, -#endif -}; - -static struct video_device bttv_video_template = { - .fops = &bttv_fops, - .ioctl_ops = &bttv_ioctl_ops, - .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -/* ----------------------------------------------------------------------- */ -/* radio interface */ - -static int radio_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct bttv *btv = video_drvdata(file); - struct bttv_fh *fh; - - dprintk("open dev=%s\n", video_device_node_name(vdev)); - - dprintk("%d: open called (radio)\n", btv->c.nr); - - /* allocate per filehandle data */ - fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (unlikely(!fh)) - return -ENOMEM; - file->private_data = fh; - *fh = btv->init; - - v4l2_prio_open(&btv->prio, &fh->prio); - - btv->radio_user++; - - bttv_call_all(btv, tuner, s_radio); - audio_input(btv,TVAUDIO_INPUT_RADIO); - - return 0; -} - -static int radio_release(struct file *file) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - - v4l2_prio_close(&btv->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - btv->radio_user--; - - bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd); - - return 0; -} - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - strcpy(cap->driver, "bttv"); - strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->capabilities = V4L2_CAP_TUNER; - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - bttv_call_all(btv, tuner, g_tuner, t); - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (0 != t->index) - return -EINVAL; - - bttv_call_all(btv, tuner, s_tuner, t); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (unlikely(i)) - return -EINVAL; - - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctl; - - return 0; -} - -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static ssize_t radio_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - cmd.block_count = count/3; - cmd.buffer = data; - cmd.instance = file; - cmd.result = -ENODEV; - - bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd); - - return cmd.result; -} - -static unsigned int radio_poll(struct file *file, poll_table *wait) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - struct saa6588_command cmd; - cmd.instance = file; - cmd.event_list = wait; - cmd.result = -ENODEV; - bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd); - - return cmd.result; -} - -static const struct v4l2_file_operations radio_fops = -{ - .owner = THIS_MODULE, - .open = radio_open, - .read = radio_read, - .release = radio_release, - .unlocked_ioctl = video_ioctl2, - .poll = radio_poll, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, -}; - -static struct video_device radio_template = { - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, -}; - -/* ----------------------------------------------------------------------- */ -/* some debug code */ - -static int bttv_risc_decode(u32 risc) -{ - static char *instr[16] = { - [ BT848_RISC_WRITE >> 28 ] = "write", - [ BT848_RISC_SKIP >> 28 ] = "skip", - [ BT848_RISC_WRITEC >> 28 ] = "writec", - [ BT848_RISC_JUMP >> 28 ] = "jump", - [ BT848_RISC_SYNC >> 28 ] = "sync", - [ BT848_RISC_WRITE123 >> 28 ] = "write123", - [ BT848_RISC_SKIP123 >> 28 ] = "skip123", - [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23", - }; - static int incr[16] = { - [ BT848_RISC_WRITE >> 28 ] = 2, - [ BT848_RISC_JUMP >> 28 ] = 2, - [ BT848_RISC_SYNC >> 28 ] = 2, - [ BT848_RISC_WRITE123 >> 28 ] = 5, - [ BT848_RISC_SKIP123 >> 28 ] = 2, - [ BT848_RISC_WRITE1S23 >> 28 ] = 3, - }; - static char *bits[] = { - "be0", "be1", "be2", "be3/resync", - "set0", "set1", "set2", "set3", - "clr0", "clr1", "clr2", "clr3", - "irq", "res", "eol", "sol", - }; - int i; - - pr_cont("0x%08x [ %s", risc, - instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) - if (risc & (1 << (i + 12))) - pr_cont(" %s", bits[i]); - pr_cont(" count=%d ]\n", risc & 0xfff); - return incr[risc >> 28] ? incr[risc >> 28] : 1; -} - -static void bttv_risc_disasm(struct bttv *btv, - struct btcx_riscmem *risc) -{ - unsigned int i,j,n; - - pr_info("%s: risc disasm: %p [dma=0x%08lx]\n", - btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma); - for (i = 0; i < (risc->size >> 2); i += n) { - pr_info("%s: 0x%lx: ", - btv->c.v4l2_dev.name, - (unsigned long)(risc->dma + (i<<2))); - n = bttv_risc_decode(le32_to_cpu(risc->cpu[i])); - for (j = 1; j < n; j++) - pr_info("%s: 0x%lx: 0x%08x [ arg #%d ]\n", - btv->c.v4l2_dev.name, - (unsigned long)(risc->dma + ((i+j)<<2)), - risc->cpu[i+j], j); - if (0 == risc->cpu[i]) - break; - } -} - -static void bttv_print_riscaddr(struct bttv *btv) -{ - pr_info(" main: %08llx\n", (unsigned long long)btv->main.dma); - pr_info(" vbi : o=%08llx e=%08llx\n", - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0); - pr_info(" cap : o=%08llx e=%08llx\n", - btv->curr.top - ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->curr.bottom - ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - pr_info(" scr : o=%08llx e=%08llx\n", - btv->screen ? (unsigned long long)btv->screen->top.dma : 0, - btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0); - bttv_risc_disasm(btv, &btv->main); -} - -/* ----------------------------------------------------------------------- */ -/* irq handler */ - -static char *irq_name[] = { - "FMTCHG", // format change detected (525 vs. 625) - "VSYNC", // vertical sync (new field) - "HSYNC", // horizontal sync - "OFLOW", // chroma/luma AGC overflow - "HLOCK", // horizontal lock changed - "VPRES", // video presence changed - "6", "7", - "I2CDONE", // hw irc operation finished - "GPINT", // gpio port triggered irq - "10", - "RISCI", // risc instruction triggered irq - "FBUS", // pixel data fifo dropped data (high pci bus latencies) - "FTRGT", // pixel data fifo overrun - "FDSR", // fifo data stream resyncronisation - "PPERR", // parity error (data transfer) - "RIPERR", // parity error (read risc instructions) - "PABORT", // pci abort - "OCERR", // risc instruction error - "SCERR", // syncronisation error -}; - -static void bttv_print_irqbits(u32 print, u32 mark) -{ - unsigned int i; - - pr_cont("bits:"); - for (i = 0; i < ARRAY_SIZE(irq_name); i++) { - if (print & (1 << i)) - pr_cont(" %s", irq_name[i]); - if (mark & (1 << i)) - pr_cont("*"); - } -} - -static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) -{ - pr_warn("%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n", - btv->c.nr, - (unsigned long)btv->main.dma, - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]), - (unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]), - (unsigned long)rc); - - if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { - pr_notice("%d: Oh, there (temporarily?) is no input signal. " - "Ok, then this is harmless, don't worry ;)\n", - btv->c.nr); - return; - } - pr_notice("%d: Uhm. Looks like we have unusual high IRQ latencies\n", - btv->c.nr); - pr_notice("%d: Lets try to catch the culpit red-handed ...\n", - btv->c.nr); - dump_stack(); -} - -static int -bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set) -{ - struct bttv_buffer *item; - - memset(set,0,sizeof(*set)); - - /* capture request ? */ - if (!list_empty(&btv->capture)) { - set->frame_irq = 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); - /* Mike Isely - Only check - * and set up the bottom field in the logic - * below. Don't ever do the top field. This - * of course means that if we set up the - * bottom field in the above code that we'll - * actually skip a field. But that's OK. - * Having processed only a single buffer this - * time, then the next time around the first - * available buffer should be for a top field. - * That will then cause us here to set up a - * top then a bottom field in the normal way. - * The alternative to this understanding is - * that we set up the second available buffer - * as a top field, but that's out of order - * since this driver always processes the top - * field first - the effect will be the two - * buffers being returned in the wrong order, - * with the second buffer also being delayed - * by one field time (owing to the fifo nature - * of videobuf). Worse still, we'll be stuck - * doing fields out of order now every time - * until something else causes a field to be - * dropped. By effectively forcing a field to - * drop this way then we always get back into - * sync within a single frame time. (Out of - * order fields can screw up deinterlacing - * algorithms.) */ - if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) { - if (NULL == set->bottom && - V4L2_FIELD_BOTTOM == item->vb.field) { - set->bottom = item; - } - if (NULL != set->top && NULL != set->bottom) - set->top_irq = 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("%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n", - btv->c.nr, set->top, set->bottom, - btv->screen, set->frame_irq, set->top_irq); - return 0; -} - -static void -bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, - struct bttv_buffer_set *curr, unsigned int state) -{ - struct timeval ts; - - do_gettimeofday(&ts); - - if (wakeup->top == wakeup->bottom) { - if (NULL != wakeup->top && curr->top != wakeup->top) { - if (irq_debug > 1) - pr_debug("%d: wakeup: both=%p\n", - btv->c.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 > 1) - pr_debug("%d: wakeup: top=%p\n", - btv->c.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 > 1) - pr_debug("%d: wakeup: bottom=%p\n", - btv->c.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_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, - unsigned int state) -{ - struct timeval ts; - - if (NULL == wakeup) - return; - - do_gettimeofday(&ts); - wakeup->vb.ts = ts; - wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = state; - wake_up(&wakeup->vb.done); -} - -static void bttv_irq_timeout(unsigned long data) -{ - struct bttv *btv = (struct bttv *)data; - struct bttv_buffer_set old,new; - struct bttv_buffer *ovbi; - struct bttv_buffer *item; - unsigned long flags; - - if (bttv_verbose) { - pr_info("%d: timeout: drop=%d irq=%d/%d, risc=%08x, ", - btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total, - btread(BT848_RISC_COUNT)); - bttv_print_irqbits(btread(BT848_INT_STAT),0); - pr_cont("\n"); - } - - spin_lock_irqsave(&btv->s_lock,flags); - - /* deactivate stuff */ - memset(&new,0,sizeof(new)); - old = btv->curr; - ovbi = btv->cvbi; - btv->curr = new; - btv->cvbi = NULL; - btv->loop_irq = 0; - bttv_buffer_activate_video(btv, &new); - bttv_buffer_activate_vbi(btv, NULL); - bttv_set_dma(btv, 0); - - /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); - - /* cancel all outstanding capture / vbi requests */ - while (!list_empty(&btv->capture)) { - item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; - wake_up(&item->vb.done); - } - while (!list_empty(&btv->vcapture)) { - item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; - wake_up(&item->vb.done); - } - - btv->errors++; - spin_unlock_irqrestore(&btv->s_lock,flags); -} - -static void -bttv_irq_wakeup_top(struct bttv *btv) -{ - struct bttv_buffer *wakeup = btv->curr.top; - - if (NULL == wakeup) - return; - - spin_lock(&btv->s_lock); - btv->curr.top_irq = 0; - btv->curr.top = NULL; - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - - do_gettimeofday(&wakeup->vb.ts); - wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = VIDEOBUF_DONE; - wake_up(&wakeup->vb.done); - spin_unlock(&btv->s_lock); -} - -static inline int is_active(struct btcx_riscmem *risc, u32 rc) -{ - if (rc < risc->dma) - return 0; - if (rc > risc->dma + risc->size) - return 0; - return 1; -} - -static void -bttv_irq_switch_video(struct bttv *btv) -{ - struct bttv_buffer_set new; - struct bttv_buffer_set old; - dma_addr_t rc; - - spin_lock(&btv->s_lock); - - /* new buffer set */ - bttv_irq_next_video(btv, &new); - rc = btread(BT848_RISC_COUNT); - if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) || - (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) { - btv->framedrop++; - if (debug_latency) - bttv_irq_debug_low_latency(btv, rc); - spin_unlock(&btv->s_lock); - return; - } - - /* switch over */ - old = btv->curr; - btv->curr = new; - btv->loop_irq &= ~1; - bttv_buffer_activate_video(btv, &new); - bttv_set_dma(btv, 0); - - /* switch input */ - if (UNSET != btv->new_input) { - video_mux(btv,btv->new_input); - btv->new_input = UNSET; - } - - /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); - spin_unlock(&btv->s_lock); -} - -static void -bttv_irq_switch_vbi(struct bttv *btv) -{ - struct bttv_buffer *new = NULL; - struct bttv_buffer *old; - u32 rc; - - spin_lock(&btv->s_lock); - - if (!list_empty(&btv->vcapture)) - new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); - old = btv->cvbi; - - rc = btread(BT848_RISC_COUNT); - if (NULL != old && (is_active(&old->top, rc) || - is_active(&old->bottom, rc))) { - btv->framedrop++; - if (debug_latency) - bttv_irq_debug_low_latency(btv, rc); - spin_unlock(&btv->s_lock); - return; - } - - /* switch */ - btv->cvbi = new; - btv->loop_irq &= ~4; - bttv_buffer_activate_vbi(btv, new); - bttv_set_dma(btv, 0); - - bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); - spin_unlock(&btv->s_lock); -} - -static irqreturn_t bttv_irq(int irq, void *dev_id) -{ - u32 stat,astat; - u32 dstat; - int count; - struct bttv *btv; - int handled = 0; - - 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) - break; - handled = 1; - btwrite(stat,BT848_INT_STAT); - - /* get device status bits */ - dstat=btread(BT848_DSTATUS); - - if (irq_debug) { - pr_debug("%d: irq loop=%d fc=%d riscs=%x, riscc=%08x, ", - btv->c.nr, count, btv->field_count, - stat>>28, btread(BT848_RISC_COUNT)); - bttv_print_irqbits(stat,astat); - if (stat & BT848_INT_HLOCK) - pr_cont(" HLOC => %s", - dstat & BT848_DSTATUS_HLOC - ? "yes" : "no"); - if (stat & BT848_INT_VPRES) - pr_cont(" PRES => %s", - dstat & BT848_DSTATUS_PRES - ? "yes" : "no"); - if (stat & BT848_INT_FMTCHG) - pr_cont(" NUML => %s", - dstat & BT848_DSTATUS_NUML - ? "625" : "525"); - pr_cont("\n"); - } - - if (astat&BT848_INT_VSYNC) - btv->field_count++; - - if ((astat & BT848_INT_GPINT) && btv->remote) { - bttv_input_irq(btv); - } - - if (astat & BT848_INT_I2CDONE) { - btv->i2c_done = stat; - wake_up(&btv->i2c_queue); - } - - if ((astat & BT848_INT_RISCI) && (stat & (4<<28))) - bttv_irq_switch_vbi(btv); - - if ((astat & BT848_INT_RISCI) && (stat & (2<<28))) - bttv_irq_wakeup_top(btv); - - if ((astat & BT848_INT_RISCI) && (stat & (1<<28))) - bttv_irq_switch_video(btv); - - if ((astat & BT848_INT_HLOCK) && btv->opt_automute) - audio_mute(btv, btv->mute); /* trigger automute */ - - if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { - pr_info("%d: %s%s @ %08x,", - btv->c.nr, - (astat & BT848_INT_SCERR) ? "SCERR" : "", - (astat & BT848_INT_OCERR) ? "OCERR" : "", - btread(BT848_RISC_COUNT)); - bttv_print_irqbits(stat,astat); - pr_cont("\n"); - if (bttv_debug) - bttv_print_riscaddr(btv); - } - if (fdsr && astat & BT848_INT_FDSR) { - pr_info("%d: FDSR @ %08x\n", - btv->c.nr, btread(BT848_RISC_COUNT)); - if (bttv_debug) - bttv_print_riscaddr(btv); - } - - count++; - if (count > 4) { - - if (count > 8 || !(astat & BT848_INT_GPINT)) { - btwrite(0, BT848_INT_MASK); - - pr_err("%d: IRQ lockup, cleared int mask [", - btv->c.nr); - } else { - pr_err("%d: IRQ lockup, clearing GPINT from int mask [", - btv->c.nr); - - btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), - BT848_INT_MASK); - }; - - bttv_print_irqbits(stat,astat); - - pr_cont("]\n"); - } - } - btv->irq_total++; - if (handled) - btv->irq_me++; - return IRQ_RETVAL(handled); -} - - -/* ----------------------------------------------------------------------- */ -/* initialitation */ - -static struct video_device *vdev_init(struct bttv *btv, - const struct video_device *template, - const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &btv->c.v4l2_dev; - vfd->release = video_device_release; - vfd->debug = bttv_debug; - video_set_drvdata(vfd, btv); - snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", - btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type_name, bttv_tvcards[btv->c.type].name); - return vfd; -} - -static void bttv_unregister_video(struct bttv *btv) -{ - if (btv->video_dev) { - if (video_is_registered(btv->video_dev)) - video_unregister_device(btv->video_dev); - else - video_device_release(btv->video_dev); - btv->video_dev = NULL; - } - if (btv->vbi_dev) { - if (video_is_registered(btv->vbi_dev)) - video_unregister_device(btv->vbi_dev); - else - video_device_release(btv->vbi_dev); - btv->vbi_dev = NULL; - } - if (btv->radio_dev) { - if (video_is_registered(btv->radio_dev)) - video_unregister_device(btv->radio_dev); - else - video_device_release(btv->radio_dev); - btv->radio_dev = NULL; - } -} - -/* register video4linux devices */ -static int __devinit bttv_register_video(struct bttv *btv) -{ - if (no_overlay > 0) - pr_notice("Overlay support disabled\n"); - - /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); - - if (NULL == btv->video_dev) - goto err; - if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, - video_nr[btv->c.nr]) < 0) - goto err; - pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->video_dev)); - if (device_create_file(&btv->video_dev->dev, - &dev_attr_card)<0) { - pr_err("%d: device_create_file 'card' failed\n", btv->c.nr); - goto err; - } - - /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); - - if (NULL == btv->vbi_dev) - goto err; - if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, - vbi_nr[btv->c.nr]) < 0) - goto err; - pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->vbi_dev)); - - if (!btv->has_radio) - return 0; - /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, "radio"); - if (NULL == btv->radio_dev) - goto err; - if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, - radio_nr[btv->c.nr]) < 0) - goto err; - pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->radio_dev)); - - /* all done */ - return 0; - - err: - bttv_unregister_video(btv); - return -1; -} - - -/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ -/* response on cards with no firmware is not enabled by OF */ -static void pci_set_command(struct pci_dev *dev) -{ -#if defined(__powerpc__) - unsigned int cmd; - - pci_read_config_dword(dev, PCI_COMMAND, &cmd); - cmd = (cmd | PCI_COMMAND_MEMORY ); - pci_write_config_dword(dev, PCI_COMMAND, cmd); -#endif -} - -static int __devinit bttv_probe(struct pci_dev *dev, - const struct pci_device_id *pci_id) -{ - int result; - unsigned char lat; - struct bttv *btv; - - if (bttv_num == BTTV_MAX) - return -ENOMEM; - pr_info("Bt8xx card found (%d)\n", bttv_num); - bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL); - if (btv == NULL) { - pr_err("out of memory\n"); - return -ENOMEM; - } - btv->c.nr = bttv_num; - snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name), - "bttv%d", btv->c.nr); - - /* initialize structs / fill in defaults */ - mutex_init(&btv->lock); - spin_lock_init(&btv->s_lock); - spin_lock_init(&btv->gpio_lock); - init_waitqueue_head(&btv->i2c_queue); - INIT_LIST_HEAD(&btv->c.subs); - INIT_LIST_HEAD(&btv->capture); - INIT_LIST_HEAD(&btv->vcapture); - v4l2_prio_init(&btv->prio); - - init_timer(&btv->timeout); - btv->timeout.function = bttv_irq_timeout; - btv->timeout.data = (unsigned long)btv; - - btv->i2c_rc = -1; - btv->tuner_type = UNSET; - btv->new_input = UNSET; - btv->has_radio=radio[btv->c.nr]; - - /* pci stuff (init, get irq/mmio, ... */ - btv->c.pci = dev; - btv->id = dev->device; - if (pci_enable_device(dev)) { - pr_warn("%d: Can't enable device\n", btv->c.nr); - return -EIO; - } - if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { - pr_warn("%d: No suitable DMA available\n", btv->c.nr); - return -EIO; - } - if (!request_mem_region(pci_resource_start(dev,0), - pci_resource_len(dev,0), - btv->c.v4l2_dev.name)) { - pr_warn("%d: can't request iomem (0x%llx)\n", - btv->c.nr, - (unsigned long long)pci_resource_start(dev, 0)); - return -EBUSY; - } - pci_set_master(dev); - pci_set_command(dev); - - result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev); - if (result < 0) { - pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); - goto fail0; - } - - btv->revision = dev->revision; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - pr_info("%d: Bt%d (rev %d) at %s, irq: %d, latency: %d, mmio: 0x%llx\n", - bttv_num, btv->id, btv->revision, pci_name(dev), - btv->c.pci->irq, lat, - (unsigned long long)pci_resource_start(dev, 0)); - schedule(); - - btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000); - if (NULL == btv->bt848_mmio) { - pr_err("%d: ioremap() failed\n", btv->c.nr); - result = -EIO; - goto fail1; - } - - /* identify card */ - bttv_idcard(btv); - - /* disable irqs, register irq handler */ - btwrite(0, BT848_INT_MASK); - result = request_irq(btv->c.pci->irq, bttv_irq, - IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv); - if (result < 0) { - pr_err("%d: can't get IRQ %d\n", - bttv_num, btv->c.pci->irq); - goto fail1; - } - - if (0 != bttv_handle_chipset(btv)) { - result = -EIO; - goto fail2; - } - - /* init options from insmod args */ - btv->opt_combfilter = combfilter; - btv->opt_lumafilter = lumafilter; - btv->opt_automute = automute; - btv->opt_chroma_agc = chroma_agc; - btv->opt_adc_crush = adc_crush; - btv->opt_vcr_hack = vcr_hack; - btv->opt_whitecrush_upper = whitecrush_upper; - btv->opt_whitecrush_lower = whitecrush_lower; - btv->opt_uv_ratio = uv_ratio; - btv->opt_full_luma_range = full_luma_range; - btv->opt_coring = coring; - - /* fill struct bttv with some useful defaults */ - btv->init.btv = btv; - btv->init.ov.w.width = 320; - btv->init.ov.w.height = 240; - btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - btv->init.width = 320; - btv->init.height = 240; - btv->input = 0; - - /* initialize hardware */ - if (bttv_gpio) - bttv_gpio_tracking(btv,"pre-init"); - - bttv_risc_init_main(btv); - init_bt848(btv); - - /* gpio */ - btwrite(0x00, BT848_GPIO_REG_INP); - btwrite(0x00, BT848_GPIO_OUT_EN); - if (bttv_verbose) - bttv_gpio_tracking(btv,"init"); - - /* needs to be done before i2c is registered */ - bttv_init_card1(btv); - - /* register i2c + gpio */ - init_bttv_i2c(btv); - - /* some card-specific stuff (needs working i2c) */ - bttv_init_card2(btv); - bttv_init_tuner(btv); - init_irqreg(btv); - - /* register video4linux + input */ - if (!bttv_tvcards[btv->c.type].no_video) { - bttv_register_video(btv); - bt848_bright(btv,32768); - bt848_contrast(btv, 27648); - bt848_hue(btv,32768); - bt848_sat(btv,32768); - audio_mute(btv, 1); - set_input(btv, 0, btv->tvnorm); - bttv_crop_reset(&btv->crop[0], btv->tvnorm); - btv->crop[1] = btv->crop[0]; /* current = default */ - disclaim_vbi_lines(btv); - disclaim_video_lines(btv); - } - - /* add subdevices and autoload dvb-bt8xx if needed */ - if (bttv_tvcards[btv->c.type].has_dvb) { - bttv_sub_add_device(&btv->c, "dvb"); - request_modules(btv); - } - - if (!disable_ir) { - init_bttv_i2c_ir(btv); - bttv_input_init(btv); - } - - /* everything is fine */ - bttv_num++; - return 0; - -fail2: - free_irq(btv->c.pci->irq,btv); - -fail1: - v4l2_device_unregister(&btv->c.v4l2_dev); - -fail0: - if (btv->bt848_mmio) - iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->c.pci,0), - pci_resource_len(btv->c.pci,0)); - return result; -} - -static void __devexit bttv_remove(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - - if (bttv_verbose) - pr_info("%d: unloading\n", btv->c.nr); - - if (bttv_tvcards[btv->c.type].has_dvb) - flush_request_modules(btv); - - /* shutdown everything (DMA+IRQs) */ - btand(~15, BT848_GPIO_DMA_CTL); - btwrite(0, BT848_INT_MASK); - btwrite(~0x0, BT848_INT_STAT); - btwrite(0x0, BT848_GPIO_OUT_EN); - if (bttv_gpio) - bttv_gpio_tracking(btv,"cleanup"); - - /* tell gpio modules we are leaving ... */ - btv->shutdown=1; - bttv_input_fini(btv); - bttv_sub_del_devices(&btv->c); - - /* unregister i2c_bus + input */ - fini_bttv_i2c(btv); - - /* unregister video4linux */ - bttv_unregister_video(btv); - - /* free allocated memory */ - btcx_riscmem_free(btv->c.pci,&btv->main); - - /* free ressources */ - free_irq(btv->c.pci->irq,btv); - iounmap(btv->bt848_mmio); - release_mem_region(pci_resource_start(btv->c.pci,0), - pci_resource_len(btv->c.pci,0)); - - v4l2_device_unregister(&btv->c.v4l2_dev); - bttvs[btv->c.nr] = NULL; - kfree(btv); - - return; -} - -#ifdef CONFIG_PM -static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - struct bttv_buffer_set idle; - unsigned long flags; - - dprintk("%d: suspend %d\n", btv->c.nr, state.event); - - /* stop dma + irqs */ - spin_lock_irqsave(&btv->s_lock,flags); - memset(&idle, 0, sizeof(idle)); - btv->state.video = btv->curr; - btv->state.vbi = btv->cvbi; - btv->state.loop_irq = btv->loop_irq; - btv->curr = idle; - btv->loop_irq = 0; - bttv_buffer_activate_video(btv, &idle); - bttv_buffer_activate_vbi(btv, NULL); - bttv_set_dma(btv, 0); - btwrite(0, BT848_INT_MASK); - spin_unlock_irqrestore(&btv->s_lock,flags); - - /* save bt878 state */ - btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN); - btv->state.gpio_data = gpio_read(); - - /* save pci state */ - pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { - pci_disable_device(pci_dev); - btv->state.disabled = 1; - } - return 0; -} - -static int bttv_resume(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct bttv *btv = to_bttv(v4l2_dev); - unsigned long flags; - int err; - - dprintk("%d: resume\n", btv->c.nr); - - /* restore pci state */ - if (btv->state.disabled) { - err=pci_enable_device(pci_dev); - if (err) { - pr_warn("%d: Can't enable device\n", btv->c.nr); - return err; - } - btv->state.disabled = 0; - } - err=pci_set_power_state(pci_dev, PCI_D0); - if (err) { - pci_disable_device(pci_dev); - pr_warn("%d: Can't enable device\n", btv->c.nr); - btv->state.disabled = 1; - return err; - } - - pci_restore_state(pci_dev); - - /* restore bt878 state */ - bttv_reinit_bt848(btv); - gpio_inout(0xffffff, btv->state.gpio_enable); - gpio_write(btv->state.gpio_data); - - /* restart dma */ - spin_lock_irqsave(&btv->s_lock,flags); - btv->curr = btv->state.video; - btv->cvbi = btv->state.vbi; - btv->loop_irq = btv->state.loop_irq; - bttv_buffer_activate_video(btv, &btv->curr); - bttv_buffer_activate_vbi(btv, btv->cvbi); - bttv_set_dma(btv, 0); - spin_unlock_irqrestore(&btv->s_lock,flags); - return 0; -} -#endif - -static struct pci_device_id bttv_pci_tbl[] = { - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 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 = __devexit_p(bttv_remove), -#ifdef CONFIG_PM - .suspend = bttv_suspend, - .resume = bttv_resume, -#endif -}; - -static int __init bttv_init_module(void) -{ - int ret; - - bttv_num = 0; - - pr_info("driver version %s loaded\n", BTTV_VERSION); - if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) - gbuffers = 2; - if (gbufsize > BTTV_MAX_FBUF) - gbufsize = BTTV_MAX_FBUF; - gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; - if (bttv_verbose) - pr_info("using %d buffers with %dk (%d pages) each for capture\n", - gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT); - - bttv_check_chipset(); - - ret = bus_register(&bttv_sub_bus_type); - if (ret < 0) { - pr_warn("bus_register error: %d\n", ret); - return ret; - } - ret = pci_register_driver(&bttv_pci_driver); - if (ret < 0) - bus_unregister(&bttv_sub_bus_type); - - return ret; -} - -static void __exit bttv_cleanup_module(void) -{ - pci_unregister_driver(&bttv_pci_driver); - bus_unregister(&bttv_sub_bus_type); -} - -module_init(bttv_init_module); -module_exit(bttv_cleanup_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c deleted file mode 100644 index 922e8233fd0b..000000000000 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - - bttv-gpio.c -- gpio sub drivers - - sysfs-based sub driver interface for bttv - mainly intended for gpio access - - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999-2003 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include "bttvp.h" - -/* ----------------------------------------------------------------------- */ -/* internal: the bttv "bus" */ - -static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv) -{ - struct bttv_sub_driver *sub = to_bttv_sub_drv(drv); - int len = strlen(sub->wanted); - - if (0 == strncmp(dev_name(dev), sub->wanted, len)) - return 1; - return 0; -} - -static int bttv_sub_probe(struct device *dev) -{ - struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); - struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); - - return sub->probe ? sub->probe(sdev) : -ENODEV; -} - -static int bttv_sub_remove(struct device *dev) -{ - struct bttv_sub_device *sdev = to_bttv_sub_dev(dev); - struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver); - - if (sub->remove) - sub->remove(sdev); - return 0; -} - -struct bus_type bttv_sub_bus_type = { - .name = "bttv-sub", - .match = &bttv_sub_bus_match, - .probe = bttv_sub_probe, - .remove = bttv_sub_remove, -}; - -static void release_sub_device(struct device *dev) -{ - struct bttv_sub_device *sub = to_bttv_sub_dev(dev); - kfree(sub); -} - -int bttv_sub_add_device(struct bttv_core *core, char *name) -{ - struct bttv_sub_device *sub; - int err; - - sub = kzalloc(sizeof(*sub),GFP_KERNEL); - if (NULL == sub) - return -ENOMEM; - - sub->core = core; - sub->dev.parent = &core->pci->dev; - sub->dev.bus = &bttv_sub_bus_type; - sub->dev.release = release_sub_device; - dev_set_name(&sub->dev, "%s%d", name, core->nr); - - err = device_register(&sub->dev); - if (0 != err) { - kfree(sub); - return err; - } - pr_info("%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev)); - list_add_tail(&sub->list,&core->subs); - return 0; -} - -int bttv_sub_del_devices(struct bttv_core *core) -{ - struct bttv_sub_device *sub, *save; - - list_for_each_entry_safe(sub, save, &core->subs, list) { - list_del(&sub->list); - device_unregister(&sub->dev); - } - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* external: sub-driver register/unregister */ - -int bttv_sub_register(struct bttv_sub_driver *sub, char *wanted) -{ - sub->drv.bus = &bttv_sub_bus_type; - snprintf(sub->wanted,sizeof(sub->wanted),"%s",wanted); - return driver_register(&sub->drv); -} -EXPORT_SYMBOL(bttv_sub_register); - -int bttv_sub_unregister(struct bttv_sub_driver *sub) -{ - driver_unregister(&sub->drv); - return 0; -} -EXPORT_SYMBOL(bttv_sub_unregister); - -/* ----------------------------------------------------------------------- */ -/* external: gpio access functions */ - -void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) -{ - struct bttv *btv = container_of(core, struct bttv, c); - unsigned long flags; - u32 data; - - spin_lock_irqsave(&btv->gpio_lock,flags); - data = btread(BT848_GPIO_OUT_EN); - data = data & ~mask; - data = data | (mask & outbits); - btwrite(data,BT848_GPIO_OUT_EN); - spin_unlock_irqrestore(&btv->gpio_lock,flags); -} - -u32 bttv_gpio_read(struct bttv_core *core) -{ - struct bttv *btv = container_of(core, struct bttv, c); - u32 value; - - value = btread(BT848_GPIO_DATA); - return value; -} - -void bttv_gpio_write(struct bttv_core *core, u32 value) -{ - struct bttv *btv = container_of(core, struct bttv, c); - - btwrite(value,BT848_GPIO_DATA); -} - -void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) -{ - struct bttv *btv = container_of(core, struct bttv, c); - unsigned long flags; - u32 data; - - spin_lock_irqsave(&btv->gpio_lock,flags); - data = btread(BT848_GPIO_DATA); - data = data & ~mask; - data = data | (mask & bits); - btwrite(data,BT848_GPIO_DATA); - spin_unlock_irqrestore(&btv->gpio_lock,flags); -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c deleted file mode 100644 index 580c8e682392..000000000000 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - - bttv-i2c.c -- all the i2c code is here - - 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-2003 Gerd Knorr - - (c) 2005 Mauro Carvalho Chehab - - Multituner support and i2c address binding - - 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include - -#include "bttvp.h" -#include -#include -#include - -static int i2c_debug; -static int i2c_hw; -static int i2c_scan; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); -module_param(i2c_hw, int, 0444); -MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " - "instead of software bitbang"); -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); - -static unsigned int i2c_udelay = 5; -module_param(i2c_udelay, int, 0444); -MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs " - "(should be 5 or higher). Lower value means higher bus speed."); - -/* ----------------------------------------------------------------------- */ -/* I2C functions - bitbanging adapter (software i2c) */ - -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 struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = { - .setsda = bttv_bit_setsda, - .setscl = bttv_bit_setscl, - .getsda = bttv_bit_getsda, - .getscl = bttv_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - hardware i2c */ - -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static int -bttv_i2c_wait_done(struct bttv *btv) -{ - int rc = 0; - - /* timeout */ - if (wait_event_interruptible_timeout(btv->i2c_queue, - btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS) - rc = -EIO; - - if (btv->i2c_done & BT848_INT_RACK) - rc = 1; - btv->i2c_done = 0; - return rc; -} - -#define I2C_HW (BT878_I2C_MODE | BT848_I2C_SYNC |\ - BT848_I2C_SCL | BT848_I2C_SDA) - -static int -bttv_i2c_sendbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - int retval,cnt; - - /* sanity checks */ - if (0 == msg->len) - return -EINVAL; - - /* start, address + first byte */ - xmit = (msg->addr << 25) | (msg->buf[0] << 16) | I2C_HW; - if (msg->len > 1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) { - pr_cont(" addr << 1, msg->buf[0]); - } - - for (cnt = 1; cnt < msg->len; cnt++ ) { - /* following bytes */ - xmit = (msg->buf[cnt] << 24) | I2C_HW | BT878_I2C_NOSTART; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - if (i2c_debug) - pr_cont(" %02x", msg->buf[cnt]); - } - if (!(xmit & BT878_I2C_NOSTOP)) - pr_cont(">\n"); - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - pr_cont(" ERR: %d\n",retval); - return retval; -} - -static int -bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last) -{ - u32 xmit; - u32 cnt; - int retval; - - for (cnt = 0; cnt < msg->len; cnt++) { - xmit = (msg->addr << 25) | (1 << 24) | I2C_HW; - if (cnt < msg->len-1) - xmit |= BT848_I2C_W3B; - if (cnt < msg->len-1 || !last) - xmit |= BT878_I2C_NOSTOP; - if (cnt) - xmit |= BT878_I2C_NOSTART; - - if (i2c_debug) { - if (!(xmit & BT878_I2C_NOSTART)) - pr_cont(" addr << 1) +1); - } - - btwrite(xmit, BT848_I2C); - retval = bttv_i2c_wait_done(btv); - if (retval < 0) - goto err; - if (retval == 0) - goto eio; - msg->buf[cnt] = ((u32)btread(BT848_I2C) >> 8) & 0xff; - if (i2c_debug) { - pr_cont(" =%02x", msg->buf[cnt]); - } - if (i2c_debug && !(xmit & BT878_I2C_NOSTOP)) - pr_cont(" >\n"); - } - - - return msg->len; - - eio: - retval = -EIO; - err: - if (i2c_debug) - pr_cont(" ERR: %d\n",retval); - return retval; -} - -static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) -{ - struct v4l2_device *v4l2_dev = i2c_get_adapdata(i2c_adap); - struct bttv *btv = to_bttv(v4l2_dev); - int retval = 0; - int i; - - if (i2c_debug) - pr_debug("bt-i2c:"); - - btwrite(BT848_INT_I2CDONE|BT848_INT_RACK, BT848_INT_STAT); - for (i = 0 ; i < num; i++) { - if (msgs[i].flags & I2C_M_RD) { - /* read */ - retval = bttv_i2c_readbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } else { - /* write */ - retval = bttv_i2c_sendbytes(btv, &msgs[i], i+1 == num); - if (retval < 0) - goto err; - } - } - return num; - - err: - return retval; -} - -static const struct i2c_algorithm bttv_algo = { - .master_xfer = bttv_i2c_xfer, - .functionality = functionality, -}; - -/* ----------------------------------------------------------------------- */ -/* I2C functions - common stuff */ - -/* read I2C */ -int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) -{ - unsigned char buffer = 0; - - if (0 != btv->i2c_rc) - return -1; - if (bttv_verbose && NULL != probe_for) - pr_info("%d: i2c: checking for %s @ 0x%02x... ", - btv->c.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) - pr_cont("not found\n"); - } else - pr_warn("%d: i2c read 0x%x: error\n", - btv->c.nr, addr); - return -1; - } - if (bttv_verbose && NULL != probe_for) - pr_cont("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_rc) - 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) -{ - memset(eedata, 0, 256); - if (0 != btv->i2c_rc) - return; - btv->i2c_client.addr = addr >> 1; - tveeprom_read(&btv->i2c_client, eedata, 256); -} - -static char *i2c_devs[128] = { - [ 0x1c >> 1 ] = "lgdt330x", - [ 0x30 >> 1 ] = "IR (hauppauge)", - [ 0x80 >> 1 ] = "msp34xx", - [ 0x86 >> 1 ] = "tda9887", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner (analog)", - [ 0xc2 >> 1 ] = "tuner (analog)", -}; - -static void do_i2c_scan(char *name, struct i2c_client *c) -{ - unsigned char buf; - int i,rc; - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c,&buf,0); - if (rc < 0) - continue; - pr_info("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } -} - -/* init + register i2c adapter */ -int __devinit init_bttv_i2c(struct bttv *btv) -{ - strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); - - if (i2c_hw) - btv->use_i2c_hw = 1; - if (btv->use_i2c_hw) { - /* bt878 */ - strlcpy(btv->c.i2c_adap.name, "bt878", - sizeof(btv->c.i2c_adap.name)); - btv->c.i2c_adap.algo = &bttv_algo; - } else { - /* bt848 */ - /* Prevents usage of invalid delay values */ - if (i2c_udelay<5) - i2c_udelay=5; - - strlcpy(btv->c.i2c_adap.name, "bttv", - sizeof(btv->c.i2c_adap.name)); - memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template, - sizeof(bttv_i2c_algo_bit_template)); - btv->i2c_algo.udelay = i2c_udelay; - btv->i2c_algo.data = btv; - btv->c.i2c_adap.algo_data = &btv->i2c_algo; - } - btv->c.i2c_adap.owner = THIS_MODULE; - - btv->c.i2c_adap.dev.parent = &btv->c.pci->dev; - snprintf(btv->c.i2c_adap.name, sizeof(btv->c.i2c_adap.name), - "bt%d #%d [%s]", btv->id, btv->c.nr, - btv->use_i2c_hw ? "hw" : "sw"); - - i2c_set_adapdata(&btv->c.i2c_adap, &btv->c.v4l2_dev); - btv->i2c_client.adapter = &btv->c.i2c_adap; - - - if (btv->use_i2c_hw) { - btv->i2c_rc = i2c_add_adapter(&btv->c.i2c_adap); - } else { - bttv_bit_setscl(btv,1); - bttv_bit_setsda(btv,1); - btv->i2c_rc = i2c_bit_add_bus(&btv->c.i2c_adap); - } - if (0 == btv->i2c_rc && i2c_scan) - do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); - - return btv->i2c_rc; -} diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c deleted file mode 100644 index a6a540dc9e4b..000000000000 --- a/drivers/media/video/bt8xx/bttv-if.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - - bttv-if.c -- old gpio interface to other kernel modules - don't use in new code, will go away in 2.7 - have a look at bttv-gpio.c instead. - - 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-2003 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 "bttvp.h" - -EXPORT_SYMBOL(bttv_get_pcidev); -EXPORT_SYMBOL(bttv_gpio_enable); -EXPORT_SYMBOL(bttv_read_gpio); -EXPORT_SYMBOL(bttv_write_gpio); - -/* ----------------------------------------------------------------------- */ -/* Exported functions - for other modules which want to access the */ -/* gpio ports (IR for example) */ -/* see bttv.h for comments */ - -struct pci_dev* bttv_get_pcidev(unsigned int card) -{ - if (card >= bttv_num) - return NULL; - if (!bttvs[card]) - return NULL; - - return bttvs[card]->c.pci; -} - - -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]; - if (!btv) - return -ENODEV; - - gpio_inout(mask,data); - if (bttv_gpio) - bttv_gpio_tracking(btv,"extern enable"); - 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) - return -ENODEV; - - if(btv->shutdown) { - return -ENODEV; - } - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because we set direct input on init */ - *data = gpio_read(); - 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]; - if (!btv) - return -ENODEV; - -/* prior setting BT848_GPIO_REG_INP is (probably) not needed - because direct input is set on init */ - gpio_bits(mask,data); - if (bttv_gpio) - bttv_gpio_tracking(btv,"extern write"); - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c deleted file mode 100644 index ef4c7cd41982..000000000000 --- a/drivers/media/video/bt8xx/bttv-input.c +++ /dev/null @@ -1,589 +0,0 @@ -/* - * - * Copyright (c) 2003 Gerd Knorr - * Copyright (c) 2003 Pavel Machek - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include "bttv.h" -#include "bttvp.h" - - -static int ir_debug; -module_param(ir_debug, int, 0644); - -static int ir_rc5_remote_gap = 885; -module_param(ir_rc5_remote_gap, int, 0644); - -#undef dprintk -#define dprintk(fmt, ...) \ -do { \ - if (ir_debug >= 1) \ - pr_info(fmt, ##__VA_ARGS__); \ -} while (0) - -#define DEVNAME "bttv-input" - -#define MODULE_NAME "bttv" - -/* ---------------------------------------------------------------------- */ - -static void ir_handle_key(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - u32 gpio,data; - - /* read gpio value */ - gpio = bttv_gpio_read(&btv->c); - if (ir->polling) { - if (ir->last_gpio == gpio) - return; - ir->last_gpio = gpio; - } - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk("irq gpio=0x%x code=%d | %s%s%s\n", - gpio, data, - ir->polling ? "poll" : "irq", - (gpio & ir->mask_keydown) ? " down" : "", - (gpio & ir->mask_keyup) ? " up" : ""); - - if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || - (ir->mask_keyup && !(gpio & ir->mask_keyup))) { - rc_keydown_notimeout(ir->dev, data, 0); - } else { - /* HACK: Probably, ir->mask_keydown is missing - for this board */ - if (btv->c.type == BTTV_BOARD_WINFAST2000) - rc_keydown_notimeout(ir->dev, data, 0); - - rc_keyup(ir->dev); - } -} - -static void ir_enltv_handle_key(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - u32 gpio, data, keyup; - - /* read gpio value */ - gpio = bttv_gpio_read(&btv->c); - - /* extract data */ - data = ir_extract_bits(gpio, ir->mask_keycode); - - /* Check if it is keyup */ - keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; - - if ((ir->last_gpio & 0x7f) != data) { - dprintk("gpio=0x%x code=%d | %s\n", - gpio, data, - (gpio & ir->mask_keyup) ? " up" : "up/down"); - - rc_keydown_notimeout(ir->dev, data, 0); - if (keyup) - rc_keyup(ir->dev); - } else { - if ((ir->last_gpio & 1 << 31) == keyup) - return; - - dprintk("(cnt) gpio=0x%x code=%d | %s\n", - gpio, data, - (gpio & ir->mask_keyup) ? " up" : "down"); - - if (keyup) - rc_keyup(ir->dev); - else - rc_keydown_notimeout(ir->dev, data, 0); - } - - ir->last_gpio = data | keyup; -} - -static int bttv_rc5_irq(struct bttv *btv); - -void bttv_input_irq(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - - if (ir->rc5_gpio) - bttv_rc5_irq(btv); - else if (!ir->polling) - ir_handle_key(btv); -} - -static void bttv_input_timer(unsigned long data) -{ - struct bttv *btv = (struct bttv*)data; - struct bttv_ir *ir = btv->remote; - - if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) - ir_enltv_handle_key(btv); - else - ir_handle_key(btv); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); -} - -/* - * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying - * on the rc-core way. As we need to be sure that both IRQ transitions are - * properly triggered, Better to touch it only with this hardware for - * testing. - */ - -#define RC5_START(x) (((x) >> 12) & 3) -#define RC5_TOGGLE(x) (((x) >> 11) & 1) -#define RC5_ADDR(x) (((x) >> 6) & 31) -#define RC5_INSTR(x) ((x) & 63) - -/* decode raw bit pattern to RC5 code */ -static u32 bttv_rc5_decode(unsigned int code) -{ - unsigned int org_code = code; - unsigned int pair; - unsigned int rc5 = 0; - int i; - - for (i = 0; i < 14; ++i) { - pair = code & 0x3; - code >>= 2; - - rc5 <<= 1; - switch (pair) { - case 0: - case 2: - break; - case 1: - rc5 |= 1; - break; - case 3: - dprintk("rc5_decode(%x) bad code\n", - org_code); - return 0; - } - } - dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " - "instr=%x\n", rc5, org_code, RC5_START(rc5), - RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); - return rc5; -} - -static void bttv_rc5_timer_end(unsigned long data) -{ - struct bttv_ir *ir = (struct bttv_ir *)data; - struct timeval tv; - u32 gap; - u32 rc5 = 0; - - /* get time */ - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - /* signal we're ready to start a new code */ - ir->active = false; - - /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */ - if (gap < 28000) { - dprintk("spurious timer_end\n"); - return; - } - - if (ir->last_bit < 20) { - /* ignore spurious codes (caused by light/other remotes) */ - dprintk("short code: %x\n", ir->code); - } else { - ir->code = (ir->code << ir->shift_by) | 1; - rc5 = bttv_rc5_decode(ir->code); - - /* two start bits? */ - if (RC5_START(rc5) != ir->start) { - pr_info(DEVNAME ":" - " rc5 start bits invalid: %u\n", RC5_START(rc5)); - - /* right address? */ - } else if (RC5_ADDR(rc5) == ir->addr) { - u32 toggle = RC5_TOGGLE(rc5); - u32 instr = RC5_INSTR(rc5); - - /* Good code */ - rc_keydown(ir->dev, instr, toggle); - dprintk("instruction %x, toggle %x\n", - instr, toggle); - } - } -} - -static int bttv_rc5_irq(struct bttv *btv) -{ - struct bttv_ir *ir = btv->remote; - struct timeval tv; - u32 gpio; - u32 gap; - unsigned long current_jiffies; - - /* read gpio port */ - gpio = bttv_gpio_read(&btv->c); - - /* get time of bit */ - current_jiffies = jiffies; - do_gettimeofday(&tv); - - /* avoid overflow with gap >1s */ - if (tv.tv_sec - ir->base_time.tv_sec > 1) { - gap = 200000; - } else { - gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + - tv.tv_usec - ir->base_time.tv_usec; - } - - dprintk("RC5 IRQ: gap %d us for %s\n", - gap, (gpio & 0x20) ? "mark" : "space"); - - /* remote IRQ? */ - if (!(gpio & 0x20)) - return 0; - - /* active code => add bit */ - if (ir->active) { - /* only if in the code (otherwise spurious IRQ or timer - late) */ - if (ir->last_bit < 28) { - ir->last_bit = (gap - ir_rc5_remote_gap / 2) / - ir_rc5_remote_gap; - ir->code |= 1 << ir->last_bit; - } - /* starting new code */ - } else { - ir->active = true; - ir->code = 0; - ir->base_time = tv; - ir->last_bit = 0; - - mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30)); - } - - /* toggle GPIO pin 4 to reset the irq */ - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - bttv_gpio_write(&btv->c, gpio | (1 << 4)); - return 1; -} - -/* ---------------------------------------------------------------------- */ - -static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) -{ - if (ir->polling) { - setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv); - ir->timer.expires = jiffies + msecs_to_jiffies(1000); - add_timer(&ir->timer); - } else if (ir->rc5_gpio) { - /* set timer_end for code completion */ - setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir); - ir->shift_by = 1; - ir->start = 3; - ir->addr = 0x0; - ir->rc5_remote_gap = ir_rc5_remote_gap; - } -} - -static void bttv_ir_stop(struct bttv *btv) -{ - if (btv->remote->polling) - del_timer_sync(&btv->remote->timer); - - if (btv->remote->rc5_gpio) { - u32 gpio; - - del_timer_sync(&btv->remote->timer); - - gpio = bttv_gpio_read(&btv->c); - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - } -} - -/* - * Get_key functions used by I2C remotes - */ - -static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk("read error\n"); - return -EIO; - } - - /* ignore 0xaa */ - if (b==0xaa) - return 0; - dprintk("key %02x\n", b); - - /* - * NOTE: - * lirc_i2c maps the pv951 code as: - * addr = 0x61D6 - * cmd = bit_reverse (b) - * So, it seems that this device uses NEC extended - * I decided to not fix the table, due to two reasons: - * 1) Without the actual device, this is only a guess; - * 2) As the addr is not reported via I2C, nor can be changed, - * the device is bound to the vendor-provided RC. - */ - - *ir_key = b; - *ir_raw = b; - return 1; -} - -/* Instantiate the I2C IR receiver device, if present */ -void __devinit init_bttv_i2c_ir(struct bttv *btv) -{ - const unsigned short addr_list[] = { - 0x1a, 0x18, 0x64, 0x30, 0x71, - I2C_CLIENT_END - }; - struct i2c_board_info info; - - if (0 != btv->i2c_rc) - return; - - memset(&info, 0, sizeof(struct i2c_board_info)); - memset(&btv->init_data, 0, sizeof(btv->init_data)); - strlcpy(info.type, "ir_video", I2C_NAME_SIZE); - - switch (btv->c.type) { - case BTTV_BOARD_PV951: - btv->init_data.name = "PV951"; - btv->init_data.get_key = get_key_pv951; - btv->init_data.ir_codes = RC_MAP_PV951; - info.addr = 0x4b; - break; - default: - /* - * The external IR receiver is at i2c address 0x34 (0x35 for - * reads). Future Hauppauge cards will have an internal - * receiver at 0x30 (0x31 for reads). In theory, both can be - * fitted, and Hauppauge suggest an external overrides an - * internal. - * That's why we probe 0x1a (~0x34) first. CB - */ - - i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); - return; - } - - if (btv->init_data.name) - info.platform_data = &btv->init_data; - i2c_new_device(&btv->c.i2c_adap, &info); - - return; -} - -int __devexit fini_bttv_i2c(struct bttv *btv) -{ - if (0 != btv->i2c_rc) - return 0; - - return i2c_del_adapter(&btv->c.i2c_adap); -} - -int bttv_input_init(struct bttv *btv) -{ - struct bttv_ir *ir; - char *ir_codes = NULL; - struct rc_dev *rc; - int err = -ENOMEM; - - if (!btv->has_remote) - return -ENODEV; - - ir = kzalloc(sizeof(*ir),GFP_KERNEL); - rc = rc_allocate_device(); - if (!ir || !rc) - goto err_out_free; - - /* detect & configure */ - switch (btv->c.type) { - case BTTV_BOARD_AVERMEDIA: - case BTTV_BOARD_AVPHONE98: - case BTTV_BOARD_AVERMEDIA98: - ir_codes = RC_MAP_AVERMEDIA; - ir->mask_keycode = 0xf88000; - ir->mask_keydown = 0x010000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_AVDVBT_761: - case BTTV_BOARD_AVDVBT_771: - ir_codes = RC_MAP_AVERMEDIA_DVBT; - ir->mask_keycode = 0x0f00c0; - ir->mask_keydown = 0x000020; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_PXELVWPLTVPAK: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x003e00; - ir->mask_keyup = 0x010000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_PV_M4900: - case BTTV_BOARD_PV_BT878P_9B: - case BTTV_BOARD_PV_BT878P_PLUS: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - - case BTTV_BOARD_WINFAST2000: - ir_codes = RC_MAP_WINFAST; - ir->mask_keycode = 0x1f8; - break; - case BTTV_BOARD_MAGICTVIEW061: - case BTTV_BOARD_MAGICTVIEW063: - ir_codes = RC_MAP_WINFAST; - ir->mask_keycode = 0x0008e000; - ir->mask_keydown = 0x00200000; - break; - case BTTV_BOARD_APAC_VIEWCOMP: - ir_codes = RC_MAP_APAC_VIEWCOMP; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x008000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_ASKEY_CPH03X: - case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: - case BTTV_BOARD_CONTVFMI: - ir_codes = RC_MAP_PIXELVIEW; - ir->mask_keycode = 0x001F00; - ir->mask_keyup = 0x006000; - ir->polling = 50; // ms - break; - case BTTV_BOARD_NEBULA_DIGITV: - ir_codes = RC_MAP_NEBULA; - ir->rc5_gpio = true; - break; - case BTTV_BOARD_MACHTV_MAGICTV: - ir_codes = RC_MAP_APAC_VIEWCOMP; - ir->mask_keycode = 0x001F00; - ir->mask_keyup = 0x004000; - ir->polling = 50; /* ms */ - break; - case BTTV_BOARD_KOZUMI_KTV_01C: - ir_codes = RC_MAP_PCTV_SEDNA; - ir->mask_keycode = 0x001f00; - ir->mask_keyup = 0x006000; - ir->polling = 50; /* ms */ - break; - case BTTV_BOARD_ENLTV_FM_2: - ir_codes = RC_MAP_ENCORE_ENLTV2; - ir->mask_keycode = 0x00fd00; - ir->mask_keyup = 0x000080; - ir->polling = 1; /* ms */ - ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), - ir->mask_keycode); - break; - } - if (NULL == ir_codes) { - dprintk("Ooops: IR config error [card=%d]\n", btv->c.type); - err = -ENODEV; - goto err_out_free; - } - - if (ir->rc5_gpio) { - u32 gpio; - /* enable remote irq */ - bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4); - gpio = bttv_gpio_read(&btv->c); - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - bttv_gpio_write(&btv->c, gpio | (1 << 4)); - } else { - /* init hardware-specific stuff */ - bttv_gpio_inout(&btv->c, ir->mask_keycode | ir->mask_keydown, 0); - } - - /* init input device */ - ir->dev = rc; - - snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", - btv->c.type); - snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", - pci_name(btv->c.pci)); - - rc->input_name = ir->name; - rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_PCI; - rc->input_id.version = 1; - if (btv->c.pci->subsystem_vendor) { - rc->input_id.vendor = btv->c.pci->subsystem_vendor; - rc->input_id.product = btv->c.pci->subsystem_device; - } else { - rc->input_id.vendor = btv->c.pci->vendor; - rc->input_id.product = btv->c.pci->device; - } - rc->dev.parent = &btv->c.pci->dev; - rc->map_name = ir_codes; - rc->driver_name = MODULE_NAME; - - btv->remote = ir; - bttv_ir_start(btv, ir); - - /* all done */ - err = rc_register_device(rc); - if (err) - goto err_out_stop; - - return 0; - - err_out_stop: - bttv_ir_stop(btv); - btv->remote = NULL; - err_out_free: - rc_free_device(rc); - kfree(ir); - return err; -} - -void bttv_input_fini(struct bttv *btv) -{ - if (btv->remote == NULL) - return; - - bttv_ir_stop(btv); - rc_unregister_device(btv->remote->dev); - kfree(btv->remote); - btv->remote = NULL; -} diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c deleted file mode 100644 index 82cc47d2e3fa..000000000000 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - - bttv-risc.c -- interfaces to other kernel modules - - bttv risc code handling - - memory management - - generation - - (c) 2000-2003 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bttvp.h" - -#define VCR_HACK_LINES 4 - -/* ---------------------------------------------------------- */ -/* risc code generators */ - -int -bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int offset, unsigned int bpl, - unsigned int padding, unsigned int skip_lines, - unsigned int store_lines) -{ - u32 instructions,line,todo; - struct scatterlist *sg; - __le32 *rp; - int rc; - - /* estimate risc mem: worst case is one write per page border + - one write per scan line + sync + jump (all 2 dwords). padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - instructions = skip_lines * 4; - instructions += (1 + ((bpl + padding) * store_lines) - / PAGE_SIZE + store_lines) * 8; - instructions += 2 * 8; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0) - return rc; - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(rp++) = cpu_to_le32(0); - - while (skip_lines-- > 0) { - *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL | - BT848_RISC_EOL | bpl); - } - - /* scan lines */ - sg = sglist; - for (line = 0; line < store_lines; line++) { - if ((btv->opt_vcr_hack) && - (line >= (store_lines - VCR_HACK_LINES))) - continue; - while (offset && offset >= sg_dma_len(sg)) { - offset -= sg_dma_len(sg); - sg++; - } - if (bpl <= sg_dma_len(sg)-offset) { - /* fits into current chunk */ - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - offset+=bpl; - } else { - /* scanline needs to be splitted */ - todo = bpl; - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - (sg_dma_len(sg)-offset)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - todo -= (sg_dma_len(sg)-offset); - offset = 0; - sg++; - while (todo > sg_dma_len(sg)) { - *(rp++)=cpu_to_le32(BT848_RISC_WRITE| - sg_dma_len(sg)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - todo -= sg_dma_len(sg); - sg++; - } - *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL| - todo); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); - offset += todo; - } - offset += padding; - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -static int -bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - 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) -{ - unsigned int instructions,line,todo,ylen,chroma; - __le32 *rp; - u32 ri; - struct scatterlist *ysg; - struct scatterlist *usg; - struct scatterlist *vsg; - int topfield = (0 == yoffset); - 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 = ((3 + (ybpl + ypadding) * ylines * 2) - / PAGE_SIZE) + ylines; - instructions += 2; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0) - return rc; - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); - *(rp++) = cpu_to_le32(0); - - /* scan lines */ - ysg = sglist; - usg = sglist; - vsg = sglist; - for (line = 0; line < ylines; line++) { - if ((btv->opt_vcr_hack) && - (line >= (ylines - VCR_HACK_LINES))) - continue; - switch (vshift) { - case 0: - chroma = 1; - break; - case 1: - if (topfield) - chroma = ((line & 1) == 0); - else - chroma = ((line & 1) == 1); - break; - case 2: - if (topfield) - chroma = ((line & 3) == 0); - else - chroma = ((line & 3) == 2); - break; - default: - chroma = 0; - break; - } - - for (todo = ybpl; todo > 0; todo -= ylen) { - /* go to next sg entry if needed */ - while (yoffset && yoffset >= sg_dma_len(ysg)) { - yoffset -= sg_dma_len(ysg); - ysg++; - } - while (uoffset && uoffset >= sg_dma_len(usg)) { - uoffset -= sg_dma_len(usg); - usg++; - } - while (voffset && voffset >= sg_dma_len(vsg)) { - voffset -= sg_dma_len(vsg); - vsg++; - } - - /* calculate max number of bytes we can write */ - ylen = todo; - if (yoffset + ylen > sg_dma_len(ysg)) - ylen = sg_dma_len(ysg) - yoffset; - if (chroma) { - if (uoffset + (ylen>>hshift) > sg_dma_len(usg)) - ylen = (sg_dma_len(usg) - uoffset) << hshift; - if (voffset + (ylen>>hshift) > sg_dma_len(vsg)) - ylen = (sg_dma_len(vsg) - voffset) << hshift; - ri = BT848_RISC_WRITE123; - } else { - ri = BT848_RISC_WRITE1S23; - } - if (ybpl == todo) - ri |= BT848_RISC_SOL; - if (ylen == todo) - ri |= BT848_RISC_EOL; - - /* write risc instruction */ - *(rp++)=cpu_to_le32(ri | ylen); - *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) | - (ylen >> hshift)); - *(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset); - yoffset += ylen; - if (chroma) { - *(rp++)=cpu_to_le32(sg_dma_address(usg)+uoffset); - uoffset += ylen >> hshift; - *(rp++)=cpu_to_le32(sg_dma_address(vsg)+voffset); - voffset += ylen >> hshift; - } - } - yoffset += ypadding; - if (chroma) { - uoffset += cpadding; - voffset += cpadding; - } - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - return 0; -} - -static int -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 dwords, rc, line, maxy, start, end; - unsigned skip, nskips; - struct btcx_skiplist *skips; - __le32 *rp; - u32 ri,ra; - u32 addr; - - /* skip list for window clipping */ - if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) - return -ENOMEM; - - /* estimate risc mem: worst case is (1.5*clip+1) * lines instructions - + sync + jump (all 2 dwords) */ - dwords = (3 * ov->nclips + 2) * - ((skip_even || skip_odd) ? (ov->w.height+1)>>1 : ov->w.height); - dwords += 4; - if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,dwords*4)) < 0) { - kfree(skips); - return rc; - } - - /* sync instruction */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); - *(rp++) = cpu_to_le32(0); - - addr = (unsigned long)btv->fbuf.base; - addr += btv->fbuf.fmt.bytesperline * ov->w.top; - addr += (fmt->depth >> 3) * ov->w.left; - - /* scan lines */ - for (maxy = -1, line = 0; line < ov->w.height; - line++, addr += btv->fbuf.fmt.bytesperline) { - if ((btv->opt_vcr_hack) && - (line >= (ov->w.height - VCR_HACK_LINES))) - continue; - if ((line%2) == 0 && skip_even) - continue; - if ((line%2) == 1 && skip_odd) - continue; - - /* calculate clipping */ - if (line > maxy) - 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) { - if (skip >= nskips) { - ri = BT848_RISC_WRITE; - end = ov->w.width; - } else if (start < skips[skip].start) { - ri = BT848_RISC_WRITE; - end = skips[skip].start; - } else { - ri = BT848_RISC_SKIP; - end = skips[skip].end; - skip++; - } - if (BT848_RISC_WRITE == ri) - ra = addr + (fmt->depth>>3)*start; - else - ra = 0; - - if (0 == start) - ri |= BT848_RISC_SOL; - if (ov->w.width == end) - ri |= BT848_RISC_EOL; - ri |= (fmt->depth>>3) * (end-start); - - *(rp++)=cpu_to_le32(ri); - if (0 != ra) - *(rp++)=cpu_to_le32(ra); - } - } - - /* save pointer to jmp instruction address */ - risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); - kfree(skips); - return 0; -} - -/* ---------------------------------------------------------- */ - -static void -bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo, - int width, int height, int interleaved, - const struct bttv_tvnorm *tvnorm) -{ - u32 xsf, sr; - int vdelay; - - int swidth = tvnorm->swidth; - int totalwidth = tvnorm->totalwidth; - int scaledtwidth = tvnorm->scaledtwidth; - - if (btv->input == btv->dig) { - swidth = 720; - totalwidth = 858; - scaledtwidth = 858; - } - - vdelay = tvnorm->vdelay; - - xsf = (width*scaledtwidth)/swidth; - geo->hscale = ((totalwidth*4096UL)/xsf-4096); - geo->hdelay = tvnorm->hdelayx1; - geo->hdelay = (geo->hdelay*width)/swidth; - geo->hdelay &= 0x3fe; - sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; - geo->vscale = (0x10000UL-sr) & 0x1fff; - geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) | - ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0); - geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0; - 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); - geo->comb = (width < 769) ? 1 : 0; - } else { - geo->vtc = 0; - geo->comb = 0; - } -} - -static void -bttv_calc_geo (struct bttv * btv, - struct bttv_geometry * geo, - unsigned int width, - unsigned int height, - int both_fields, - const struct bttv_tvnorm * tvnorm, - const struct v4l2_rect * crop) -{ - unsigned int c_width; - unsigned int c_height; - u32 sr; - - if ((crop->left == tvnorm->cropcap.defrect.left - && crop->top == tvnorm->cropcap.defrect.top - && crop->width == tvnorm->cropcap.defrect.width - && crop->height == tvnorm->cropcap.defrect.height - && width <= tvnorm->swidth /* see PAL-Nc et al */) - || btv->input == btv->dig) { - bttv_calc_geo_old(btv, geo, width, height, - both_fields, tvnorm); - return; - } - - /* For bug compatibility the image size checks permit scale - factors > 16. See bttv_crop_calc_limits(). */ - c_width = min((unsigned int) crop->width, width * 16); - c_height = min((unsigned int) crop->height, height * 16); - - geo->width = width; - geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096; - /* Even to store Cb first, odd for Cr. */ - geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1; - - geo->sheight = c_height; - geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY; - sr = c_height >> !both_fields; - sr = (sr * 512U + (height >> 1)) / height - 512; - geo->vscale = (0x10000UL - sr) & 0x1fff; - geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0; - geo->vtotal = tvnorm->vtotal; - - geo->crop = (((geo->width >> 8) & 0x03) | - ((geo->hdelay >> 6) & 0x0c) | - ((geo->sheight >> 4) & 0x30) | - ((geo->vdelay >> 2) & 0xc0)); - - if (btv->opt_combfilter) { - geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0); - geo->comb = (width < 769) ? 1 : 0; - } else { - geo->vtc = 0; - geo->comb = 0; - } -} - -static void -bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd) -{ - int off = odd ? 0x80 : 0x00; - - if (geo->comb) - btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - else - btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off); - - btwrite(geo->vtc, BT848_E_VTC+off); - btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off); - btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off); - btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off); - btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off); - btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off); - btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off); - 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); -} - -/* ---------------------------------------------------------- */ -/* risc group / risc main loop / dma management */ - -void -bttv_set_dma(struct bttv *btv, int override) -{ - unsigned long cmd; - int capctl; - - btv->cap_ctl = 0; - if (NULL != btv->curr.top) btv->cap_ctl |= 0x02; - if (NULL != btv->curr.bottom) btv->cap_ctl |= 0x01; - if (NULL != btv->cvbi) btv->cap_ctl |= 0x0c; - - capctl = 0; - capctl |= (btv->cap_ctl & 0x03) ? 0x03 : 0x00; /* capture */ - capctl |= (btv->cap_ctl & 0x0c) ? 0x0c : 0x00; /* vbi data */ - capctl |= override; - - d2printk("%d: capctl=%x lirq=%d top=%08llx/%08llx even=%08llx/%08llx\n", - btv->c.nr,capctl,btv->loop_irq, - btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0, - btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0, - btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0, - btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0); - - cmd = BT848_RISC_JUMP; - if (btv->loop_irq) { - cmd |= BT848_RISC_IRQ; - cmd |= (btv->loop_irq & 0x0f) << 16; - cmd |= (~btv->loop_irq & 0x0f) << 20; - } - if (btv->curr.frame_irq || btv->loop_irq || btv->cvbi) { - mod_timer(&btv->timeout, jiffies+BTTV_TIMEOUT); - } else { - del_timer(&btv->timeout); - } - btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd); - - btaor(capctl, ~0x0f, BT848_CAP_CTL); - if (capctl) { - if (btv->dma_on) - return; - btwrite(btv->main.dma, BT848_RISC_STRT_ADD); - btor(3, BT848_GPIO_DMA_CTL); - btv->dma_on = 1; - } else { - if (!btv->dma_on) - return; - btand(~3, BT848_GPIO_DMA_CTL); - btv->dma_on = 0; - } - return; -} - -int -bttv_risc_init_main(struct bttv *btv) -{ - int rc; - - if ((rc = btcx_riscmem_alloc(btv->c.pci,&btv->main,PAGE_SIZE)) < 0) - return rc; - dprintk("%d: risc main @ %08llx\n", - btv->c.nr, (unsigned long long)btv->main.dma); - - btv->main.cpu[0] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | - BT848_FIFO_STATUS_VRE); - btv->main.cpu[1] = cpu_to_le32(0); - btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); - - /* top field */ - btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); - btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2)); - - btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC | - BT848_FIFO_STATUS_VRO); - btv->main.cpu[9] = cpu_to_le32(0); - - /* bottom field */ - btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); - btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); - - /* jump back to top field */ - btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); - btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); - - return 0; -} - -int -bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, - int irqflags) -{ - unsigned long cmd; - unsigned long next = btv->main.dma + ((slot+2) << 2); - - if (NULL == risc) { - d2printk("%d: risc=%p slot[%d]=NULL\n", btv->c.nr, risc, slot); - btv->main.cpu[slot+1] = cpu_to_le32(next); - } else { - d2printk("%d: risc=%p slot[%d]=%08llx irq=%d\n", - btv->c.nr, risc, slot, - (unsigned long long)risc->dma, irqflags); - cmd = BT848_RISC_JUMP; - 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); - } - return 0; -} - -void -bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf) -{ - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(btv->c.pci,&buf->bottom); - btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -int -bttv_buffer_activate_vbi(struct bttv *btv, - struct bttv_buffer *vbi) -{ - struct btcx_riscmem *top; - struct btcx_riscmem *bottom; - int top_irq_flags; - int bottom_irq_flags; - - top = NULL; - bottom = NULL; - top_irq_flags = 0; - bottom_irq_flags = 0; - - if (vbi) { - unsigned int crop, vdelay; - - vbi->vb.state = VIDEOBUF_ACTIVE; - list_del(&vbi->vb.queue); - - /* VDELAY is start of video, end of VBI capturing. */ - crop = btread(BT848_E_CROP); - vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2); - - if (vbi->geo.vdelay > vdelay) { - vdelay = vbi->geo.vdelay & 0xfe; - crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0); - - btwrite(vdelay, BT848_E_VDELAY_LO); - btwrite(crop, BT848_E_CROP); - btwrite(vdelay, BT848_O_VDELAY_LO); - btwrite(crop, BT848_O_CROP); - } - - if (vbi->vbi_count[0] > 0) { - top = &vbi->top; - top_irq_flags = 4; - } - - if (vbi->vbi_count[1] > 0) { - top_irq_flags = 0; - bottom = &vbi->bottom; - bottom_irq_flags = 4; - } - } - - bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags); - - return 0; -} - -int -bttv_buffer_activate_video(struct bttv *btv, - struct bttv_buffer_set *set) -{ - /* video capture */ - if (NULL != set->top && NULL != set->bottom) { - if (set->top == set->bottom) { - set->top->vb.state = VIDEOBUF_ACTIVE; - if (set->top->vb.queue.next) - list_del(&set->top->vb.queue); - } else { - set->top->vb.state = VIDEOBUF_ACTIVE; - set->bottom->vb.state = VIDEOBUF_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->top_irq); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &set->bottom->bottom, - set->frame_irq); - btaor((set->top->btformat & 0xf0) | (set->bottom->btformat & 0x0f), - ~0xff, BT848_COLOR_FMT); - btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), - ~0x0f, BT848_COLOR_CTL); - } else if (NULL != set->top) { - set->top->vb.state = VIDEOBUF_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, - set->frame_irq); - 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 = VIDEOBUF_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, - set->frame_irq); - 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); - } - return 0; -} - -/* ---------------------------------------------------------- */ - -/* calculate geometry, build risc code */ -int -bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) -{ - const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - dprintk("%d: buffer field: %s format: %s size: %dx%d\n", - btv->c.nr, v4l2_field_names[buf->vb.field], - buf->fmt->name, buf->vb.width, buf->vb.height); - - /* packed pixel modes */ - if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { - int bpl = (buf->fmt->depth >> 3) * buf->vb.width; - int bpf = bpl * (buf->vb.height >> 1); - - bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, - V4L2_FIELD_HAS_BOTH(buf->vb.field), - tvnorm,&buf->crop); - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - bttv_risc_packed(btv,&buf->top,dma->sglist, - /* offset */ 0,bpl, - /* padding */ 0,/* skip_lines */ 0, - buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - 0,bpl,0,0,buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - bttv_risc_packed(btv,&buf->top,dma->sglist, - 0,bpl,bpl,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - bpl,bpl,bpl,0,buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - bttv_risc_packed(btv,&buf->top,dma->sglist, - 0,bpl,0,0,buf->vb.height >> 1); - bttv_risc_packed(btv,&buf->bottom,dma->sglist, - bpf,bpl,0,0,buf->vb.height >> 1); - break; - default: - BUG(); - } - } - - /* planar modes */ - if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { - int uoffset, voffset; - int ypadding, cpadding, lines; - - /* calculate chroma offsets */ - uoffset = buf->vb.width * buf->vb.height; - voffset = buf->vb.width * buf->vb.height; - if (buf->fmt->flags & FORMAT_FLAGS_CrCb) { - /* Y-Cr-Cb plane order */ - uoffset >>= buf->fmt->hshift; - uoffset >>= buf->fmt->vshift; - uoffset += voffset; - } else { - /* Y-Cb-Cr plane order */ - voffset >>= buf->fmt->hshift; - voffset >>= buf->fmt->vshift; - voffset += uoffset; - } - - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,/* both_fields */ 0, - tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->top, dma->sglist, - 0,buf->vb.width,0,buf->vb.height, - uoffset,voffset,buf->fmt->hshift, - buf->fmt->vshift,0); - break; - case V4L2_FIELD_BOTTOM: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,0, - tvnorm,&buf->crop); - bttv_risc_planar(btv, &buf->bottom, dma->sglist, - 0,buf->vb.width,0,buf->vb.height, - uoffset,voffset,buf->fmt->hshift, - buf->fmt->vshift,0); - break; - case V4L2_FIELD_INTERLACED: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,1, - tvnorm,&buf->crop); - lines = buf->vb.height >> 1; - ypadding = buf->vb.width; - cpadding = buf->vb.width >> buf->fmt->hshift; - bttv_risc_planar(btv,&buf->top, - dma->sglist, - 0,buf->vb.width,ypadding,lines, - uoffset,voffset, - buf->fmt->hshift, - buf->fmt->vshift, - cpadding); - bttv_risc_planar(btv,&buf->bottom, - dma->sglist, - ypadding,buf->vb.width,ypadding,lines, - uoffset+cpadding, - voffset+cpadding, - buf->fmt->hshift, - buf->fmt->vshift, - cpadding); - break; - case V4L2_FIELD_SEQ_TB: - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,1, - tvnorm,&buf->crop); - lines = buf->vb.height >> 1; - ypadding = buf->vb.width; - cpadding = buf->vb.width >> buf->fmt->hshift; - bttv_risc_planar(btv,&buf->top, - 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, - 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(); - } - } - - /* raw data */ - if (buf->fmt->flags & FORMAT_FLAGS_RAW) { - /* build risc code */ - buf->vb.field = V4L2_FIELD_SEQ_TB; - bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, - 1,tvnorm,&buf->crop); - bttv_risc_packed(btv, &buf->top, dma->sglist, - /* offset */ 0, RAW_BPL, /* padding */ 0, - /* skip_lines */ 0, RAW_LINES); - bttv_risc_packed(btv, &buf->bottom, dma->sglist, - buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES); - } - - /* copy format info */ - buf->btformat = buf->fmt->btformat; - buf->btswap = buf->fmt->btswap; - return 0; -} - -/* ---------------------------------------------------------- */ - -/* calculate geometry, build risc code */ -int -bttv_overlay_risc(struct bttv *btv, - struct bttv_overlay *ov, - const struct bttv_format *fmt, - struct bttv_buffer *buf) -{ - /* check interleave, bottom+top fields */ - dprintk("%d: overlay fields: %s format: %s size: %dx%d\n", - btv->c.nr, v4l2_field_names[buf->vb.field], - fmt->name, ov->w.width, ov->w.height); - - /* calculate geometry */ - bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, - V4L2_FIELD_HAS_BOTH(ov->field), - &bttv_tvnorms[ov->tvnorm],&buf->crop); - - /* build risc code */ - switch (ov->field) { - case V4L2_FIELD_TOP: - bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); - break; - case V4L2_FIELD_BOTTOM: - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); - break; - case V4L2_FIELD_INTERLACED: - bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); - bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); - break; - default: - BUG(); - } - - /* copy format info */ - buf->btformat = fmt->btformat; - buf->btswap = fmt->btswap; - buf->vb.field = ov->field; - return 0; -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c deleted file mode 100644 index b433267d9aa9..000000000000 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - vbi interface - - (c) 2002 Gerd Knorr - - Copyright (C) 2005, 2006 Michael H. Schimek - Sponsored by OPQ Systems AB - - 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include "bttvp.h" - -/* Offset from line sync pulse leading edge (0H) to start of VBI capture, - in fCLKx2 pixels. According to the datasheet, VBI capture starts - VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET - is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be - (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is - Just Plain Wrong. The real value appears to be different for - different revisions of the bt8x8 chips, and to be affected by the - horizontal scaling factor. Experimentally, the value is measured - to be about 244. */ -#define VBI_OFFSET 244 - -/* 2048 for compatibility with earlier driver versions. The driver - really stores 1024 + tvnorm->vbipack * 4 samples per line in the - buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI - is 0x1FF DWORDs) and VBI read()s store a frame counter in the last - four bytes of the VBI image. */ -#define VBI_BPL 2048 - -/* Compatibility. */ -#define VBI_DEFLINES 16 - -static unsigned int vbibufs = 4; -static unsigned int vbi_debug; - -module_param(vbibufs, int, 0444); -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32, default 4"); -MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)"); - -#ifdef dprintk -# undef dprintk -#endif -#define dprintk(fmt, ...) \ -do { \ - if (vbi_debug) \ - pr_debug("%d: " fmt, btv->c.nr, ##__VA_ARGS__); \ -} while (0) - -#define IMAGE_SIZE(fmt) \ - (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line) - -/* ----------------------------------------------------------------------- */ -/* vbi risc code + mm */ - -static int vbi_buffer_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - - if (0 == *count) - *count = vbibufs; - - *size = IMAGE_SIZE(&fh->vbi_fmt.fmt); - - dprintk("setup: samples=%u start=%d,%d count=%u,%u\n", - fh->vbi_fmt.fmt.samples_per_line, - fh->vbi_fmt.fmt.start[0], - fh->vbi_fmt.fmt.start[1], - fh->vbi_fmt.fmt.count[0], - fh->vbi_fmt.fmt.count[1]); - - return 0; -} - -static int vbi_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - const struct bttv_tvnorm *tvnorm; - unsigned int skip_lines0, skip_lines1, min_vdelay; - int redo_dma_risc; - int rc; - - buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt); - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - tvnorm = fh->vbi_fmt.tvnorm; - - /* There's no VBI_VDELAY register, RISC must skip the lines - we don't want. With default parameters we skip zero lines - as earlier driver versions did. The driver permits video - standard changes while capturing, so we use vbi_fmt.tvnorm - instead of btv->tvnorm to skip zero lines after video - standard changes as well. */ - - skip_lines0 = 0; - skip_lines1 = 0; - - if (fh->vbi_fmt.fmt.count[0] > 0) - skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0] - - tvnorm->vbistart[0])); - if (fh->vbi_fmt.fmt.count[1] > 0) - skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1] - - tvnorm->vbistart[1])); - - redo_dma_risc = 0; - - if (buf->vbi_skip[0] != skip_lines0 || - buf->vbi_skip[1] != skip_lines1 || - buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] || - buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) { - buf->vbi_skip[0] = skip_lines0; - buf->vbi_skip[1] = skip_lines1; - buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0]; - buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1]; - redo_dma_risc = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - redo_dma_risc = 1; - if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) - goto fail; - } - - if (redo_dma_risc) { - unsigned int bpl, padding, offset; - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - - bpl = 2044; /* max. vbipack */ - padding = VBI_BPL - bpl; - - if (fh->vbi_fmt.fmt.count[0] > 0) { - rc = bttv_risc_packed(btv, &buf->top, - dma->sglist, - /* offset */ 0, bpl, - padding, skip_lines0, - fh->vbi_fmt.fmt.count[0]); - if (0 != rc) - goto fail; - } - - if (fh->vbi_fmt.fmt.count[1] > 0) { - offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL; - - rc = bttv_risc_packed(btv, &buf->bottom, - dma->sglist, - offset, bpl, - padding, skip_lines1, - fh->vbi_fmt.fmt.count[1]); - if (0 != rc) - goto fail; - } - } - - /* VBI capturing ends at VDELAY, start of video capturing, - no matter where the RISC program ends. VDELAY minimum is 2, - bounds.top is the corresponding first field line number - times two. VDELAY counts half field lines. */ - min_vdelay = MIN_VDELAY; - if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top) - min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top; - - /* For bttv_buffer_activate_vbi(). */ - buf->geo.vdelay = min_vdelay; - - buf->vb.state = VIDEOBUF_PREPARED; - buf->vb.field = field; - dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", - vb, &buf->top, &buf->bottom, - v4l2_field_names[buf->vb.field]); - return 0; - - fail: - bttv_dma_free(q,btv,buf); - return rc; -} - -static void -vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - - dprintk("queue %p\n",vb); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue,&btv->vcapture); - if (NULL == btv->cvbi) { - fh->btv->loop_irq |= 4; - bttv_set_dma(btv,0x0c); - } -} - -static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct bttv_fh *fh = q->priv_data; - struct bttv *btv = fh->btv; - struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); - - dprintk("free %p\n",vb); - bttv_dma_free(q,fh->btv,buf); -} - -struct videobuf_queue_ops bttv_vbi_qops = { - .buf_setup = vbi_buffer_setup, - .buf_prepare = vbi_buffer_prepare, - .buf_queue = vbi_buffer_queue, - .buf_release = vbi_buffer_release, -}; - -/* ----------------------------------------------------------------------- */ - -static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, - __s32 crop_start) -{ - __s32 min_start, max_start, max_end, f2_offset; - unsigned int i; - - /* For compatibility with earlier driver versions we must pretend - the VBI and video capture window may overlap. In reality RISC - magic aborts VBI capturing at the first line of video capturing, - leaving the rest of the buffer unchanged, usually all zero. - VBI capturing must always start before video capturing. >> 1 - because cropping counts field lines times two. */ - min_start = tvnorm->vbistart[0]; - max_start = (crop_start >> 1) - 1; - max_end = (tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height) >> 1; - - if (min_start > max_start) - return -EBUSY; - - BUG_ON(max_start >= max_end); - - f->sampling_rate = tvnorm->Fsc; - f->samples_per_line = VBI_BPL; - f->sample_format = V4L2_PIX_FMT_GREY; - f->offset = VBI_OFFSET; - - f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0]; - - for (i = 0; i < 2; ++i) { - if (0 == f->count[i]) { - /* No data from this field. We leave f->start[i] - alone because VIDIOCSVBIFMT is w/o and EINVALs - when a driver does not support exactly the - requested parameters. */ - } else { - s64 start, count; - - start = clamp(f->start[i], min_start, max_start); - /* s64 to prevent overflow. */ - count = (s64) f->start[i] + f->count[i] - start; - f->start[i] = start; - f->count[i] = clamp(count, (s64) 1, - max_end - start); - } - - min_start += f2_offset; - max_start += f2_offset; - max_end += f2_offset; - } - - if (0 == (f->count[0] | f->count[1])) { - /* As in earlier driver versions. */ - f->start[0] = tvnorm->vbistart[0]; - f->start[1] = tvnorm->vbistart[1]; - f->count[0] = 1; - f->count[1] = 1; - } - - f->flags = 0; - - f->reserved[0] = 0; - f->reserved[1] = 0; - - return 0; -} - -int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_tvnorm *tvnorm; - __s32 crop_start; - - mutex_lock(&btv->lock); - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - crop_start = btv->crop_start; - - mutex_unlock(&btv->lock); - - return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); -} - - -int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_tvnorm *tvnorm; - __s32 start1, end; - int rc; - - mutex_lock(&btv->lock); - - rc = -EBUSY; - if (fh->resources & RESOURCE_VBI) - goto fail; - - tvnorm = &bttv_tvnorms[btv->tvnorm]; - - rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); - if (0 != rc) - goto fail; - - start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + - tvnorm->vbistart[0]; - - /* First possible line of video capturing. Should be - max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 - when capturing both fields. But for compatibility we must - pretend the VBI and video capture window may overlap, - so end = start + 1, the lowest possible value, times two - because vbi_fmt.end counts field lines times two. */ - end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; - - mutex_lock(&fh->vbi.vb_lock); - - fh->vbi_fmt.fmt = frt->fmt.vbi; - fh->vbi_fmt.tvnorm = tvnorm; - fh->vbi_fmt.end = end; - - mutex_unlock(&fh->vbi.vb_lock); - - rc = 0; - - fail: - mutex_unlock(&btv->lock); - - return rc; -} - - -int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) -{ - struct bttv_fh *fh = f; - const struct bttv_tvnorm *tvnorm; - - frt->fmt.vbi = fh->vbi_fmt.fmt; - - tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; - - if (tvnorm != fh->vbi_fmt.tvnorm) { - __s32 max_end; - unsigned int i; - - /* As in vbi_buffer_prepare() this imitates the - behaviour of earlier driver versions after video - standard changes, with default parameters anyway. */ - - max_end = (tvnorm->cropcap.bounds.top - + tvnorm->cropcap.bounds.height) >> 1; - - frt->fmt.vbi.sampling_rate = tvnorm->Fsc; - - for (i = 0; i < 2; ++i) { - __s32 new_start; - - new_start = frt->fmt.vbi.start[i] - + tvnorm->vbistart[i] - - fh->vbi_fmt.tvnorm->vbistart[i]; - - frt->fmt.vbi.start[i] = min(new_start, max_end - 1); - frt->fmt.vbi.count[i] = - min((__s32) frt->fmt.vbi.count[i], - max_end - frt->fmt.vbi.start[i]); - - max_end += tvnorm->vbistart[1] - - tvnorm->vbistart[0]; - } - } - return 0; -} - -void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm) -{ - const struct bttv_tvnorm *tvnorm; - unsigned int real_samples_per_line; - unsigned int real_count; - - tvnorm = &bttv_tvnorms[norm]; - - f->fmt.sampling_rate = tvnorm->Fsc; - f->fmt.samples_per_line = VBI_BPL; - f->fmt.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.offset = VBI_OFFSET; - f->fmt.start[0] = tvnorm->vbistart[0]; - f->fmt.start[1] = tvnorm->vbistart[1]; - f->fmt.count[0] = VBI_DEFLINES; - f->fmt.count[1] = VBI_DEFLINES; - f->fmt.flags = 0; - f->fmt.reserved[0] = 0; - f->fmt.reserved[1] = 0; - - /* For compatibility the buffer size must be 2 * VBI_DEFLINES * - VBI_BPL regardless of the current video standard. */ - real_samples_per_line = 1024 + tvnorm->vbipack * 4; - real_count = ((tvnorm->cropcap.defrect.top >> 1) - - tvnorm->vbistart[0]); - - BUG_ON(real_samples_per_line > VBI_BPL); - BUG_ON(real_count > VBI_DEFLINES); - - f->tvnorm = tvnorm; - - /* See bttv_vbi_fmt_set(). */ - f->end = tvnorm->vbistart[0] * 2 + 2; -} - -/* ----------------------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h deleted file mode 100644 index 79a11240a590..000000000000 --- a/drivers/media/video/bt8xx/bttv.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * - * bttv - Bt848 frame grabber driver - * - * card ID's and external interfaces of the bttv driver - * basically stuff needed by other drivers (i2c, lirc, ...) - * and is supported not to change much over time. - * - * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de) - * (c) 1999,2000 Gerd Knorr - * - */ - -#ifndef _BTTV_H_ -#define _BTTV_H_ - -#include -#include -#include -#include -#include - -/* ---------------------------------------------------------- */ -/* exported by bttv-cards.c */ - -#define BTTV_BOARD_UNKNOWN 0x00 -#define BTTV_BOARD_MIRO 0x01 -#define BTTV_BOARD_HAUPPAUGE 0x02 -#define BTTV_BOARD_STB 0x03 -#define BTTV_BOARD_INTEL 0x04 -#define BTTV_BOARD_DIAMOND 0x05 -#define BTTV_BOARD_AVERMEDIA 0x06 -#define BTTV_BOARD_MATRIX_VISION 0x07 -#define BTTV_BOARD_FLYVIDEO 0x08 -#define BTTV_BOARD_TURBOTV 0x09 -#define BTTV_BOARD_HAUPPAUGE878 0x0a -#define BTTV_BOARD_MIROPRO 0x0b -#define BTTV_BOARD_ADSTECH_TV 0x0c -#define BTTV_BOARD_AVERMEDIA98 0x0d -#define BTTV_BOARD_VHX 0x0e -#define BTTV_BOARD_ZOLTRIX 0x0f -#define BTTV_BOARD_PIXVIEWPLAYTV 0x10 -#define BTTV_BOARD_WINVIEW_601 0x11 -#define BTTV_BOARD_AVEC_INTERCAP 0x12 -#define BTTV_BOARD_LIFE_FLYKIT 0x13 -#define BTTV_BOARD_CEI_RAFFLES 0x14 -#define BTTV_BOARD_CONFERENCETV 0x15 -#define BTTV_BOARD_PHOEBE_TVMAS 0x16 -#define BTTV_BOARD_MODTEC_205 0x17 -#define BTTV_BOARD_MAGICTVIEW061 0x18 -#define BTTV_BOARD_VOBIS_BOOSTAR 0x19 -#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a -#define BTTV_BOARD_MAXI 0x1b -#define BTTV_BOARD_TERRATV 0x1c -#define BTTV_BOARD_PXC200 0x1d -#define BTTV_BOARD_FLYVIDEO_98 0x1e -#define BTTV_BOARD_IPROTV 0x1f -#define BTTV_BOARD_INTEL_C_S_PCI 0x20 -#define BTTV_BOARD_TERRATVALUE 0x21 -#define BTTV_BOARD_WINFAST2000 0x22 -#define BTTV_BOARD_CHRONOS_VS2 0x23 -#define BTTV_BOARD_TYPHOON_TVIEW 0x24 -#define BTTV_BOARD_PXELVWPLTVPRO 0x25 -#define BTTV_BOARD_MAGICTVIEW063 0x26 -#define BTTV_BOARD_PINNACLE 0x27 -#define BTTV_BOARD_STB2 0x28 -#define BTTV_BOARD_AVPHONE98 0x29 -#define BTTV_BOARD_PV951 0x2a -#define BTTV_BOARD_ONAIR_TV 0x2b -#define BTTV_BOARD_SIGMA_TVII_FM 0x2c -#define BTTV_BOARD_MATRIX_VISION2 0x2d -#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e -#define BTTV_BOARD_TERRATVRADIO 0x2f -#define BTTV_BOARD_DYNALINK 0x30 -#define BTTV_BOARD_GVBCTV3PCI 0x31 -#define BTTV_BOARD_PXELVWPLTVPAK 0x32 -#define BTTV_BOARD_EAGLE 0x33 -#define BTTV_BOARD_PINNACLEPRO 0x34 -#define BTTV_BOARD_TVIEW_RDS_FM 0x35 -#define BTTV_BOARD_LIFETEC_9415 0x36 -#define BTTV_BOARD_BESTBUY_EASYTV 0x37 -#define BTTV_BOARD_FLYVIDEO_98FM 0x38 -#define BTTV_BOARD_GRANDTEC 0x39 -#define BTTV_BOARD_ASKEY_CPH060 0x3a -#define BTTV_BOARD_ASKEY_CPH03X 0x3b -#define BTTV_BOARD_MM100PCTV 0x3c -#define BTTV_BOARD_GMV1 0x3d -#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e -#define BTTV_BOARD_ATI_TVWONDER 0x3f -#define BTTV_BOARD_ATI_TVWONDERVE 0x40 -#define BTTV_BOARD_FLYVIDEO2000 0x41 -#define BTTV_BOARD_TERRATVALUER 0x42 -#define BTTV_BOARD_GVBCTV4PCI 0x43 -#define BTTV_BOARD_VOODOOTV_FM 0x44 -#define BTTV_BOARD_AIMMS 0x45 -#define BTTV_BOARD_PV_BT878P_PLUS 0x46 -#define BTTV_BOARD_FLYVIDEO98EZ 0x47 -#define BTTV_BOARD_PV_BT878P_9B 0x48 -#define BTTV_BOARD_SENSORAY311_611 0x49 -#define BTTV_BOARD_RV605 0x4a -#define BTTV_BOARD_POWERCLR_MTV878 0x4b -#define BTTV_BOARD_WINDVR 0x4c -#define BTTV_BOARD_GRANDTEC_MULTI 0x4d -#define BTTV_BOARD_KWORLD 0x4e -#define BTTV_BOARD_DSP_TCVIDEO 0x4f -#define BTTV_BOARD_HAUPPAUGEPVR 0x50 -#define BTTV_BOARD_GVBCTV5PCI 0x51 -#define BTTV_BOARD_OSPREY1x0 0x52 -#define BTTV_BOARD_OSPREY1x0_848 0x53 -#define BTTV_BOARD_OSPREY101_848 0x54 -#define BTTV_BOARD_OSPREY1x1 0x55 -#define BTTV_BOARD_OSPREY1x1_SVID 0x56 -#define BTTV_BOARD_OSPREY2xx 0x57 -#define BTTV_BOARD_OSPREY2x0_SVID 0x58 -#define BTTV_BOARD_OSPREY2x0 0x59 -#define BTTV_BOARD_OSPREY500 0x5a -#define BTTV_BOARD_OSPREY540 0x5b -#define BTTV_BOARD_OSPREY2000 0x5c -#define BTTV_BOARD_IDS_EAGLE 0x5d -#define BTTV_BOARD_PINNACLESAT 0x5e -#define BTTV_BOARD_FORMAC_PROTV 0x5f -#define BTTV_BOARD_MACHTV 0x60 -#define BTTV_BOARD_EURESYS_PICOLO 0x61 -#define BTTV_BOARD_PV150 0x62 -#define BTTV_BOARD_AD_TVK503 0x63 -#define BTTV_BOARD_HERCULES_SM_TV 0x64 -#define BTTV_BOARD_PACETV 0x65 -#define BTTV_BOARD_IVC200 0x66 -#define BTTV_BOARD_XGUARD 0x67 -#define BTTV_BOARD_NEBULA_DIGITV 0x68 -#define BTTV_BOARD_PV143 0x69 -#define BTTV_BOARD_VD009X1_VD011_MINIDIN 0x6a -#define BTTV_BOARD_VD009X1_VD011_COMBI 0x6b -#define BTTV_BOARD_VD009_MINIDIN 0x6c -#define BTTV_BOARD_VD009_COMBI 0x6d -#define BTTV_BOARD_IVC100 0x6e -#define BTTV_BOARD_IVC120 0x6f -#define BTTV_BOARD_PC_HDTV 0x70 -#define BTTV_BOARD_TWINHAN_DST 0x71 -#define BTTV_BOARD_WINFASTVC100 0x72 -#define BTTV_BOARD_TEV560 0x73 -#define BTTV_BOARD_SIMUS_GVC1100 0x74 -#define BTTV_BOARD_NGSTV_PLUS 0x75 -#define BTTV_BOARD_LMLBT4 0x76 -#define BTTV_BOARD_TEKRAM_M205 0x77 -#define BTTV_BOARD_CONTVFMI 0x78 -#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 -#define BTTV_BOARD_SPIRIT_TV 0x7a -#define BTTV_BOARD_AVDVBT_771 0x7b -#define BTTV_BOARD_AVDVBT_761 0x7c -#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d -#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e -#define BTTV_BOARD_APAC_VIEWCOMP 0x7f -#define BTTV_BOARD_DVICO_DVBT_LITE 0x80 -#define BTTV_BOARD_VGEAR_MYVCD 0x81 -#define BTTV_BOARD_SUPER_TV 0x82 -#define BTTV_BOARD_TIBET_CS16 0x83 -#define BTTV_BOARD_KODICOM_4400R 0x84 -#define BTTV_BOARD_KODICOM_4400R_SL 0x85 -#define BTTV_BOARD_ADLINK_RTV24 0x86 -#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 -#define BTTV_BOARD_ACORP_Y878F 0x88 -#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89 -#define BTTV_BOARD_PV_BT878P_2E 0x8a -#define BTTV_BOARD_PV_M4900 0x8b -#define BTTV_BOARD_OSPREY440 0x8c -#define BTTV_BOARD_ASOUND_SKYEYE 0x8d -#define BTTV_BOARD_SABRENT_TVFM 0x8e -#define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f -#define BTTV_BOARD_MACHTV_MAGICTV 0x90 -#define BTTV_BOARD_SSAI_SECURITY 0x91 -#define BTTV_BOARD_SSAI_ULTRASOUND 0x92 -#define BTTV_BOARD_VOODOOTV_200 0x93 -#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94 -#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 -#define BTTV_BOARD_GEOVISION_GV600 0x96 -#define BTTV_BOARD_KOZUMI_KTV_01C 0x97 -#define BTTV_BOARD_ENLTV_FM_2 0x98 -#define BTTV_BOARD_VD012 0x99 -#define BTTV_BOARD_VD012_X1 0x9a -#define BTTV_BOARD_VD012_X2 0x9b -#define BTTV_BOARD_IVCE8784 0x9c -#define BTTV_BOARD_GEOVISION_GV800S 0x9d -#define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e -#define BTTV_BOARD_PV183 0x9f -#define BTTV_BOARD_TVT_TD3116 0xa0 -#define BTTV_BOARD_APOSONIC_WDVR 0xa1 - -/* more card-specific defines */ -#define PT2254_L_CHANNEL 0x10 -#define PT2254_R_CHANNEL 0x08 -#define PT2254_DBS_IN_2 0x400 -#define PT2254_DBS_IN_10 0x20000 -#define WINVIEW_PT2254_CLK 0x40 -#define WINVIEW_PT2254_DATA 0x20 -#define WINVIEW_PT2254_STROBE 0x80 - -struct bttv_core { - /* device structs */ - struct v4l2_device v4l2_dev; - struct pci_dev *pci; - struct i2c_adapter i2c_adap; - struct list_head subs; /* struct bttv_sub_device */ - - /* device config */ - unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */ - unsigned int type; /* card type (pointer into tvcards[]) */ -}; - -struct bttv; - -struct tvcard { - char *name; - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); - void (*muxsel_hook)(struct bttv *btv, unsigned int input); - - /* MUX bits for each input, two bits per input starting with the LSB */ - u32 muxsel; /* Use MUXSEL() to set */ - - u32 gpiomask; - u32 gpiomux[4]; /* Tuner, Radio, external, internal */ - u32 gpiomute; /* GPIO mute setting */ - u32 gpiomask2; /* GPIO MUX mask */ - - unsigned int tuner_type; - u8 tuner_addr; - u8 video_inputs; /* Number of inputs */ - unsigned int svhs:4; /* Which input is s-video */ -#define NO_SVHS 15 - unsigned int pll:2; -#define PLL_NONE 0 -#define PLL_28 1 -#define PLL_35 2 - - /* i2c audio flags */ - unsigned int no_msp34xx:1; - unsigned int no_tda7432:1; - unsigned int msp34xx_alt:1; - /* Note: currently no card definition needs to mark the presence - of a RDS saa6588 chip. If this is ever needed, then add a new - 'has_saa6588' bit here. */ - - unsigned int no_video:1; /* video pci function is unused */ - unsigned int has_dvb:1; - unsigned int has_remote:1; - unsigned int has_radio:1; - unsigned int has_dig_in:1; /* Has digital input (always last input) */ - unsigned int no_gpioirq:1; -}; - -extern struct tvcard bttv_tvcards[]; - -/* - * This bit of cpp voodoo is used to create a macro with a variable number of - * arguments (1 to 16). It will pack each argument into a word two bits at a - * time. It can't be a function because it needs to be compile time constant to - * initialize structures. Since each argument must fit in two bits, it's ok - * that they are changed to octal. One should not use hex number, macros, or - * anything else with this macro. Just use plain integers from 0 to 3. - */ -#define _MUXSELf(a) 0##a << 30 -#define _MUXSELe(a, b...) 0##a << 28 | _MUXSELf(b) -#define _MUXSELd(a, b...) 0##a << 26 | _MUXSELe(b) -#define _MUXSELc(a, b...) 0##a << 24 | _MUXSELd(b) -#define _MUXSELb(a, b...) 0##a << 22 | _MUXSELc(b) -#define _MUXSELa(a, b...) 0##a << 20 | _MUXSELb(b) -#define _MUXSEL9(a, b...) 0##a << 18 | _MUXSELa(b) -#define _MUXSEL8(a, b...) 0##a << 16 | _MUXSEL9(b) -#define _MUXSEL7(a, b...) 0##a << 14 | _MUXSEL8(b) -#define _MUXSEL6(a, b...) 0##a << 12 | _MUXSEL7(b) -#define _MUXSEL5(a, b...) 0##a << 10 | _MUXSEL6(b) -#define _MUXSEL4(a, b...) 0##a << 8 | _MUXSEL5(b) -#define _MUXSEL3(a, b...) 0##a << 6 | _MUXSEL4(b) -#define _MUXSEL2(a, b...) 0##a << 4 | _MUXSEL3(b) -#define _MUXSEL1(a, b...) 0##a << 2 | _MUXSEL2(b) -#define MUXSEL(a, b...) (a | _MUXSEL1(b)) - -/* identification / initialization of the card */ -extern void bttv_idcard(struct bttv *btv); -extern void bttv_init_card1(struct bttv *btv); -extern void bttv_init_card2(struct bttv *btv); -extern void bttv_init_tuner(struct bttv *btv); - -/* card-specific funtions */ -extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); -extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); - -/* extra tweaks for some chipsets */ -extern void bttv_check_chipset(void); -extern int bttv_handle_chipset(struct bttv *btv); - -/* ---------------------------------------------------------- */ -/* exported by bttv-if.c */ - -/* this obsolete -- please use the sysfs-based - interface below for new code */ - -extern struct pci_dev* bttv_get_pcidev(unsigned int card); - -/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: - data | (current_GPOE_value & ~mask) - returns negative value if error occurred -*/ -extern int bttv_gpio_enable(unsigned int card, - unsigned long mask, unsigned long data); - -/* fills data with GPDATA register contents - returns negative value if error occurred -*/ -extern int bttv_read_gpio(unsigned int card, unsigned long *data); - -/* sets GPDATA register to new value: - (data & mask) | (current_GPDATA_value & ~mask) - returns negative value if error occurred -*/ -extern int bttv_write_gpio(unsigned int card, - unsigned long mask, unsigned long data); - - - - -/* ---------------------------------------------------------- */ -/* sysfs/driver-moded based gpio access interface */ - -struct bttv_sub_device { - struct device dev; - struct bttv_core *core; - struct list_head list; -}; -#define to_bttv_sub_dev(x) container_of((x), struct bttv_sub_device, dev) - -struct bttv_sub_driver { - struct device_driver drv; - char wanted[20]; - int (*probe)(struct bttv_sub_device *sub); - void (*remove)(struct bttv_sub_device *sub); -}; -#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) - -int bttv_sub_register(struct bttv_sub_driver *drv, char *wanted); -int bttv_sub_unregister(struct bttv_sub_driver *drv); - -/* gpio access functions */ -void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits); -u32 bttv_gpio_read(struct bttv_core *core); -void bttv_gpio_write(struct bttv_core *core, u32 value); -void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); - -#define gpio_inout(mask,bits) bttv_gpio_inout(&btv->c, mask, bits) -#define gpio_read() bttv_gpio_read(&btv->c) -#define gpio_write(value) bttv_gpio_write(&btv->c, value) -#define gpio_bits(mask,bits) bttv_gpio_bits(&btv->c, mask, bits) - - -/* ---------------------------------------------------------- */ -/* i2c */ - -#define bttv_call_all(btv, o, f, args...) \ - v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args) - -extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); -extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, - unsigned char b2, int both); -extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr); - -extern int bttv_input_init(struct bttv *dev); -extern void bttv_input_fini(struct bttv *dev); -extern void bttv_input_irq(struct bttv *dev); - -#endif /* _BTTV_H_ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h deleted file mode 100644 index 70fd4f23f605..000000000000 --- a/drivers/media/video/bt8xx/bttvp.h +++ /dev/null @@ -1,535 +0,0 @@ -/* - - bttv - Bt848 frame grabber driver - - bttv's *private* header file -- nobody other than bttv itself - should ever include this file. - - (c) 2000-2002 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. -*/ - -#ifndef _BTTVP_H_ -#define _BTTVP_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bt848.h" -#include "bttv.h" -#include "btcx-risc.h" - -#ifdef __KERNEL__ - -#define FORMAT_FLAGS_DITHER 0x01 -#define FORMAT_FLAGS_PACKED 0x02 -#define FORMAT_FLAGS_PLANAR 0x04 -#define FORMAT_FLAGS_RAW 0x08 -#define FORMAT_FLAGS_CrCb 0x10 - -#define RISC_SLOT_O_VBI 4 -#define RISC_SLOT_O_FIELD 6 -#define RISC_SLOT_E_VBI 10 -#define RISC_SLOT_E_FIELD 12 -#define RISC_SLOT_LOOP 14 - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO_STREAM 2 -#define RESOURCE_VBI 4 -#define RESOURCE_VIDEO_READ 8 - -#define RAW_LINES 640 -#define RAW_BPL 1024 - -#define UNSET (-1U) - -/* Min. value in VDELAY register. */ -#define MIN_VDELAY 2 -/* Even to get Cb first, odd for Cr. */ -#define MAX_HDELAY (0x3FF & -2) -/* Limits scaled width, which must be a multiple of 4. */ -#define MAX_HACTIVE (0x3FF & -4) - -#define BTTV_NORMS (\ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60) -/* ---------------------------------------------------------- */ - -struct bttv_tvnorm { - int v4l2_id; - char *name; - u32 Fsc; - u16 swidth, sheight; /* scaled standard width, height */ - u16 totalwidth; - u8 adelay, bdelay, iform; - u32 scaledtwidth; - u16 hdelayx1, hactivex1; - u16 vdelay; - u8 vbipack; - u16 vtotal; - int sram; - /* ITU-R frame line number of the first VBI line we can - capture, of the first and second field. The last possible line - is determined by cropcap.bounds. */ - u16 vbistart[2]; - /* Horizontally this counts fCLKx1 samples following the leading - edge of the horizontal sync pulse, vertically ITU-R frame line - numbers of the first field times two (2, 4, 6, ... 524 or 624). */ - struct v4l2_cropcap cropcap; -}; -extern const struct bttv_tvnorm bttv_tvnorms[]; - -struct bttv_format { - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift,vshift; /* for planar modes */ -}; - -struct bttv_ir { - struct rc_dev *dev; - struct timer_list timer; - - char name[32]; - char phys[32]; - - /* Usual gpio signalling */ - u32 mask_keycode; - u32 mask_keydown; - u32 mask_keyup; - u32 polling; - u32 last_gpio; - int shift_by; - int start; // What should RC5_START() be - int addr; // What RC5_ADDR() should be. - int rc5_remote_gap; - - /* RC5 gpio */ - bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */ - u32 last_bit; /* last raw bit seen */ - u32 code; /* raw code under construction */ - struct timeval base_time; /* time of last seen code */ - bool active; /* building raw code */ -}; - - -/* ---------------------------------------------------------- */ - -struct bttv_geometry { - u8 vtc,crop,comb; - u16 width,hscale,hdelay; - u16 sheight,vscale,vdelay,vtotal; -}; - -struct bttv_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* bttv specific */ - const struct bttv_format *fmt; - unsigned int tvnorm; - int btformat; - int btswap; - struct bttv_geometry geo; - struct btcx_riscmem top; - struct btcx_riscmem bottom; - struct v4l2_rect crop; - unsigned int vbi_skip[2]; - unsigned int vbi_count[2]; -}; - -struct bttv_buffer_set { - struct bttv_buffer *top; /* top field buffer */ - struct bttv_buffer *bottom; /* bottom field buffer */ - unsigned int top_irq; - unsigned int frame_irq; -}; - -struct bttv_overlay { - unsigned int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct bttv_vbi_fmt { - struct v4l2_vbi_format fmt; - - /* fmt.start[] and count[] refer to this video standard. */ - const struct bttv_tvnorm *tvnorm; - - /* Earliest possible start of video capturing with this - v4l2_vbi_format, in struct bttv_crop.rect units. */ - __s32 end; -}; - -/* bttv-vbi.c */ -void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm); - -struct bttv_crop { - /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */ - struct v4l2_rect rect; - - /* Scaled image size limits with this crop rect. Divide - max_height, but not min_height, by two when capturing - single fields. See also bttv_crop_reset() and - bttv_crop_adjust() in bttv-driver.c. */ - __s32 min_scaled_width; - __s32 min_scaled_height; - __s32 max_scaled_width; - __s32 max_scaled_height; -}; - -struct bttv_fh { - struct bttv *btv; - int resources; -#ifdef VIDIOC_G_PRIORITY - enum v4l2_priority prio; -#endif - enum v4l2_buf_type type; - - /* video capture */ - struct videobuf_queue cap; - const struct bttv_format *fmt; - int width; - int height; - - /* video overlay */ - const struct bttv_format *ovfmt; - struct bttv_overlay ov; - - /* Application called VIDIOC_S_CROP. */ - int do_crop; - - /* vbi capture */ - struct videobuf_queue vbi; - /* Current VBI capture window as seen through this fh (cannot - be global for compatibility with earlier drivers). Protected - by struct bttv.lock and struct bttv_fh.vbi.lock. */ - struct bttv_vbi_fmt vbi_fmt; -}; - -/* ---------------------------------------------------------- */ -/* bttv-risc.c */ - -/* risc code generators - capture */ -int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int offset, unsigned int bpl, - unsigned int pitch, unsigned int skip_lines, - unsigned int store_lines); - -/* control dma register + risc main loop */ -void bttv_set_dma(struct bttv *btv, int override); -int bttv_risc_init_main(struct bttv *btv); -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_video(struct bttv *btv, - struct bttv_buffer_set *set); -int bttv_buffer_activate_vbi(struct bttv *btv, - struct bttv_buffer *vbi); -void bttv_dma_free(struct videobuf_queue *q, struct bttv *btv, - struct bttv_buffer *buf); - -/* overlay handling */ -int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, - const struct bttv_format *fmt, - struct bttv_buffer *buf); - - -/* ---------------------------------------------------------- */ -/* bttv-vbi.c */ - -int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); -int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); -int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); - -extern struct videobuf_queue_ops bttv_vbi_qops; - -/* ---------------------------------------------------------- */ -/* bttv-gpio.c */ - -extern struct bus_type bttv_sub_bus_type; -int bttv_sub_add_device(struct bttv_core *core, char *name); -int bttv_sub_del_devices(struct bttv_core *core); - -/* ---------------------------------------------------------- */ -/* bttv-cards.c */ - -extern int no_overlay; - -/* ---------------------------------------------------------- */ -/* bttv-input.c */ - -extern void init_bttv_i2c_ir(struct bttv *btv); -extern int fini_bttv_i2c(struct bttv *btv); - -/* ---------------------------------------------------------- */ -/* bttv-driver.c */ - -/* insmod options */ -extern unsigned int bttv_verbose; -extern unsigned int bttv_debug; -extern unsigned int bttv_gpio; -extern void bttv_gpio_tracking(struct bttv *btv, char *comment); -extern int init_bttv_i2c(struct bttv *btv); - -#define dprintk(fmt, ...) \ -do { \ - if (bttv_debug >= 1) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) -#define dprintk_cont(fmt, ...) \ -do { \ - if (bttv_debug >= 1) \ - pr_cont(fmt, ##__VA_ARGS__); \ -} while (0) -#define d2printk(fmt, ...) \ -do { \ - if (bttv_debug >= 2) \ - printk(fmt, ##__VA_ARGS__); \ -} while (0) - -#define BTTV_MAX_FBUF 0x208000 -#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */ - - -struct bttv_pll_info { - unsigned int pll_ifreq; /* PLL input frequency */ - unsigned int pll_ofreq; /* PLL output frequency */ - unsigned int pll_crystal; /* Crystal used for input */ - unsigned int pll_current; /* Currently programmed ofreq */ -}; - -/* for gpio-connected remote control */ -struct bttv_input { - struct input_dev *dev; - char name[32]; - char phys[32]; - u32 mask_keycode; - u32 mask_keydown; -}; - -struct bttv_suspend_state { - u32 gpio_enable; - u32 gpio_data; - int disabled; - int loop_irq; - struct bttv_buffer_set video; - struct bttv_buffer *vbi; -}; - -struct bttv { - struct bttv_core c; - - /* pci device config */ - unsigned short id; - unsigned char revision; - unsigned char __iomem *bt848_mmio; /* pointer to mmio */ - - /* card configuration info */ - unsigned int cardid; /* pci subsystem id (bt878 based ones) */ - unsigned int tuner_type; /* tuner chip type */ - unsigned int tda9887_conf; - unsigned int svhs, dig; - unsigned int has_saa6588:1; - struct bttv_pll_info pll; - int triton1; - int gpioirq; - - int use_i2c_hw; - - /* old gpio interface */ - int shutdown; - - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); - - /* new gpio interface */ - spinlock_t gpio_lock; - - /* i2c layer */ - struct i2c_algo_bit_data i2c_algo; - struct i2c_client i2c_client; - int i2c_state, i2c_rc; - int i2c_done; - wait_queue_head_t i2c_queue; - struct v4l2_subdev *sd_msp34xx; - struct v4l2_subdev *sd_tvaudio; - - /* video4linux (1) */ - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; - - /* infrared remote */ - int has_remote; - struct bttv_ir *remote; - - /* I2C remote data */ - struct IR_i2c_init_data init_data; - - /* locking */ - spinlock_t s_lock; - struct mutex lock; - int resources; -#ifdef VIDIOC_G_PRIORITY - struct v4l2_prio_state prio; -#endif - - /* video state */ - unsigned int input; - unsigned int audio; - unsigned int mute; - unsigned long freq; - unsigned int tvnorm; - int hue, contrast, bright, saturation; - struct v4l2_framebuffer fbuf; - unsigned int field_count; - - /* various options */ - int opt_combfilter; - int opt_lumafilter; - int opt_automute; - int opt_chroma_agc; - int opt_adc_crush; - int opt_vcr_hack; - int opt_whitecrush_upper; - int opt_whitecrush_lower; - int opt_uv_ratio; - int opt_full_luma_range; - int opt_coring; - - /* radio data/state */ - int has_radio; - int radio_user; - int radio_uses_msp_demodulator; - - /* miro/pinnacle + Aimslab VHX - philips matchbox (tea5757 radio tuner) support */ - int has_matchbox; - int mbox_we; - int mbox_data; - int mbox_clk; - int mbox_most; - int mbox_mask; - - /* ISA stuff (Terratec Active Radio Upgrade) */ - int mbox_ior; - int mbox_iow; - int mbox_csel; - - /* risc memory management data - - must acquire s_lock before changing these - - 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 */ - struct bttv_buffer *cvbi; /* active vbi buffer */ - int loop_irq; - int new_input; - - unsigned long cap_ctl; - unsigned long dma_on; - struct timer_list timeout; - struct bttv_suspend_state state; - - /* stats */ - unsigned int errors; - unsigned int framedrop; - unsigned int irq_total; - unsigned int irq_me; - - unsigned int users; - struct bttv_fh init; - - /* used to make dvb-bt8xx autoloadable */ - struct work_struct request_module_wk; - - /* Default (0) and current (1) video capturing and overlay - cropping parameters in bttv_tvnorm.cropcap units. Protected - by bttv.lock. */ - struct bttv_crop crop[2]; - - /* Earliest possible start of video capturing in - bttv_tvnorm.cropcap line units. Set by check_alloc_btres() - and free_btres(). Protected by bttv.lock. */ - __s32 vbi_end; - - /* Latest possible end of VBI capturing (= crop[x].rect.top when - VIDEO_RESOURCES are locked). Set by check_alloc_btres() - and free_btres(). Protected by bttv.lock. */ - __s32 crop_start; -}; - -static inline struct bttv *to_bttv(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct bttv, c.v4l2_dev); -} - -/* our devices */ -#define BTTV_MAX 32 -extern unsigned int bttv_num; -extern struct bttv *bttvs[BTTV_MAX]; - -static inline unsigned int bttv_muxsel(const struct bttv *btv, - unsigned int input) -{ - return (bttv_tvcards[btv->c.type].muxsel >> (input * 2)) & 3; -} - -#endif - -#define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) -#define btread(adr) readl(btv->bt848_mmio+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#endif /* _BTTVP_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */