mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-30 07:38:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
43
drivers/media/pci/bt8xx/Kconfig
Normal file
43
drivers/media/pci/bt8xx/Kconfig
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
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 MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
Support for BT848 based frame grabber/overlay boards. This includes
|
||||
the Miro, Hauppauge and STB boards. Please read the material in
|
||||
<file:Documentation/video4linux/bttv/> for more information.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bttv.
|
||||
|
||||
config DVB_BT8XX
|
||||
tristate "DVB/ATSC Support for bt878 based TV cards"
|
||||
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_SP887X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24110 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_OR51211 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
|
||||
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
|
||||
the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
|
||||
some AVerMedia cards.
|
||||
|
||||
Since these cards have no MPEG decoder onboard, they transmit
|
||||
only compressed MPEG data over the PCI bus, so you need
|
||||
an external software decoder to watch TV on your computer.
|
||||
|
||||
Say Y if you own such a device and want to use it.
|
||||
12
drivers/media/pci/bt8xx/Makefile
Normal file
12
drivers/media/pci/bt8xx/Makefile
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
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/i2c
|
||||
ccflags-y += -Idrivers/media/common
|
||||
ccflags-y += -Idrivers/media/tuners
|
||||
369
drivers/media/pci/bt8xx/bt848.h
Normal file
369
drivers/media/pci/bt8xx/bt848.h
Normal file
|
|
@ -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
|
||||
598
drivers/media/pci/bt8xx/bt878.c
Normal file
598
drivers/media/pci/bt8xx/bt878.c
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card
|
||||
*
|
||||
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
|
||||
*
|
||||
* large parts based on the bttv driver
|
||||
* Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de)
|
||||
* & Marcus Metzler (mocm@metzlerbros.de)
|
||||
* (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "bt878.h"
|
||||
#include "dst_priv.h"
|
||||
|
||||
|
||||
/**************************************/
|
||||
/* Miscellaneous utility definitions */
|
||||
/**************************************/
|
||||
|
||||
static unsigned int bt878_verbose = 1;
|
||||
static unsigned int bt878_debug;
|
||||
|
||||
module_param_named(verbose, bt878_verbose, int, 0444);
|
||||
MODULE_PARM_DESC(verbose,
|
||||
"verbose startup messages, default is 1 (yes)");
|
||||
module_param_named(debug, bt878_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
|
||||
|
||||
int bt878_num;
|
||||
struct bt878 bt878[BT878_MAX];
|
||||
|
||||
EXPORT_SYMBOL(bt878_num);
|
||||
EXPORT_SYMBOL(bt878);
|
||||
|
||||
#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr)))
|
||||
#define btread(adr) bmtread(bt->bt878_mem+(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)
|
||||
|
||||
#if defined(dprintk)
|
||||
#undef dprintk
|
||||
#endif
|
||||
#define dprintk(fmt, arg...) \
|
||||
do { \
|
||||
if (bt878_debug) \
|
||||
printk(KERN_DEBUG fmt, ##arg); \
|
||||
} while (0)
|
||||
|
||||
static void bt878_mem_free(struct bt878 *bt)
|
||||
{
|
||||
if (bt->buf_cpu) {
|
||||
pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu,
|
||||
bt->buf_dma);
|
||||
bt->buf_cpu = NULL;
|
||||
}
|
||||
|
||||
if (bt->risc_cpu) {
|
||||
pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu,
|
||||
bt->risc_dma);
|
||||
bt->risc_cpu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int bt878_mem_alloc(struct bt878 *bt)
|
||||
{
|
||||
if (!bt->buf_cpu) {
|
||||
bt->buf_size = 128 * 1024;
|
||||
|
||||
bt->buf_cpu = pci_zalloc_consistent(bt->dev, bt->buf_size,
|
||||
&bt->buf_dma);
|
||||
if (!bt->buf_cpu)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!bt->risc_cpu) {
|
||||
bt->risc_size = PAGE_SIZE;
|
||||
bt->risc_cpu = pci_zalloc_consistent(bt->dev, bt->risc_size,
|
||||
&bt->risc_dma);
|
||||
if (!bt->risc_cpu) {
|
||||
bt878_mem_free(bt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RISC instructions */
|
||||
#define RISC_WRITE (0x01 << 28)
|
||||
#define RISC_JUMP (0x07 << 28)
|
||||
#define RISC_SYNC (0x08 << 28)
|
||||
|
||||
/* RISC bits */
|
||||
#define RISC_WR_SOL (1 << 27)
|
||||
#define RISC_WR_EOL (1 << 26)
|
||||
#define RISC_IRQ (1 << 24)
|
||||
#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
|
||||
#define RISC_SYNC_RESYNC (1 << 15)
|
||||
#define RISC_SYNC_FM1 0x06
|
||||
#define RISC_SYNC_VRO 0x0C
|
||||
|
||||
#define RISC_FLUSH() bt->risc_pos = 0
|
||||
#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
|
||||
|
||||
static int bt878_make_risc(struct bt878 *bt)
|
||||
{
|
||||
bt->block_bytes = bt->buf_size >> 4;
|
||||
bt->block_count = 1 << 4;
|
||||
bt->line_bytes = bt->block_bytes;
|
||||
bt->line_count = bt->block_count;
|
||||
|
||||
while (bt->line_bytes > 4095) {
|
||||
bt->line_bytes >>= 1;
|
||||
bt->line_count <<= 1;
|
||||
}
|
||||
|
||||
if (bt->line_count > 255) {
|
||||
printk(KERN_ERR "bt878: buffer size error!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin)
|
||||
{
|
||||
u32 buf_pos = 0;
|
||||
u32 line;
|
||||
|
||||
RISC_FLUSH();
|
||||
RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
|
||||
RISC_INSTR(0);
|
||||
|
||||
dprintk("bt878: risc len lines %u, bytes per line %u\n",
|
||||
bt->line_count, bt->line_bytes);
|
||||
for (line = 0; line < bt->line_count; line++) {
|
||||
// At the beginning of every block we issue an IRQ with previous (finished) block number set
|
||||
if (!(buf_pos % bt->block_bytes))
|
||||
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
|
||||
RISC_IRQ |
|
||||
RISC_STATUS(((buf_pos /
|
||||
bt->block_bytes) +
|
||||
(bt->block_count -
|
||||
1)) %
|
||||
bt->block_count) | bt->
|
||||
line_bytes);
|
||||
else
|
||||
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
|
||||
bt->line_bytes);
|
||||
RISC_INSTR(bt->buf_dma + buf_pos);
|
||||
buf_pos += bt->line_bytes;
|
||||
}
|
||||
|
||||
RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO);
|
||||
RISC_INSTR(0);
|
||||
|
||||
RISC_INSTR(RISC_JUMP);
|
||||
RISC_INSTR(bt->risc_dma);
|
||||
|
||||
btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
/* Start/Stop grabbing funcs */
|
||||
/*****************************/
|
||||
|
||||
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
|
||||
u32 irq_err_ignore)
|
||||
{
|
||||
u32 int_mask;
|
||||
|
||||
dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg);
|
||||
/* complete the writing of the risc dma program now we have
|
||||
* the card specifics
|
||||
*/
|
||||
bt878_risc_program(bt, op_sync_orin);
|
||||
controlreg &= ~0x1f;
|
||||
controlreg |= 0x1b;
|
||||
|
||||
btwrite(bt->risc_dma, BT878_ARISC_START);
|
||||
|
||||
/* original int mask had :
|
||||
* 6 2 8 4 0
|
||||
* 1111 1111 1000 0000 0000
|
||||
* SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI
|
||||
* Hacked for DST to:
|
||||
* SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
|
||||
*/
|
||||
int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
|
||||
BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
|
||||
BT878_AFBUS | BT878_ARISCI;
|
||||
|
||||
|
||||
/* ignore pesky bits */
|
||||
int_mask &= ~irq_err_ignore;
|
||||
|
||||
btwrite(int_mask, BT878_AINT_MASK);
|
||||
btwrite(controlreg, BT878_AGPIO_DMA_CTL);
|
||||
}
|
||||
|
||||
void bt878_stop(struct bt878 *bt)
|
||||
{
|
||||
u32 stat;
|
||||
int i = 0;
|
||||
|
||||
dprintk("bt878 debug: bt878_stop\n");
|
||||
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
btand(~0x13, BT878_AGPIO_DMA_CTL);
|
||||
|
||||
do {
|
||||
stat = btread(BT878_AINT_STAT);
|
||||
if (!(stat & BT878_ARISC_EN))
|
||||
break;
|
||||
i++;
|
||||
} while (i < 500);
|
||||
|
||||
dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",
|
||||
bt->nr, i, stat);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(bt878_start);
|
||||
EXPORT_SYMBOL(bt878_stop);
|
||||
|
||||
/*****************************/
|
||||
/* Interrupt service routine */
|
||||
/*****************************/
|
||||
|
||||
static irqreturn_t bt878_irq(int irq, void *dev_id)
|
||||
{
|
||||
u32 stat, astat, mask;
|
||||
int count;
|
||||
struct bt878 *bt;
|
||||
|
||||
bt = (struct bt878 *) dev_id;
|
||||
|
||||
count = 0;
|
||||
while (1) {
|
||||
stat = btread(BT878_AINT_STAT);
|
||||
mask = btread(BT878_AINT_MASK);
|
||||
if (!(astat = (stat & mask)))
|
||||
return IRQ_NONE; /* this interrupt is not for me */
|
||||
/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
|
||||
btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */
|
||||
|
||||
|
||||
if (astat & (BT878_ASCERR | BT878_AOCERR)) {
|
||||
if (bt878_verbose) {
|
||||
printk(KERN_INFO
|
||||
"bt878(%d): irq%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_ASCERR) ? " SCERR" :
|
||||
"",
|
||||
(astat & BT878_AOCERR) ? " OCERR" :
|
||||
"", btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
|
||||
if (bt878_verbose) {
|
||||
printk(KERN_INFO
|
||||
"bt878(%d): irq%s%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_APABORT) ? " PABORT" :
|
||||
"",
|
||||
(astat & BT878_ARIPERR) ? " RIPERR" :
|
||||
"",
|
||||
(astat & BT878_APPERR) ? " PPERR" :
|
||||
"", btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
|
||||
if (bt878_verbose) {
|
||||
printk(KERN_INFO
|
||||
"bt878(%d): irq%s%s%s risc_pc=%08x\n",
|
||||
bt->nr,
|
||||
(astat & BT878_AFDSR) ? " FDSR" : "",
|
||||
(astat & BT878_AFTRGT) ? " FTRGT" :
|
||||
"",
|
||||
(astat & BT878_AFBUS) ? " FBUS" : "",
|
||||
btread(BT878_ARISC_PC));
|
||||
}
|
||||
}
|
||||
if (astat & BT878_ARISCI) {
|
||||
bt->finished_block = (stat & BT878_ARISCS) >> 28;
|
||||
tasklet_schedule(&bt->tasklet);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
if (count > 20) {
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
printk(KERN_ERR
|
||||
"bt878(%d): IRQ lockup, cleared int mask\n",
|
||||
bt->nr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int
|
||||
bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = 0;
|
||||
if (mutex_lock_interruptible(&bt->gpio_lock))
|
||||
return -ERESTARTSYS;
|
||||
/* special gpio signal */
|
||||
switch (cmd) {
|
||||
case DST_IG_ENABLE:
|
||||
// dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable);
|
||||
retval = bttv_gpio_enable(bt->bttv_nr,
|
||||
mp->enb.mask,
|
||||
mp->enb.enable);
|
||||
break;
|
||||
case DST_IG_WRITE:
|
||||
// dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals);
|
||||
retval = bttv_write_gpio(bt->bttv_nr,
|
||||
mp->outp.mask,
|
||||
mp->outp.highvals);
|
||||
|
||||
break;
|
||||
case DST_IG_READ:
|
||||
/* read */
|
||||
retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value);
|
||||
// dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value);
|
||||
break;
|
||||
case DST_IG_TS:
|
||||
/* Set packet size */
|
||||
bt->TS_Size = mp->psize;
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&bt->gpio_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(bt878_device_control);
|
||||
|
||||
#define BROOKTREE_878_DEVICE(vend, dev, name) \
|
||||
{ \
|
||||
.vendor = PCI_VENDOR_ID_BROOKTREE, \
|
||||
.device = PCI_DEVICE_ID_BROOKTREE_878, \
|
||||
.subvendor = (vend), .subdevice = (dev), \
|
||||
.driver_data = (unsigned long) name \
|
||||
}
|
||||
|
||||
static struct pci_device_id bt878_pci_tbl[] = {
|
||||
BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
|
||||
BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
|
||||
BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
|
||||
BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
|
||||
BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
|
||||
BROOKTREE_878_DEVICE(0x270f, 0xfc00,
|
||||
"ChainTech digitop DST-1000 DVB-S"),
|
||||
BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
|
||||
BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
|
||||
BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
|
||||
BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
|
||||
BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
|
||||
BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
|
||||
|
||||
static const char * card_name(const struct pci_device_id *id)
|
||||
{
|
||||
return id->driver_data ? (const char *)id->driver_data : "Unknown";
|
||||
}
|
||||
|
||||
/***********************/
|
||||
/* PCI device handling */
|
||||
/***********************/
|
||||
|
||||
static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
|
||||
{
|
||||
int result = 0;
|
||||
unsigned char lat;
|
||||
struct bt878 *bt;
|
||||
#if defined(__powerpc__)
|
||||
unsigned int cmd;
|
||||
#endif
|
||||
unsigned int cardid;
|
||||
|
||||
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
|
||||
bt878_num);
|
||||
if (bt878_num >= BT878_MAX) {
|
||||
printk(KERN_ERR "bt878: Too many devices inserted\n");
|
||||
result = -ENOMEM;
|
||||
goto fail0;
|
||||
}
|
||||
if (pci_enable_device(dev))
|
||||
return -EIO;
|
||||
|
||||
cardid = dev->subsystem_device << 16;
|
||||
cardid |= dev->subsystem_vendor;
|
||||
|
||||
printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
|
||||
__func__, cardid, card_name(pci_id));
|
||||
|
||||
bt = &bt878[bt878_num];
|
||||
bt->dev = dev;
|
||||
bt->nr = bt878_num;
|
||||
bt->shutdown = 0;
|
||||
|
||||
bt->id = dev->device;
|
||||
bt->irq = dev->irq;
|
||||
bt->bt878_adr = pci_resource_start(dev, 0);
|
||||
if (!request_mem_region(pci_resource_start(dev, 0),
|
||||
pci_resource_len(dev, 0), "bt878")) {
|
||||
result = -EBUSY;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
bt->revision = dev->revision;
|
||||
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
|
||||
|
||||
|
||||
printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ",
|
||||
bt878_num, bt->id, bt->revision, dev->bus->number,
|
||||
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
|
||||
printk("irq: %d, latency: %d, memory: 0x%lx\n",
|
||||
bt->irq, lat, bt->bt878_adr);
|
||||
|
||||
|
||||
#if defined(__powerpc__)
|
||||
/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
|
||||
/* response on cards with no firmware is not enabled by OF */
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &cmd);
|
||||
cmd = (cmd | PCI_COMMAND_MEMORY);
|
||||
pci_write_config_dword(dev, PCI_COMMAND, cmd);
|
||||
#endif
|
||||
|
||||
#ifdef __sparc__
|
||||
bt->bt878_mem = (unsigned char *) bt->bt878_adr;
|
||||
#else
|
||||
bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000);
|
||||
#endif
|
||||
|
||||
/* clear interrupt mask */
|
||||
btwrite(0, BT848_INT_MASK);
|
||||
|
||||
result = request_irq(bt->irq, bt878_irq,
|
||||
IRQF_SHARED, "bt878", (void *) bt);
|
||||
if (result == -EINVAL) {
|
||||
printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
|
||||
bt878_num);
|
||||
goto fail1;
|
||||
}
|
||||
if (result == -EBUSY) {
|
||||
printk(KERN_ERR
|
||||
"bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",
|
||||
bt878_num, bt->irq);
|
||||
goto fail1;
|
||||
}
|
||||
if (result < 0)
|
||||
goto fail1;
|
||||
|
||||
pci_set_master(dev);
|
||||
pci_set_drvdata(dev, bt);
|
||||
|
||||
if ((result = bt878_mem_alloc(bt))) {
|
||||
printk(KERN_ERR "bt878: failed to allocate memory!\n");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
bt878_make_risc(bt);
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
bt878_num++;
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
free_irq(bt->irq, bt);
|
||||
fail1:
|
||||
release_mem_region(pci_resource_start(bt->dev, 0),
|
||||
pci_resource_len(bt->dev, 0));
|
||||
fail0:
|
||||
pci_disable_device(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void bt878_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
u8 command;
|
||||
struct bt878 *bt = pci_get_drvdata(pci_dev);
|
||||
|
||||
if (bt878_verbose)
|
||||
printk(KERN_INFO "bt878(%d): unloading\n", bt->nr);
|
||||
|
||||
/* turn off all capturing, DMA and IRQs */
|
||||
btand(~0x13, BT878_AGPIO_DMA_CTL);
|
||||
|
||||
/* first disable interrupts before unmapping the memory! */
|
||||
btwrite(0, BT878_AINT_MASK);
|
||||
btwrite(~0U, BT878_AINT_STAT);
|
||||
|
||||
/* disable PCI bus-mastering */
|
||||
pci_read_config_byte(bt->dev, PCI_COMMAND, &command);
|
||||
/* Should this be &=~ ?? */
|
||||
command &= ~PCI_COMMAND_MASTER;
|
||||
pci_write_config_byte(bt->dev, PCI_COMMAND, command);
|
||||
|
||||
free_irq(bt->irq, bt);
|
||||
printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem);
|
||||
if (bt->bt878_mem)
|
||||
iounmap(bt->bt878_mem);
|
||||
|
||||
release_mem_region(pci_resource_start(bt->dev, 0),
|
||||
pci_resource_len(bt->dev, 0));
|
||||
/* wake up any waiting processes
|
||||
because shutdown flag is set, no new processes (in this queue)
|
||||
are expected
|
||||
*/
|
||||
bt->shutdown = 1;
|
||||
bt878_mem_free(bt);
|
||||
|
||||
pci_disable_device(pci_dev);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct pci_driver bt878_pci_driver = {
|
||||
.name = "bt878",
|
||||
.id_table = bt878_pci_tbl,
|
||||
.probe = bt878_probe,
|
||||
.remove = bt878_remove,
|
||||
};
|
||||
|
||||
/*******************************/
|
||||
/* Module management functions */
|
||||
/*******************************/
|
||||
|
||||
static int __init bt878_init_module(void)
|
||||
{
|
||||
bt878_num = 0;
|
||||
|
||||
printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
|
||||
(BT878_VERSION_CODE >> 16) & 0xff,
|
||||
(BT878_VERSION_CODE >> 8) & 0xff,
|
||||
BT878_VERSION_CODE & 0xff);
|
||||
|
||||
return pci_register_driver(&bt878_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit bt878_cleanup_module(void)
|
||||
{
|
||||
pci_unregister_driver(&bt878_pci_driver);
|
||||
}
|
||||
|
||||
module_init(bt878_init_module);
|
||||
module_exit(bt878_cleanup_module);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
159
drivers/media/pci/bt8xx/bt878.h
Normal file
159
drivers/media/pci/bt8xx/bt878.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
bt878.h - Bt878 audio module (register offsets)
|
||||
|
||||
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.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 _BT878_H_
|
||||
#define _BT878_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "bt848.h"
|
||||
#include "bttv.h"
|
||||
|
||||
#define BT878_VERSION_CODE 0x000000
|
||||
|
||||
#define BT878_AINT_STAT 0x100
|
||||
#define BT878_ARISCS (0xf<<28)
|
||||
#define BT878_ARISC_EN (1<<27)
|
||||
#define BT878_ASCERR (1<<19)
|
||||
#define BT878_AOCERR (1<<18)
|
||||
#define BT878_APABORT (1<<17)
|
||||
#define BT878_ARIPERR (1<<16)
|
||||
#define BT878_APPERR (1<<15)
|
||||
#define BT878_AFDSR (1<<14)
|
||||
#define BT878_AFTRGT (1<<13)
|
||||
#define BT878_AFBUS (1<<12)
|
||||
#define BT878_ARISCI (1<<11)
|
||||
#define BT878_AOFLOW (1<<3)
|
||||
|
||||
#define BT878_AINT_MASK 0x104
|
||||
|
||||
#define BT878_AGPIO_DMA_CTL 0x10c
|
||||
#define BT878_A_GAIN (0xf<<28)
|
||||
#define BT878_A_G2X (1<<27)
|
||||
#define BT878_A_PWRDN (1<<26)
|
||||
#define BT878_A_SEL (3<<24)
|
||||
#define BT878_DA_SCE (1<<23)
|
||||
#define BT878_DA_LRI (1<<22)
|
||||
#define BT878_DA_MLB (1<<21)
|
||||
#define BT878_DA_LRD (0x1f<<16)
|
||||
#define BT878_DA_DPM (1<<15)
|
||||
#define BT878_DA_SBR (1<<14)
|
||||
#define BT878_DA_ES2 (1<<13)
|
||||
#define BT878_DA_LMT (1<<12)
|
||||
#define BT878_DA_SDR (0xf<<8)
|
||||
#define BT878_DA_IOM (3<<6)
|
||||
#define BT878_DA_APP (1<<5)
|
||||
#define BT878_ACAP_EN (1<<4)
|
||||
#define BT878_PKTP (3<<2)
|
||||
#define BT878_RISC_EN (1<<1)
|
||||
#define BT878_FIFO_EN 1
|
||||
|
||||
#define BT878_APACK_LEN 0x110
|
||||
#define BT878_AFP_LEN (0xff<<16)
|
||||
#define BT878_ALP_LEN 0xfff
|
||||
|
||||
#define BT878_ARISC_START 0x114
|
||||
|
||||
#define BT878_ARISC_PC 0x120
|
||||
|
||||
/* BT878 FUNCTION 0 REGISTERS */
|
||||
#define BT878_GPIO_DMA_CTL 0x10c
|
||||
|
||||
/* Interrupt register */
|
||||
#define BT878_INT_STAT 0x100
|
||||
#define BT878_INT_MASK 0x104
|
||||
#define BT878_I2CRACK (1<<25)
|
||||
#define BT878_I2CDONE (1<<8)
|
||||
|
||||
#define BT878_MAX 4
|
||||
|
||||
#define BT878_RISC_SYNC_MASK (1 << 15)
|
||||
|
||||
|
||||
#define BTTV_BOARD_UNKNOWN 0x00
|
||||
#define BTTV_BOARD_PINNACLESAT 0x5e
|
||||
#define BTTV_BOARD_NEBULA_DIGITV 0x68
|
||||
#define BTTV_BOARD_PC_HDTV 0x70
|
||||
#define BTTV_BOARD_TWINHAN_DST 0x71
|
||||
#define BTTV_BOARD_AVDVBT_771 0x7b
|
||||
#define BTTV_BOARD_AVDVBT_761 0x7c
|
||||
#define BTTV_BOARD_DVICO_DVBT_LITE 0x80
|
||||
#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
|
||||
|
||||
extern int bt878_num;
|
||||
|
||||
struct bt878 {
|
||||
struct mutex gpio_lock;
|
||||
unsigned int nr;
|
||||
unsigned int bttv_nr;
|
||||
struct i2c_adapter *adapter;
|
||||
struct pci_dev *dev;
|
||||
unsigned int id;
|
||||
unsigned int TS_Size;
|
||||
unsigned char revision;
|
||||
unsigned int irq;
|
||||
unsigned long bt878_adr;
|
||||
volatile void __iomem *bt878_mem; /* function 1 */
|
||||
|
||||
volatile u32 finished_block;
|
||||
volatile u32 last_block;
|
||||
u32 block_count;
|
||||
u32 block_bytes;
|
||||
u32 line_bytes;
|
||||
u32 line_count;
|
||||
|
||||
u32 buf_size;
|
||||
u8 *buf_cpu;
|
||||
dma_addr_t buf_dma;
|
||||
|
||||
u32 risc_size;
|
||||
__le32 *risc_cpu;
|
||||
dma_addr_t risc_dma;
|
||||
u32 risc_pos;
|
||||
|
||||
struct tasklet_struct tasklet;
|
||||
int shutdown;
|
||||
};
|
||||
|
||||
extern struct bt878 bt878[BT878_MAX];
|
||||
|
||||
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
|
||||
u32 irq_err_ignore);
|
||||
void bt878_stop(struct bt878 *bt);
|
||||
|
||||
#if defined(__powerpc__) /* big-endian */
|
||||
static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
|
||||
{
|
||||
st_le32(addr, val);
|
||||
eieio();
|
||||
}
|
||||
|
||||
#define bmtwrite(dat,adr) io_st_le32((adr),(dat))
|
||||
#define bmtread(adr) ld_le32((adr))
|
||||
#else
|
||||
#define bmtwrite(dat,adr) writel((dat), (adr))
|
||||
#define bmtread(adr) readl(adr)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
382
drivers/media/pci/bt8xx/bttv-audio-hook.c
Normal file
382
drivers/media/pci/bt8xx/bttv-audio-hook.c
Normal file
|
|
@ -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 <linux/delay.h>
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* 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<<loops))
|
||||
data |= WINVIEW_PT2254_DATA;
|
||||
else
|
||||
data &= ~WINVIEW_PT2254_DATA;
|
||||
gpio_write(data);
|
||||
udelay(5);
|
||||
data |= WINVIEW_PT2254_CLK;
|
||||
gpio_write(data);
|
||||
udelay(5);
|
||||
data &= ~WINVIEW_PT2254_CLK;
|
||||
gpio_write(data);
|
||||
}
|
||||
data |= WINVIEW_PT2254_STROBE;
|
||||
data &= ~WINVIEW_PT2254_DATA;
|
||||
gpio_write(data);
|
||||
udelay(10);
|
||||
data &= ~WINVIEW_PT2254_STROBE;
|
||||
gpio_write(data);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* mono/stereo control for various cards (which don't use i2c chips but */
|
||||
/* connect something to the GPIO pins */
|
||||
|
||||
void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
|
||||
{
|
||||
unsigned int con = 0;
|
||||
|
||||
if (set) {
|
||||
gpio_inout(0x300, 0x300);
|
||||
if (t->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 <medisoft@alohabbs.org.mx>
|
||||
* I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
|
||||
* 0xdde enables mono and 0xccd enables sap
|
||||
*
|
||||
* Petr Vandrovec <VANDROVE@vc.cvut.cz>
|
||||
* 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 <darekk@automex.pl>
|
||||
* 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 <darekk@automex.pl>
|
||||
* 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 <masaki@btree.org>
|
||||
*/
|
||||
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 <sian@big.or.jp>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
23
drivers/media/pci/bt8xx/bttv-audio-hook.h
Normal file
23
drivers/media/pci/bt8xx/bttv-audio-hook.h
Normal file
|
|
@ -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);
|
||||
|
||||
5057
drivers/media/pci/bt8xx/bttv-cards.c
Normal file
5057
drivers/media/pci/bt8xx/bttv-cards.c
Normal file
File diff suppressed because it is too large
Load diff
4437
drivers/media/pci/bt8xx/bttv-driver.c
Normal file
4437
drivers/media/pci/bt8xx/bttv-driver.c
Normal file
File diff suppressed because it is too large
Load diff
189
drivers/media/pci/bt8xx/bttv-gpio.c
Normal file
189
drivers/media/pci/bt8xx/bttv-gpio.c
Normal file
|
|
@ -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 <kraxel@bytesex.org>
|
||||
|
||||
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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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) {
|
||||
put_device(&sub->dev);
|
||||
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:
|
||||
*/
|
||||
404
drivers/media/pci/bt8xx/bttv-i2c.c
Normal file
404
drivers/media/pci/bt8xx/bttv-i2c.c
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
|
||||
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 <kraxel@bytesex.org>
|
||||
|
||||
(c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
- 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "bttvp.h"
|
||||
#include <media/v4l2-common.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
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 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(" <W %02x %02x", msg->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 (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_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(" <R %02x", (msg->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 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 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));
|
||||
btv->i2c_algo = 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;
|
||||
}
|
||||
|
||||
int fini_bttv_i2c(struct bttv *btv)
|
||||
{
|
||||
if (btv->i2c_rc == 0)
|
||||
i2c_del_adapter(&btv->c.i2c_adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
121
drivers/media/pci/bt8xx/bttv-if.c
Normal file
121
drivers/media/pci/bt8xx/bttv-if.c
Normal file
|
|
@ -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 <kraxel@bytesex.org>
|
||||
|
||||
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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#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:
|
||||
*/
|
||||
590
drivers/media/pci/bt8xx/bttv-input.c
Normal file
590
drivers/media/pci/bt8xx/bttv-input.c
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
/*
|
||||
*
|
||||
* 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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#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, RC_TYPE_UNKNOWN, 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, RC_TYPE_UNKNOWN, 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, RC_TYPE_UNKNOWN, 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, RC_TYPE_UNKNOWN, 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) & 0x03)
|
||||
#define RC5_TOGGLE(x) (((x) >> 11) & 0x01)
|
||||
#define RC5_ADDR(x) (((x) >> 6) & 0x1f)
|
||||
#define RC5_INSTR(x) (((x) >> 0) & 0x3f)
|
||||
|
||||
/* 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, rc5, scancode;
|
||||
u8 toggle, command, system;
|
||||
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
|
||||
ir->code = (ir->code << ir->shift_by) | 1;
|
||||
rc5 = bttv_rc5_decode(ir->code);
|
||||
|
||||
toggle = RC5_TOGGLE(rc5);
|
||||
system = RC5_ADDR(rc5);
|
||||
command = RC5_INSTR(rc5);
|
||||
|
||||
switch (RC5_START(rc5)) {
|
||||
case 0x3:
|
||||
break;
|
||||
case 0x2:
|
||||
command += 0x40;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
scancode = RC_SCANCODE_RC5(system, command);
|
||||
rc_keydown(ir->dev, RC_TYPE_RC5, scancode, toggle);
|
||||
dprintk("scancode %x, toggle %x\n", scancode, 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->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, enum rc_type *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
*protocol = RC_TYPE_UNKNOWN;
|
||||
*scancode = b;
|
||||
*toggle = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Instantiate the I2C IR receiver device, if present */
|
||||
void 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;
|
||||
struct i2c_client *i2c_dev;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (btv->init_data.name) {
|
||||
info.platform_data = &btv->init_data;
|
||||
i2c_dev = i2c_new_device(&btv->c.i2c_adap, &info);
|
||||
} else {
|
||||
/*
|
||||
* 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_dev = i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
|
||||
}
|
||||
if (NULL == i2c_dev)
|
||||
return;
|
||||
|
||||
#if defined(CONFIG_MODULES) && defined(MODULE)
|
||||
request_module("ir-kbd-i2c");
|
||||
#endif
|
||||
}
|
||||
|
||||
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:
|
||||
case BTTV_BOARD_KWORLD_VSTREAM_XPERT:
|
||||
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 (!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;
|
||||
}
|
||||
909
drivers/media/pci/bt8xx/bttv-risc.c
Normal file
909
drivers/media/pci/bt8xx/bttv-risc.c
Normal file
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
|
||||
bttv-risc.c -- interfaces to other kernel modules
|
||||
|
||||
bttv risc code handling
|
||||
- memory management
|
||||
- generation
|
||||
|
||||
(c) 2000-2003 Gerd Knorr <kraxel@bytesex.org>
|
||||
|
||||
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 <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
|
||||
#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:
|
||||
*/
|
||||
459
drivers/media/pci/bt8xx/bttv-vbi.c
Normal file
459
drivers/media/pci/bt8xx/bttv-vbi.c
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
|
||||
bttv - Bt848 frame grabber driver
|
||||
vbi interface
|
||||
|
||||
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
|
||||
|
||||
Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
|
||||
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 <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <asm/io.h>
|
||||
#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:
|
||||
*/
|
||||
385
drivers/media/pci/bt8xx/bttv.h
Normal file
385
drivers/media/pci/bt8xx/bttv.h
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
*
|
||||
* 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 <kraxel@goldbach.in-berlin.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BTTV_H_
|
||||
#define _BTTV_H_
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/i2c-addr.h>
|
||||
#include <media/tuner.h>
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* 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
|
||||
#define BTTV_BOARD_ADLINK_MPG24 0xa2
|
||||
#define BTTV_BOARD_BT848_CAP_14 0xa3
|
||||
#define BTTV_BOARD_CYBERVISION_CV06 0xa4
|
||||
#define BTTV_BOARD_KWORLD_VSTREAM_XPERT 0xa5
|
||||
#define BTTV_BOARD_PCI_8604PW 0xa6
|
||||
|
||||
/* 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
|
||||
#define PLL_14 3
|
||||
|
||||
/* 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)
|
||||
|
||||
#define bttv_call_all_err(btv, o, f, args...) \
|
||||
v4l2_device_call_until_err(&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:
|
||||
*/
|
||||
539
drivers/media/pci/bt8xx/bttvp.h
Normal file
539
drivers/media/pci/bt8xx/bttvp.h
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
|
||||
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 <kraxel@bytesex.org>
|
||||
|
||||
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 <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/io.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/rc-core.h>
|
||||
#include <media/ir-kbd-i2c.h>
|
||||
|
||||
#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 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 {
|
||||
/* This must be the first field in this struct */
|
||||
struct v4l2_fh fh;
|
||||
|
||||
struct bttv *btv;
|
||||
int resources;
|
||||
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);
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-i2c.c */
|
||||
extern int init_bttv_i2c(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);
|
||||
|
||||
#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;
|
||||
struct v4l2_subdev *sd_tda7432;
|
||||
|
||||
/* video4linux (1) */
|
||||
struct video_device *video_dev;
|
||||
struct video_device *radio_dev;
|
||||
struct video_device *vbi_dev;
|
||||
|
||||
/* controls */
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct v4l2_ctrl_handler radio_ctrl_handler;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* video state */
|
||||
unsigned int input;
|
||||
unsigned int audio_input;
|
||||
unsigned int mute;
|
||||
unsigned long tv_freq;
|
||||
unsigned int tvnorm;
|
||||
v4l2_std_id std;
|
||||
int hue, contrast, bright, saturation;
|
||||
struct v4l2_framebuffer fbuf;
|
||||
unsigned int field_count;
|
||||
|
||||
/* various options */
|
||||
int opt_combfilter;
|
||||
int opt_automute;
|
||||
int opt_vcr_hack;
|
||||
int opt_uv_ratio;
|
||||
|
||||
/* radio data/state */
|
||||
int has_radio;
|
||||
int has_radio_tuner;
|
||||
int radio_user;
|
||||
int radio_uses_msp_demodulator;
|
||||
unsigned long radio_freq;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* switch status for multi-controller cards */
|
||||
char sw_status[4];
|
||||
|
||||
/* 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:
|
||||
*/
|
||||
1873
drivers/media/pci/bt8xx/dst.c
Normal file
1873
drivers/media/pci/bt8xx/dst.c
Normal file
File diff suppressed because it is too large
Load diff
724
drivers/media/pci/bt8xx/dst_ca.c
Normal file
724
drivers/media/pci/bt8xx/dst_ca.c
Normal file
|
|
@ -0,0 +1,724 @@
|
|||
/*
|
||||
CA-driver for TwinHan DST Frontend/Card
|
||||
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
|
||||
|
||||
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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dst_ca.h"
|
||||
#include "dst_common.h"
|
||||
|
||||
#define DST_CA_ERROR 0
|
||||
#define DST_CA_NOTICE 1
|
||||
#define DST_CA_INFO 2
|
||||
#define DST_CA_DEBUG 3
|
||||
|
||||
#define dprintk(x, y, z, format, arg...) do { \
|
||||
if (z) { \
|
||||
if ((x > DST_CA_ERROR) && (x > y)) \
|
||||
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > DST_CA_NOTICE) && (x > y)) \
|
||||
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > DST_CA_INFO) && (x > y)) \
|
||||
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
|
||||
else if ((x > DST_CA_DEBUG) && (x > y)) \
|
||||
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
|
||||
} else { \
|
||||
if (x > y) \
|
||||
printk(format, ## arg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
static DEFINE_MUTEX(dst_ca_mutex);
|
||||
static unsigned int verbose = 5;
|
||||
module_param(verbose, int, 0644);
|
||||
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_set_slot_descr(void)
|
||||
{
|
||||
/* We could make this more graceful ? */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_set_pid(void)
|
||||
{
|
||||
/* We could make this more graceful ? */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void put_command_and_length(u8 *data, int command, int length)
|
||||
{
|
||||
data[0] = (command >> 16) & 0xff;
|
||||
data[1] = (command >> 8) & 0xff;
|
||||
data[2] = command & 0xff;
|
||||
data[3] = length;
|
||||
}
|
||||
|
||||
static void put_checksum(u8 *check_string, int length)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
|
||||
check_string[length] = dst_check_sum (check_string, length);
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
|
||||
}
|
||||
|
||||
static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
|
||||
{
|
||||
u8 reply;
|
||||
|
||||
mutex_lock(&state->dst_mutex);
|
||||
dst_comm_init(state);
|
||||
msleep(65);
|
||||
|
||||
if (write_dst(state, data, len)) {
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
if ((dst_pio_disable(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
|
||||
goto error;
|
||||
}
|
||||
if (read_dst(state, &reply, GET_ACK) < 0) {
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
if (read) {
|
||||
if (! dst_wait_dst_ready(state, LONG_DELAY)) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
|
||||
goto error;
|
||||
}
|
||||
if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
|
||||
dst_error_recovery(state);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&state->dst_mutex);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
mutex_unlock(&state->dst_mutex);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
|
||||
{
|
||||
u8 dst_ca_comm_err = 0;
|
||||
|
||||
while (dst_ca_comm_err < RETRIES) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
|
||||
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
|
||||
dst_error_recovery(state);
|
||||
dst_ca_comm_err++; // work required here.
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dst_ca_comm_err == RETRIES)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ca_get_app_info(struct dst_state *state)
|
||||
{
|
||||
int length, str_length;
|
||||
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
|
||||
|
||||
put_checksum(&command[0], command[0]);
|
||||
if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
|
||||
state->messages[7], (state->messages[8] << 8) | state->messages[9],
|
||||
(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
|
||||
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
|
||||
|
||||
// Transform dst message to correct application_info message
|
||||
length = state->messages[5];
|
||||
str_length = length - 6;
|
||||
if (str_length < 0) {
|
||||
str_length = 0;
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
|
||||
}
|
||||
|
||||
// First, the command and length fields
|
||||
put_command_and_length(&state->messages[0], CA_APP_INFO, length);
|
||||
|
||||
// Copy application_type, application_manufacturer and manufacturer_code
|
||||
memmove(&state->messages[4], &state->messages[7], 5);
|
||||
|
||||
// Set string length and copy string
|
||||
state->messages[9] = str_length;
|
||||
memmove(&state->messages[10], &state->messages[12], str_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_get_ca_info(struct dst_state *state)
|
||||
{
|
||||
int srcPtr, dstPtr, i, num_ids;
|
||||
static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
|
||||
const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
|
||||
|
||||
put_checksum(&slot_command[0], slot_command[0]);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
// Print raw data
|
||||
dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
|
||||
for (i = 0; i < state->messages[0] + 1; i++) {
|
||||
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 0, "]\n");
|
||||
|
||||
// Set the command and length of the output
|
||||
num_ids = state->messages[in_num_ids_pos];
|
||||
if (num_ids >= 100) {
|
||||
num_ids = 100;
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
|
||||
}
|
||||
put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
|
||||
srcPtr = in_system_id_pos;
|
||||
dstPtr = out_system_id_pos;
|
||||
for(i = 0; i < num_ids; i++) {
|
||||
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
|
||||
// Append to output
|
||||
state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
|
||||
state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
|
||||
srcPtr += 2;
|
||||
dstPtr += 2;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 0, "]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
|
||||
{
|
||||
int i;
|
||||
u8 slot_cap[256];
|
||||
static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
|
||||
|
||||
put_checksum(&slot_command[0], slot_command[0]);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
/* Will implement the rest soon */
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
|
||||
for (i = 0; i < slot_cap[0] + 1; i++)
|
||||
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "\n");
|
||||
|
||||
p_ca_caps->slot_num = 1;
|
||||
p_ca_caps->slot_type = 1;
|
||||
p_ca_caps->descr_num = slot_cap[7];
|
||||
p_ca_caps->descr_type = 1;
|
||||
|
||||
if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Need some more work */
|
||||
static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
|
||||
{
|
||||
int i;
|
||||
static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
|
||||
|
||||
u8 *slot_info = state->messages;
|
||||
|
||||
put_checksum(&slot_command[0], 7);
|
||||
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
|
||||
|
||||
/* Will implement the rest soon */
|
||||
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
|
||||
for (i = 0; i < 8; i++)
|
||||
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
|
||||
dprintk(verbose, DST_CA_INFO, 0, "\n");
|
||||
|
||||
if (slot_info[4] & 0x80) {
|
||||
p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
|
||||
p_ca_slot_info->num = 1;
|
||||
p_ca_slot_info->type = CA_CI;
|
||||
} else if (slot_info[4] & 0x40) {
|
||||
p_ca_slot_info->flags = CA_CI_MODULE_READY;
|
||||
p_ca_slot_info->num = 1;
|
||||
p_ca_slot_info->type = CA_CI;
|
||||
} else
|
||||
p_ca_slot_info->flags = 0;
|
||||
|
||||
if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
u8 i = 0;
|
||||
u32 command = 0;
|
||||
|
||||
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
|
||||
return -EFAULT;
|
||||
|
||||
if (p_ca_message->msg) {
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]",
|
||||
3, p_ca_message->msg);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
command = command | p_ca_message->msg[i];
|
||||
if (i < 2)
|
||||
command = command << 8;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
|
||||
|
||||
switch (command) {
|
||||
case CA_APP_INFO:
|
||||
memcpy(p_ca_message->msg, state->messages, 128);
|
||||
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
case CA_INFO:
|
||||
memcpy(p_ca_message->msg, state->messages, 128);
|
||||
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
|
||||
{
|
||||
if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
|
||||
hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
|
||||
hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
|
||||
} else {
|
||||
if (length > 247) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
|
||||
return -1;
|
||||
}
|
||||
hw_buffer->msg[0] = (length & 0xff) + 7;
|
||||
hw_buffer->msg[1] = 0x40;
|
||||
hw_buffer->msg[2] = 0x03;
|
||||
hw_buffer->msg[3] = 0x00;
|
||||
hw_buffer->msg[4] = 0x03;
|
||||
hw_buffer->msg[5] = length & 0xff;
|
||||
hw_buffer->msg[6] = 0x00;
|
||||
|
||||
/*
|
||||
* Need to compute length for EN50221 section 8.3.2, for the time being
|
||||
* assuming 8.3.2 is not applicable
|
||||
*/
|
||||
memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
|
||||
{
|
||||
if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
|
||||
rdc_reset_state(state);
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 asn_1_decode(u8 *asn_1_array)
|
||||
{
|
||||
u8 length_field = 0, word_count = 0, count = 0;
|
||||
u32 length = 0;
|
||||
|
||||
length_field = asn_1_array[0];
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
|
||||
if (length_field < 0x80) {
|
||||
length = length_field & 0x7f;
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
|
||||
} else {
|
||||
word_count = length_field & 0x7f;
|
||||
for (count = 0; count < word_count; count++) {
|
||||
length = length << 8;
|
||||
length += asn_1_array[count + 1];
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int debug_string(u8 *msg, u32 length, u32 offset)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
|
||||
for (i = offset; i < length; i++)
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
|
||||
dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
|
||||
{
|
||||
u32 length = 0;
|
||||
u8 tag_length = 8;
|
||||
|
||||
length = asn_1_decode(&p_ca_message->msg[3]);
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
|
||||
debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */
|
||||
|
||||
memset(hw_buffer->msg, '\0', length);
|
||||
handle_dst_tag(state, p_ca_message, hw_buffer, length);
|
||||
put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
|
||||
|
||||
debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */
|
||||
write_to_8820(state, hw_buffer, (length + tag_length), reply);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Board supports CA PMT reply ? */
|
||||
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
|
||||
{
|
||||
int ca_pmt_reply_test = 0;
|
||||
|
||||
/* Do test board */
|
||||
/* Not there yet but soon */
|
||||
|
||||
/* CA PMT Reply capable */
|
||||
if (ca_pmt_reply_test) {
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Process CA PMT Reply */
|
||||
/* will implement soon */
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
|
||||
}
|
||||
/* CA PMT Reply not capable */
|
||||
if (!ca_pmt_reply_test) {
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
|
||||
return -1;
|
||||
}
|
||||
dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
|
||||
/* put a dummy message */
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
u32 command = 0;
|
||||
struct ca_msg *hw_buffer;
|
||||
int result = 0;
|
||||
|
||||
if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
|
||||
return -ENOMEM;
|
||||
}
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " ");
|
||||
|
||||
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
|
||||
result = -EFAULT;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
|
||||
|
||||
if (p_ca_message->msg) {
|
||||
/* EN50221 tag */
|
||||
command = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
command = command | p_ca_message->msg[i];
|
||||
if (i < 2)
|
||||
command = command << 8;
|
||||
}
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
|
||||
|
||||
switch (command) {
|
||||
case CA_PMT:
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
|
||||
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
|
||||
break;
|
||||
case CA_PMT_REPLY:
|
||||
dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
|
||||
/* Have to handle the 2 basic types of cards here */
|
||||
if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
|
||||
break;
|
||||
case CA_APP_INFO_ENQUIRY: // only for debugging
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
|
||||
|
||||
if ((ca_get_app_info(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
|
||||
break;
|
||||
case CA_INFO_ENQUIRY:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
|
||||
|
||||
if ((ca_get_ca_info(state)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_mem_and_exit:
|
||||
kfree (hw_buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct dst_state *state;
|
||||
struct ca_slot_info *p_ca_slot_info;
|
||||
struct ca_caps *p_ca_caps;
|
||||
struct ca_msg *p_ca_message;
|
||||
void __user *arg = (void __user *)ioctl_arg;
|
||||
int result = 0;
|
||||
|
||||
mutex_lock(&dst_ca_mutex);
|
||||
dvbdev = file->private_data;
|
||||
state = (struct dst_state *)dvbdev->priv;
|
||||
p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
|
||||
p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
|
||||
p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
|
||||
if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
|
||||
result = -ENOMEM;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
|
||||
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
|
||||
switch (cmd) {
|
||||
case CA_SEND_MSG:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Sending message");
|
||||
if ((ca_send_message(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
break;
|
||||
case CA_GET_MSG:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting message");
|
||||
if ((ca_get_message(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
|
||||
break;
|
||||
case CA_RESET:
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
|
||||
dst_error_bailout(state);
|
||||
msleep(4000);
|
||||
break;
|
||||
case CA_GET_SLOT_INFO:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
|
||||
if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
|
||||
break;
|
||||
case CA_GET_CAP:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
|
||||
if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
|
||||
break;
|
||||
case CA_GET_DESCR_INFO:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
|
||||
if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
|
||||
break;
|
||||
case CA_SET_DESCR:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
|
||||
if ((ca_set_slot_descr()) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
|
||||
break;
|
||||
case CA_SET_PID:
|
||||
dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
|
||||
if ((ca_set_pid()) < 0) {
|
||||
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
|
||||
result = -1;
|
||||
goto free_mem_and_exit;
|
||||
}
|
||||
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
|
||||
default:
|
||||
result = -EOPNOTSUPP;
|
||||
}
|
||||
free_mem_and_exit:
|
||||
kfree (p_ca_message);
|
||||
kfree (p_ca_slot_info);
|
||||
kfree (p_ca_caps);
|
||||
|
||||
mutex_unlock(&dst_ca_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dst_ca_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
|
||||
try_module_get(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dst_ca_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
|
||||
{
|
||||
dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations dst_ca_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = dst_ca_ioctl,
|
||||
.open = dst_ca_open,
|
||||
.release = dst_ca_release,
|
||||
.read = dst_ca_read,
|
||||
.write = dst_ca_write,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct dvb_device dvbdev_ca = {
|
||||
.priv = NULL,
|
||||
.users = 1,
|
||||
.readers = 1,
|
||||
.writers = 1,
|
||||
.fops = &dst_ca_fops
|
||||
};
|
||||
|
||||
struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
|
||||
dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
|
||||
if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
|
||||
dst->dst_ca = dvbdev;
|
||||
return dst->dst_ca;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dst_ca_attach);
|
||||
|
||||
MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
|
||||
MODULE_AUTHOR("Manu Abraham");
|
||||
MODULE_LICENSE("GPL");
|
||||
58
drivers/media/pci/bt8xx/dst_ca.h
Normal file
58
drivers/media/pci/bt8xx/dst_ca.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
CA-driver for TwinHan DST Frontend/Card
|
||||
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
|
||||
|
||||
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 _DST_CA_H_
|
||||
#define _DST_CA_H_
|
||||
|
||||
#define RETRIES 5
|
||||
|
||||
|
||||
#define CA_APP_INFO_ENQUIRY 0x9f8020
|
||||
#define CA_APP_INFO 0x9f8021
|
||||
#define CA_ENTER_MENU 0x9f8022
|
||||
#define CA_INFO_ENQUIRY 0x9f8030
|
||||
#define CA_INFO 0x9f8031
|
||||
#define CA_PMT 0x9f8032
|
||||
#define CA_PMT_REPLY 0x9f8033
|
||||
|
||||
#define CA_CLOSE_MMI 0x9f8800
|
||||
#define CA_DISPLAY_CONTROL 0x9f8801
|
||||
#define CA_DISPLAY_REPLY 0x9f8802
|
||||
#define CA_TEXT_LAST 0x9f8803
|
||||
#define CA_TEXT_MORE 0x9f8804
|
||||
#define CA_KEYPAD_CONTROL 0x9f8805
|
||||
#define CA_KEYPRESS 0x9f8806
|
||||
|
||||
#define CA_ENQUIRY 0x9f8807
|
||||
#define CA_ANSWER 0x9f8808
|
||||
#define CA_MENU_LAST 0x9f8809
|
||||
#define CA_MENU_MORE 0x9f880a
|
||||
#define CA_MENU_ANSWER 0x9f880b
|
||||
#define CA_LIST_LAST 0x9f880c
|
||||
#define CA_LIST_MORE 0x9f880d
|
||||
|
||||
|
||||
struct dst_ca_private {
|
||||
struct dst_state *dst;
|
||||
struct dvb_device *dvbdev;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
182
drivers/media/pci/bt8xx/dst_common.h
Normal file
182
drivers/media/pci/bt8xx/dst_common.h
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
Frontend-driver for TwinHan DST Frontend
|
||||
|
||||
Copyright (C) 2003 Jamie Honan
|
||||
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
|
||||
|
||||
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 DST_COMMON_H
|
||||
#define DST_COMMON_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "bt878.h"
|
||||
|
||||
#include "dst_ca.h"
|
||||
|
||||
|
||||
#define NO_DELAY 0
|
||||
#define LONG_DELAY 1
|
||||
#define DEVICE_INIT 2
|
||||
|
||||
#define DELAY 1
|
||||
|
||||
#define DST_TYPE_IS_SAT 0
|
||||
#define DST_TYPE_IS_TERR 1
|
||||
#define DST_TYPE_IS_CABLE 2
|
||||
#define DST_TYPE_IS_ATSC 3
|
||||
|
||||
#define DST_TYPE_HAS_TS188 1
|
||||
#define DST_TYPE_HAS_TS204 2
|
||||
#define DST_TYPE_HAS_SYMDIV 4
|
||||
#define DST_TYPE_HAS_FW_1 8
|
||||
#define DST_TYPE_HAS_FW_2 16
|
||||
#define DST_TYPE_HAS_FW_3 32
|
||||
#define DST_TYPE_HAS_FW_BUILD 64
|
||||
#define DST_TYPE_HAS_OBS_REGS 128
|
||||
#define DST_TYPE_HAS_INC_COUNT 256
|
||||
#define DST_TYPE_HAS_MULTI_FE 512
|
||||
#define DST_TYPE_HAS_NEWTUNE_2 1024
|
||||
#define DST_TYPE_HAS_DBOARD 2048
|
||||
#define DST_TYPE_HAS_VLF 4096
|
||||
|
||||
/* Card capability list */
|
||||
|
||||
#define DST_TYPE_HAS_MAC 1
|
||||
#define DST_TYPE_HAS_DISEQC3 2
|
||||
#define DST_TYPE_HAS_DISEQC4 4
|
||||
#define DST_TYPE_HAS_DISEQC5 8
|
||||
#define DST_TYPE_HAS_MOTO 16
|
||||
#define DST_TYPE_HAS_CA 32
|
||||
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
|
||||
#define DST_TYPE_HAS_SESSION 128
|
||||
|
||||
#define TUNER_TYPE_MULTI 1
|
||||
#define TUNER_TYPE_UNKNOWN 2
|
||||
/* DVB-S */
|
||||
#define TUNER_TYPE_L64724 4
|
||||
#define TUNER_TYPE_STV0299 8
|
||||
#define TUNER_TYPE_MB86A15 16
|
||||
|
||||
/* DVB-T */
|
||||
#define TUNER_TYPE_TDA10046 32
|
||||
|
||||
/* ATSC */
|
||||
#define TUNER_TYPE_NXT200x 64
|
||||
|
||||
|
||||
#define RDC_8820_PIO_0_DISABLE 0
|
||||
#define RDC_8820_PIO_0_ENABLE 1
|
||||
#define RDC_8820_INT 2
|
||||
#define RDC_8820_RESET 4
|
||||
|
||||
/* DST Communication */
|
||||
#define GET_REPLY 1
|
||||
#define NO_REPLY 0
|
||||
|
||||
#define GET_ACK 1
|
||||
#define FIXED_COMM 8
|
||||
|
||||
#define ACK 0xff
|
||||
|
||||
struct dst_state {
|
||||
|
||||
struct i2c_adapter* i2c;
|
||||
|
||||
struct bt878* bt;
|
||||
|
||||
/* configuration settings */
|
||||
const struct dst_config* config;
|
||||
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
/* private ASIC data */
|
||||
u8 tx_tuna[10];
|
||||
u8 rx_tuna[10];
|
||||
u8 rxbuffer[10];
|
||||
u8 diseq_flags;
|
||||
u8 dst_type;
|
||||
u32 type_flags;
|
||||
u32 frequency; /* intermediate frequency in kHz for QPSK */
|
||||
fe_spectral_inversion_t inversion;
|
||||
u32 symbol_rate; /* symbol rate in Symbols per second */
|
||||
fe_code_rate_t fec;
|
||||
fe_sec_voltage_t voltage;
|
||||
fe_sec_tone_mode_t tone;
|
||||
u32 decode_freq;
|
||||
u8 decode_lock;
|
||||
u16 decode_strength;
|
||||
u16 decode_snr;
|
||||
unsigned long cur_jiff;
|
||||
u8 k22;
|
||||
u32 bandwidth;
|
||||
u32 dst_hw_cap;
|
||||
u8 dst_fw_version;
|
||||
fe_sec_mini_cmd_t minicmd;
|
||||
fe_modulation_t modulation;
|
||||
u8 messages[256];
|
||||
u8 mac_address[8];
|
||||
u8 fw_version[8];
|
||||
u8 card_info[8];
|
||||
u8 vendor[8];
|
||||
u8 board_info[8];
|
||||
u32 tuner_type;
|
||||
char *tuner_name;
|
||||
struct mutex dst_mutex;
|
||||
u8 fw_name[8];
|
||||
struct dvb_device *dst_ca;
|
||||
};
|
||||
|
||||
struct tuner_types {
|
||||
u32 tuner_type;
|
||||
char *tuner_name;
|
||||
char *board_name;
|
||||
char *fw_name;
|
||||
};
|
||||
|
||||
struct dst_types {
|
||||
char *device_id;
|
||||
int offset;
|
||||
u8 dst_type;
|
||||
u32 type_flags;
|
||||
u32 dst_feature;
|
||||
u32 tuner_type;
|
||||
};
|
||||
|
||||
struct dst_config
|
||||
{
|
||||
/* the ASIC i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
int rdc_reset_state(struct dst_state *state);
|
||||
|
||||
int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
|
||||
int dst_pio_disable(struct dst_state *state);
|
||||
int dst_error_recovery(struct dst_state* state);
|
||||
int dst_error_bailout(struct dst_state *state);
|
||||
int dst_comm_init(struct dst_state* state);
|
||||
|
||||
int write_dst(struct dst_state *state, u8 * data, u8 len);
|
||||
int read_dst(struct dst_state *state, u8 * ret, u8 len);
|
||||
u8 dst_check_sum(u8 * buf, u32 len);
|
||||
struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
|
||||
struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
|
||||
|
||||
|
||||
#endif // DST_COMMON_H
|
||||
35
drivers/media/pci/bt8xx/dst_priv.h
Normal file
35
drivers/media/pci/bt8xx/dst_priv.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
|
||||
*
|
||||
* Copyright (C) 2003 Jamie Honan
|
||||
*/
|
||||
|
||||
struct dst_gpio_enable {
|
||||
u32 mask;
|
||||
u32 enable;
|
||||
};
|
||||
|
||||
struct dst_gpio_output {
|
||||
u32 mask;
|
||||
u32 highvals;
|
||||
};
|
||||
|
||||
struct dst_gpio_read {
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
union dst_gpio_packet {
|
||||
struct dst_gpio_enable enb;
|
||||
struct dst_gpio_output outp;
|
||||
struct dst_gpio_read rd;
|
||||
int psize;
|
||||
};
|
||||
|
||||
#define DST_IG_ENABLE 0
|
||||
#define DST_IG_WRITE 1
|
||||
#define DST_IG_READ 2
|
||||
#define DST_IG_TS 3
|
||||
|
||||
struct bt878;
|
||||
|
||||
int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);
|
||||
976
drivers/media/pci/bt8xx/dvb-bt8xx.c
Normal file
976
drivers/media/pci/bt8xx/dvb-bt8xx.c
Normal file
|
|
@ -0,0 +1,976 @@
|
|||
/*
|
||||
* Bt8xx based DVB adapter driver
|
||||
*
|
||||
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
|
||||
*
|
||||
* 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) "dvb_bt8xx: " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb-bt8xx.h"
|
||||
#include "bt878.h"
|
||||
|
||||
static int debug;
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
#define dprintk( args... ) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG args); \
|
||||
} while (0)
|
||||
|
||||
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
|
||||
|
||||
static void dvb_bt8xx_task(unsigned long data)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
|
||||
|
||||
//printk("%d ", card->bt->finished_block);
|
||||
|
||||
while (card->bt->last_block != card->bt->finished_block) {
|
||||
(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
|
||||
(&card->demux,
|
||||
&card->bt->buf_cpu[card->bt->last_block *
|
||||
card->bt->block_bytes],
|
||||
card->bt->block_bytes);
|
||||
card->bt->last_block = (card->bt->last_block + 1) %
|
||||
card->bt->block_count;
|
||||
}
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
|
||||
struct dvb_bt8xx_card *card = dvbdmx->priv;
|
||||
int rc;
|
||||
|
||||
dprintk("dvb_bt8xx: start_feed\n");
|
||||
|
||||
if (!dvbdmx->dmx.frontend)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
card->nfeeds++;
|
||||
rc = card->nfeeds;
|
||||
if (card->nfeeds == 1)
|
||||
bt878_start(card->bt, card->gpio_mode,
|
||||
card->op_sync_orin, card->irq_err_ignore);
|
||||
mutex_unlock(&card->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
|
||||
struct dvb_bt8xx_card *card = dvbdmx->priv;
|
||||
|
||||
dprintk("dvb_bt8xx: stop_feed\n");
|
||||
|
||||
if (!dvbdmx->dmx.frontend)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
card->nfeeds--;
|
||||
if (card->nfeeds == 0)
|
||||
bt878_stop(card->bt);
|
||||
mutex_unlock(&card->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
|
||||
{
|
||||
if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
|
||||
(adev->subsystem_device == bdev->subsystem_device) &&
|
||||
(adev->bus->number == bdev->bus->number) &&
|
||||
(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bt878 *dvb_bt8xx_878_match(unsigned int bttv_nr,
|
||||
struct pci_dev* bttv_pci_dev)
|
||||
{
|
||||
unsigned int card_nr;
|
||||
|
||||
/* Hmm, n squared. Hope n is small */
|
||||
for (card_nr = 0; card_nr < bt878_num; card_nr++)
|
||||
if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
|
||||
return &bt878[card_nr];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
|
||||
static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
unsigned char cp = 0;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (c->frequency < 542000000)
|
||||
cp = 0xb4;
|
||||
else if (c->frequency < 771000000)
|
||||
cp = 0xbc;
|
||||
else
|
||||
cp = 0xf4;
|
||||
|
||||
if (c->frequency == 0)
|
||||
bs = 0x03;
|
||||
else if (c->frequency < 443250000)
|
||||
bs = 0x02;
|
||||
else
|
||||
bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x60;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = cp;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config thomson_dtt7579_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = thomson_dtt7579_demod_init,
|
||||
};
|
||||
|
||||
static struct zl10353_config thomson_dtt7579_zl10353_config = {
|
||||
.demod_address = 0x0f,
|
||||
};
|
||||
|
||||
static int cx24108_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u32 freq = c->frequency;
|
||||
int i, a, n, pump;
|
||||
u32 band, pll;
|
||||
u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
|
||||
1576000,1718000,1856000,2036000,2150000};
|
||||
u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
|
||||
0x00102000,0x00104000,0x00108000,0x00110000,
|
||||
0x00120000,0x00140000};
|
||||
|
||||
#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
|
||||
dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
|
||||
|
||||
/* This is really the bit driving the tuner chip cx24108 */
|
||||
|
||||
if (freq<950000)
|
||||
freq = 950000; /* kHz */
|
||||
else if (freq>2150000)
|
||||
freq = 2150000; /* satellite IF is 950..2150MHz */
|
||||
|
||||
/* decide which VCO to use for the input frequency */
|
||||
for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
|
||||
dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
|
||||
band=bandsel[i];
|
||||
/* the gain values must be set by SetSymbolrate */
|
||||
/* compute the pll divider needed, from Conexant data sheet,
|
||||
resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
|
||||
depending on the divider bit. It is set to /4 on the 2 lowest
|
||||
bands */
|
||||
n=((i<=2?2:1)*freq*10L)/(XTAL/100);
|
||||
a=n%32; n/=32; if(a==0) n--;
|
||||
pump=(freq<(osci[i-1]+osci[i])/2);
|
||||
pll=0xf8000000|
|
||||
((pump?1:2)<<(14+11))|
|
||||
((n&0x1ff)<<(5+11))|
|
||||
((a&0x1f)<<11);
|
||||
/* everything is shifted left 11 bits to left-align the bits in the
|
||||
32bit word. Output to the tuner goes MSB-aligned, after all */
|
||||
dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
|
||||
cx24110_pll_write(fe,band);
|
||||
/* set vga and vca to their widest-band settings, as a precaution.
|
||||
SetSymbolrate might not be called to set this up */
|
||||
cx24110_pll_write(fe,0x500c0000);
|
||||
cx24110_pll_write(fe,0x83f1f800);
|
||||
cx24110_pll_write(fe,pll);
|
||||
//writereg(client,0x56,0x7f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pinnsat_tuner_init(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = fe->dvb->priv;
|
||||
|
||||
bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */
|
||||
bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = fe->dvb->priv;
|
||||
|
||||
bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cx24110_config pctvsat_config = {
|
||||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
|
||||
u8 cfg, cpump, band_select;
|
||||
u8 data[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
|
||||
|
||||
div = (36000000 + c->frequency + 83333) / 166666;
|
||||
cfg = 0x88;
|
||||
|
||||
if (c->frequency < 175000000)
|
||||
cpump = 2;
|
||||
else if (c->frequency < 390000000)
|
||||
cpump = 1;
|
||||
else if (c->frequency < 470000000)
|
||||
cpump = 2;
|
||||
else if (c->frequency < 750000000)
|
||||
cpump = 2;
|
||||
else
|
||||
cpump = 3;
|
||||
|
||||
if (c->frequency < 175000000)
|
||||
band_select = 0x0e;
|
||||
else if (c->frequency < 470000000)
|
||||
band_select = 0x05;
|
||||
else
|
||||
band_select = 0x03;
|
||||
|
||||
data[0] = (div >> 8) & 0x7f;
|
||||
data[1] = div & 0xff;
|
||||
data[2] = ((div >> 10) & 0x60) | cfg;
|
||||
data[3] = (cpump << 6) | band_select;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(card->i2c_adapter, &msg, 1);
|
||||
return (div * 166666 - 36000000);
|
||||
}
|
||||
|
||||
static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
|
||||
|
||||
return request_firmware(fw, name, &bt->bt->dev->dev);
|
||||
}
|
||||
|
||||
static struct sp887x_config microtune_mt7202dtf_config = {
|
||||
.demod_address = 0x70,
|
||||
.request_firmware = microtune_mt7202dtf_request_firmware,
|
||||
};
|
||||
|
||||
static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0xFF, 0x00, 0x40, 0x40 };
|
||||
static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
|
||||
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u32 div;
|
||||
unsigned char bs = 0;
|
||||
unsigned char cp = 0;
|
||||
|
||||
if (buf_len < 5) return -EINVAL;
|
||||
|
||||
div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
if (c->frequency < 150000000)
|
||||
cp = 0xB4;
|
||||
else if (c->frequency < 173000000)
|
||||
cp = 0xBC;
|
||||
else if (c->frequency < 250000000)
|
||||
cp = 0xB4;
|
||||
else if (c->frequency < 400000000)
|
||||
cp = 0xBC;
|
||||
else if (c->frequency < 420000000)
|
||||
cp = 0xF4;
|
||||
else if (c->frequency < 470000000)
|
||||
cp = 0xFC;
|
||||
else if (c->frequency < 600000000)
|
||||
cp = 0xBC;
|
||||
else if (c->frequency < 730000000)
|
||||
cp = 0xF4;
|
||||
else
|
||||
cp = 0xFC;
|
||||
|
||||
if (c->frequency < 150000000)
|
||||
bs = 0x01;
|
||||
else if (c->frequency < 173000000)
|
||||
bs = 0x01;
|
||||
else if (c->frequency < 250000000)
|
||||
bs = 0x02;
|
||||
else if (c->frequency < 400000000)
|
||||
bs = 0x02;
|
||||
else if (c->frequency < 420000000)
|
||||
bs = 0x02;
|
||||
else if (c->frequency < 470000000)
|
||||
bs = 0x02;
|
||||
else if (c->frequency < 600000000)
|
||||
bs = 0x08;
|
||||
else if (c->frequency < 730000000)
|
||||
bs = 0x08;
|
||||
else
|
||||
bs = 0x08;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = div >> 8;
|
||||
pllbuf[2] = div & 0xff;
|
||||
pllbuf[3] = cp;
|
||||
pllbuf[4] = bs;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
|
||||
.demod_address = 0x0f,
|
||||
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
|
||||
};
|
||||
|
||||
static struct dst_config dst_config = {
|
||||
.demod_address = 0x55,
|
||||
};
|
||||
|
||||
static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
|
||||
|
||||
return request_firmware(fw, name, &bt->bt->dev->dev);
|
||||
}
|
||||
|
||||
static void or51211_setmode(struct dvb_frontend * fe, int mode)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void or51211_reset(struct dvb_frontend * fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
|
||||
/* RESET DEVICE
|
||||
* reset is controlled by GPIO-0
|
||||
* when set to 0 causes reset and when to 1 for normal op
|
||||
* must remain reset for 128 clock cycles on a 50Mhz clock
|
||||
* also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4
|
||||
* We assume that the reset has be held low long enough or we
|
||||
* have been reset by a power on. When the driver is unloaded
|
||||
* reset set to 0 so if reloaded we have been reset.
|
||||
*/
|
||||
/* reset & PRM1,2&4 are outputs */
|
||||
int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret);
|
||||
bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */
|
||||
msleep(20);
|
||||
/* Now set for normal operation */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
|
||||
/* wait for operation to begin */
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
static void or51211_sleep(struct dvb_frontend * fe)
|
||||
{
|
||||
struct dvb_bt8xx_card *bt = fe->dvb->priv;
|
||||
bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
|
||||
}
|
||||
|
||||
static struct or51211_config or51211_config = {
|
||||
.demod_address = 0x15,
|
||||
.request_firmware = or51211_request_firmware,
|
||||
.setmode = or51211_setmode,
|
||||
.reset = or51211_reset,
|
||||
.sleep = or51211_sleep,
|
||||
};
|
||||
|
||||
static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
|
||||
u8 buf[4];
|
||||
u32 div;
|
||||
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
|
||||
div = (c->frequency + 36166667) / 166667;
|
||||
|
||||
buf[0] = (div >> 8) & 0x7F;
|
||||
buf[1] = div & 0xFF;
|
||||
buf[2] = 0x85;
|
||||
if ((c->frequency >= 47000000) && (c->frequency < 153000000))
|
||||
buf[3] = 0x01;
|
||||
else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
|
||||
buf[3] = 0x02;
|
||||
else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
|
||||
buf[3] = 0x0C;
|
||||
else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
|
||||
buf[3] = 0x8C;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
i2c_transfer(card->i2c_adapter, &msg, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nxt6000_config vp3021_alps_tded4_config = {
|
||||
.demod_address = 0x0a,
|
||||
.clock_inversion = 1,
|
||||
};
|
||||
|
||||
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
|
||||
static u8 mt352_reset [] = { 0x50, 0x80 };
|
||||
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
|
||||
static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
|
||||
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
|
||||
|
||||
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
|
||||
udelay(2000);
|
||||
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
|
||||
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
|
||||
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
|
||||
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
|
||||
{
|
||||
u32 div;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
if (buf_len < 5)
|
||||
return -EINVAL;
|
||||
|
||||
div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
|
||||
|
||||
pllbuf[0] = 0x61;
|
||||
pllbuf[1] = (div >> 8) & 0x7F;
|
||||
pllbuf[2] = div & 0xFF;
|
||||
pllbuf[3] = 0x85;
|
||||
|
||||
dprintk("frequency %u, div %u\n", c->frequency, div);
|
||||
|
||||
if (c->frequency < 470000000)
|
||||
pllbuf[4] = 0x02;
|
||||
else if (c->frequency > 823000000)
|
||||
pllbuf[4] = 0x88;
|
||||
else
|
||||
pllbuf[4] = 0x08;
|
||||
|
||||
if (c->bandwidth_hz == 8000000)
|
||||
pllbuf[4] |= 0x04;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
|
||||
{
|
||||
/*
|
||||
* Reset the frontend, must be called before trying
|
||||
* to initialise the MT352 or mt352_attach
|
||||
* will fail. Same goes for the nxt6000 frontend.
|
||||
*
|
||||
*/
|
||||
|
||||
int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
|
||||
if (ret != 0)
|
||||
printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret);
|
||||
|
||||
/* Pulse the reset line */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */
|
||||
msleep(100);
|
||||
|
||||
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
|
||||
}
|
||||
|
||||
static struct mt352_config digitv_alps_tded4_config = {
|
||||
.demod_address = 0x0a,
|
||||
.demod_init = digitv_alps_tded4_demod_init,
|
||||
};
|
||||
|
||||
static struct lgdt330x_config tdvs_tua6034_config = {
|
||||
.demod_address = 0x0e,
|
||||
.demod_chip = LGDT3303,
|
||||
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
|
||||
};
|
||||
|
||||
static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
|
||||
{
|
||||
/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
|
||||
|
||||
/* Pulse the reset line */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */
|
||||
msleep(100);
|
||||
|
||||
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
|
||||
{
|
||||
struct dst_state* state = NULL;
|
||||
|
||||
switch(type) {
|
||||
case BTTV_BOARD_DVICO_DVBT_LITE:
|
||||
card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
|
||||
|
||||
if (card->fe == NULL)
|
||||
card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
|
||||
card->i2c_adapter);
|
||||
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
|
||||
card->fe->ops.info.frequency_min = 174000000;
|
||||
card->fe->ops.info.frequency_max = 862000000;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
|
||||
lgdt330x_reset(card);
|
||||
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
dvb_attach(simple_tuner_attach, card->fe,
|
||||
card->i2c_adapter, 0x61,
|
||||
TUNER_LG_TDVS_H06XF);
|
||||
dprintk ("dvb_bt8xx: lgdt330x detected\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_NEBULA_DIGITV:
|
||||
/*
|
||||
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
|
||||
* this would be a cleaner solution than trying each frontend in turn.
|
||||
*/
|
||||
|
||||
/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
|
||||
digitv_alps_tded4_reset(card);
|
||||
card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
|
||||
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
|
||||
digitv_alps_tded4_reset(card);
|
||||
card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
|
||||
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
|
||||
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_761:
|
||||
card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter);
|
||||
if (card->fe) {
|
||||
card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_771:
|
||||
card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
|
||||
if (card->fe != NULL) {
|
||||
card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
|
||||
card->fe->ops.info.frequency_min = 174000000;
|
||||
card->fe->ops.info.frequency_max = 862000000;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_TWINHAN_DST:
|
||||
/* DST is not a frontend driver !!! */
|
||||
state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
|
||||
if (!state) {
|
||||
pr_err("No memory\n");
|
||||
break;
|
||||
}
|
||||
/* Setup the Card */
|
||||
state->config = &dst_config;
|
||||
state->i2c = card->i2c_adapter;
|
||||
state->bt = card->bt;
|
||||
state->dst_ca = NULL;
|
||||
/* DST is not a frontend, attaching the ASIC */
|
||||
if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
|
||||
pr_err("%s: Could not find a Twinhan DST\n", __func__);
|
||||
break;
|
||||
}
|
||||
/* Attach other DST peripherals if any */
|
||||
/* Conditional Access device */
|
||||
card->fe = &state->frontend;
|
||||
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
|
||||
dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PINNACLESAT:
|
||||
card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
|
||||
if (card->fe) {
|
||||
card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
|
||||
card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
|
||||
card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PC_HDTV:
|
||||
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
|
||||
if (card->fe != NULL)
|
||||
dvb_attach(simple_tuner_attach, card->fe,
|
||||
card->i2c_adapter, 0x61,
|
||||
TUNER_PHILIPS_FCV1236D);
|
||||
break;
|
||||
}
|
||||
|
||||
if (card->fe == NULL)
|
||||
pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||
card->bt->dev->vendor,
|
||||
card->bt->dev->device,
|
||||
card->bt->dev->subsystem_vendor,
|
||||
card->bt->dev->subsystem_device);
|
||||
else
|
||||
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
|
||||
pr_err("Frontend registration failed!\n");
|
||||
dvb_frontend_detach(card->fe);
|
||||
card->fe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
|
||||
THIS_MODULE, &card->bt->dev->dev,
|
||||
adapter_nr);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_register_adapter failed (errno = %d)\n", result);
|
||||
return result;
|
||||
}
|
||||
card->dvb_adapter.priv = card;
|
||||
|
||||
card->bt->adapter = card->i2c_adapter;
|
||||
|
||||
memset(&card->demux, 0, sizeof(struct dvb_demux));
|
||||
|
||||
card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
|
||||
|
||||
card->demux.priv = card;
|
||||
card->demux.filternum = 256;
|
||||
card->demux.feednum = 256;
|
||||
card->demux.start_feed = dvb_bt8xx_start_feed;
|
||||
card->demux.stop_feed = dvb_bt8xx_stop_feed;
|
||||
card->demux.write_to_decoder = NULL;
|
||||
|
||||
result = dvb_dmx_init(&card->demux);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_dmx_init failed (errno = %d)\n", result);
|
||||
goto err_unregister_adaptor;
|
||||
}
|
||||
|
||||
card->dmxdev.filternum = 256;
|
||||
card->dmxdev.demux = &card->demux.dmx;
|
||||
card->dmxdev.capabilities = 0;
|
||||
|
||||
result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
|
||||
goto err_dmx_release;
|
||||
}
|
||||
|
||||
card->fe_hw.source = DMX_FRONTEND_0;
|
||||
|
||||
result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_dmx_init failed (errno = %d)\n", result);
|
||||
goto err_dmxdev_release;
|
||||
}
|
||||
|
||||
card->fe_mem.source = DMX_MEMORY_FE;
|
||||
|
||||
result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_dmx_init failed (errno = %d)\n", result);
|
||||
goto err_remove_hw_frontend;
|
||||
}
|
||||
|
||||
result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_dmx_init failed (errno = %d)\n", result);
|
||||
goto err_remove_mem_frontend;
|
||||
}
|
||||
|
||||
result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
|
||||
if (result < 0) {
|
||||
pr_err("dvb_net_init failed (errno = %d)\n", result);
|
||||
goto err_disconnect_frontend;
|
||||
}
|
||||
|
||||
tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
|
||||
|
||||
frontend_init(card, type);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disconnect_frontend:
|
||||
card->demux.dmx.disconnect_frontend(&card->demux.dmx);
|
||||
err_remove_mem_frontend:
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
err_remove_hw_frontend:
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
err_dmxdev_release:
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
err_dmx_release:
|
||||
dvb_dmx_release(&card->demux);
|
||||
err_unregister_adaptor:
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
|
||||
{
|
||||
struct dvb_bt8xx_card *card;
|
||||
struct pci_dev* bttv_pci_dev;
|
||||
int ret;
|
||||
|
||||
if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&card->lock);
|
||||
card->bttv_nr = sub->core->nr;
|
||||
strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
|
||||
card->i2c_adapter = &sub->core->i2c_adap;
|
||||
|
||||
switch(sub->core->type) {
|
||||
case BTTV_BOARD_PINNACLESAT:
|
||||
card->gpio_mode = 0x0400c060;
|
||||
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
|
||||
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_DVBT_LITE:
|
||||
card->gpio_mode = 0x0400C060;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* 26, 15, 14, 6, 5
|
||||
* A_PWRDN DA_DPM DA_SBR DA_IOM_DA
|
||||
* DA_APP(parallel) */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
|
||||
card->gpio_mode = 0x0400c060;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_NEBULA_DIGITV:
|
||||
case BTTV_BOARD_AVDVBT_761:
|
||||
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* A_PWRDN DA_SBR DA_APP (high speed serial) */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
|
||||
card->gpio_mode = 0x0400402B;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
/* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_TWINHAN_DST:
|
||||
card->gpio_mode = 0x2204f2c;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
|
||||
BT878_APPERR | BT878_AFBUS;
|
||||
/* 25,21,14,11,10,9,8,3,2 then
|
||||
* 0x33 = 5,4,1,0
|
||||
* A_SEL=SML, DA_MLB, DA_SBR,
|
||||
* DA_SDR=f, fifo trigger = 32 DWORDS
|
||||
* IOM = 0 == audio A/D
|
||||
* DPM = 0 == digital audio mode
|
||||
* == async data parallel port
|
||||
* then 0x33 (13 is set by start_capture)
|
||||
* DA_APP = async data parallel port,
|
||||
* ACAP_EN = 1,
|
||||
* RISC+FIFO ENABLE */
|
||||
break;
|
||||
|
||||
case BTTV_BOARD_PC_HDTV:
|
||||
card->gpio_mode = 0x0100EC7B;
|
||||
card->op_sync_orin = BT878_RISC_SYNC_MASK;
|
||||
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Unknown bttv card type: %d\n", sub->core->type);
|
||||
kfree(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
|
||||
|
||||
if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
|
||||
pr_err("no pci device for card %d\n", card->bttv_nr);
|
||||
kfree(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
|
||||
pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
|
||||
pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
|
||||
|
||||
kfree(card);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_init(&card->bt->gpio_lock);
|
||||
card->bt->bttv_nr = sub->core->nr;
|
||||
|
||||
if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
|
||||
kfree(card);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&sub->dev, card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
|
||||
{
|
||||
struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
|
||||
|
||||
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
|
||||
|
||||
bt878_stop(card->bt);
|
||||
tasklet_kill(&card->bt->tasklet);
|
||||
dvb_net_release(&card->dvbnet);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
|
||||
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
|
||||
dvb_dmxdev_release(&card->dmxdev);
|
||||
dvb_dmx_release(&card->demux);
|
||||
if (card->fe) {
|
||||
dvb_unregister_frontend(card->fe);
|
||||
dvb_frontend_detach(card->fe);
|
||||
}
|
||||
dvb_unregister_adapter(&card->dvb_adapter);
|
||||
|
||||
kfree(card);
|
||||
}
|
||||
|
||||
static struct bttv_sub_driver driver = {
|
||||
.drv = {
|
||||
.name = "dvb-bt8xx",
|
||||
},
|
||||
.probe = dvb_bt8xx_probe,
|
||||
.remove = dvb_bt8xx_remove,
|
||||
/* FIXME:
|
||||
* .shutdown = dvb_bt8xx_shutdown,
|
||||
* .suspend = dvb_bt8xx_suspend,
|
||||
* .resume = dvb_bt8xx_resume,
|
||||
*/
|
||||
};
|
||||
|
||||
static int __init dvb_bt8xx_init(void)
|
||||
{
|
||||
return bttv_sub_register(&driver, "dvb");
|
||||
}
|
||||
|
||||
static void __exit dvb_bt8xx_exit(void)
|
||||
{
|
||||
bttv_sub_unregister(&driver);
|
||||
}
|
||||
|
||||
module_init(dvb_bt8xx_init);
|
||||
module_exit(dvb_bt8xx_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
|
||||
MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
63
drivers/media/pci/bt8xx/dvb-bt8xx.h
Normal file
63
drivers/media/pci/bt8xx/dvb-bt8xx.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Bt8xx based DVB adapter driver
|
||||
*
|
||||
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
|
||||
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
|
||||
* Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH
|
||||
* Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.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 DVB_BT8XX_H
|
||||
#define DVB_BT8XX_H
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_net.h"
|
||||
#include "bttv.h"
|
||||
#include "mt352.h"
|
||||
#include "sp887x.h"
|
||||
#include "dst_common.h"
|
||||
#include "nxt6000.h"
|
||||
#include "cx24110.h"
|
||||
#include "or51211.h"
|
||||
#include "lgdt330x.h"
|
||||
#include "zl10353.h"
|
||||
#include "tuner-simple.h"
|
||||
|
||||
struct dvb_bt8xx_card {
|
||||
struct mutex lock;
|
||||
int nfeeds;
|
||||
char card_name[32];
|
||||
struct dvb_adapter dvb_adapter;
|
||||
struct bt878 *bt;
|
||||
unsigned int bttv_nr;
|
||||
struct dvb_demux demux;
|
||||
struct dmxdev dmxdev;
|
||||
struct dmx_frontend fe_hw;
|
||||
struct dmx_frontend fe_mem;
|
||||
u32 gpio_mode;
|
||||
u32 op_sync_orin;
|
||||
u32 irq_err_ignore;
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
struct dvb_net dvbnet;
|
||||
|
||||
struct dvb_frontend* fe;
|
||||
};
|
||||
|
||||
#endif /* DVB_BT8XX_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue