From 43e9d4ab0c14ccff3ed27f8e43274571e286f0ed Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Aug 2014 12:19:13 -0300 Subject: [media] cx23885: Spelling s/compuations/computations/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23888-ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 2c951dec2d33..c2ff5fc01157 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -263,7 +263,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { -- cgit v1.2.3 From c8fa50549dc6e717e0941ee7092a973388253c7a Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Sun, 10 Aug 2014 17:30:18 -0300 Subject: [media] drivers: media: pci: Makefile: Remove duplicate subdirectory from obj-y In the list of subdirectories compiled, b2c2/ appears twice. This patch removes one of the appearances. Signed-off-by: Andreas Ruprecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index e5b53fb569ef..dc2ebbe27306 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -10,7 +10,6 @@ obj-y += ttpci/ \ mantis/ \ ngene/ \ ddbridge/ \ - b2c2/ \ saa7146/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -- cgit v1.2.3 From b250392f7b5062cf026b1423e27265e278fd6b30 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Aug 2014 21:15:53 -0300 Subject: [media] media: ttpci: fix av7110 build to be compatible with CONFIG_INPUT_EVDEV Fix build when CONFIG_INPUT_EVDEV=m and DVB_AV7110=y. Only build av7110_ir.c when CONFIG_INPUT_EVDEV is compatible with CONFIG_DVB_AV7110. Fixes these build errors: drivers/built-in.o: In function `input_sync': av7110_ir.c:(.text+0x1223ac): undefined reference to `input_event' drivers/built-in.o: In function `av7110_emit_key': av7110_ir.c:(.text+0x12247c): undefined reference to `input_event' av7110_ir.c:(.text+0x122495): undefined reference to `input_event' av7110_ir.c:(.text+0x122569): undefined reference to `input_event' av7110_ir.c:(.text+0x1225a7): undefined reference to `input_event' drivers/built-in.o:av7110_ir.c:(.text+0x122629): more undefined references to `input_event' follow drivers/built-in.o: In function `av7110_ir_init': (.text+0x1227e4): undefined reference to `input_allocate_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12298f): undefined reference to `input_register_device' drivers/built-in.o: In function `av7110_ir_init': (.text+0x12299e): undefined reference to `input_free_device' drivers/built-in.o: In function `av7110_ir_exit': (.text+0x122a94): undefined reference to `input_unregister_device' drivers/built-in.o: In function `av7110_detach': av7110.c:(.text+0x228d4a): undefined reference to `av7110_ir_exit' drivers/built-in.o: In function `arm_thread': av7110.c:(.text+0x22a404): undefined reference to `av7110_check_ir_config' av7110.c:(.text+0x22a626): undefined reference to `av7110_check_ir_config' drivers/built-in.o: In function `av7110_attach': av7110.c:(.text+0x22b08c): undefined reference to `av7110_ir_init' Signed-off-by: Randy Dunlap Reported-by: Randy Dunlap Reported-by: Jim Davis Reported-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/Kconfig | 4 ++++ drivers/media/pci/ttpci/Makefile | 2 +- drivers/media/pci/ttpci/av7110.c | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index 0dcb8cd77676..7b83151ed6c4 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,8 +1,12 @@ +config DVB_AV7110_IR + bool + config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV + select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index 98905963ff08..49f71b1eaf14 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile @@ -5,7 +5,7 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o -ifdef CONFIG_INPUT_EVDEV +ifdef CONFIG_DVB_AV7110_IR dvb-ttpci-objs += av7110_ir.o endif diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f38329d29daa..c1f0617a6973 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110) restart_feeds(av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, true); #endif } @@ -268,7 +268,7 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_check_ir_config(av7110, false); #endif @@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->ioctl_mutex); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_init(av7110); #endif printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); @@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa) struct av7110 *av7110 = saa->ext_priv; dprintk(4, "%p\n", av7110); -#if IS_ENABLED(CONFIG_INPUT_EVDEV) +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) av7110_ir_exit(av7110); #endif if (budgetpatch || av7110->full_ts) { -- cgit v1.2.3 From 12bd88e62cf7c1557c7cd78f42a76d7c716b2283 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Aug 2014 16:45:39 -0300 Subject: [media] be sure that HAS_DMA is enabled for vb2-dma-contig vb2-dma-contig depends on HAS_DMA, but the Kbuild doesn't take it into account at select. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/Kconfig | 1 + drivers/media/pci/sta2x11/Kconfig | 1 + drivers/media/platform/Kconfig | 12 ++++++++++++ drivers/media/platform/blackfin/Kconfig | 1 + drivers/media/platform/davinci/Kconfig | 6 ++++++ drivers/media/platform/exynos4-is/Kconfig | 3 +++ drivers/media/platform/marvell-ccic/Kconfig | 2 ++ drivers/media/platform/s5p-tv/Kconfig | 1 + drivers/media/platform/soc_camera/Kconfig | 6 ++++++ drivers/staging/media/davinci_vpfe/Kconfig | 1 + drivers/staging/media/dt3155v4l/Kconfig | 1 + drivers/staging/media/omap4iss/Kconfig | 1 + 12 files changed, 36 insertions(+) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig index d9e06a6bf1eb..0fb91dc7ca73 100644 --- a/drivers/media/pci/solo6x10/Kconfig +++ b/drivers/media/pci/solo6x10/Kconfig @@ -1,6 +1,7 @@ config VIDEO_SOLO6X10 tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)" depends on PCI && VIDEO_DEV && SND && I2C + depends on HAS_DMA select BITREVERSE select FONT_SUPPORT select FONT_8x16 diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 03130157db83..f6f30abc088b 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,6 +1,7 @@ config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" depends on STA2X11 + depends on HAS_DMA select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a8ae457f8a02..ae021faf7a42 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -96,6 +96,7 @@ config VIDEO_M32R_AR_M64278 config VIDEO_OMAP3 tristate "OMAP 3 Camera support" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 + depends on HAS_DMA select ARM_DMA_USE_IOMMU select OMAP_IOMMU select VIDEOBUF2_DMA_CONTIG @@ -113,6 +114,7 @@ config VIDEO_S3C_CAMIF depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on PM_RUNTIME depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -143,6 +145,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_CODA tristate "Chips&Media Coda multi-standard codec IP" depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC + depends on HAS_DMA select SRAM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV @@ -154,6 +157,7 @@ config VIDEO_CODA config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -163,6 +167,7 @@ config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n @@ -174,6 +179,7 @@ config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- @@ -184,6 +190,7 @@ config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n help @@ -193,6 +200,7 @@ config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -204,6 +212,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_EXYNOS5 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -212,6 +221,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -221,6 +231,7 @@ config VIDEO_SH_VEU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a V4L2 driver for the Renesas VSP1 video processing engine. @@ -232,6 +243,7 @@ config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on SOC_DRA7XX || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig index cc239972fa2c..68fa90151b8f 100644 --- a/drivers/media/platform/blackfin/Kconfig +++ b/drivers/media/platform/blackfin/Kconfig @@ -1,6 +1,7 @@ config VIDEO_BLACKFIN_CAPTURE tristate "Blackfin Video Capture Driver" depends on VIDEO_V4L2 && BLACKFIN && I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help V4L2 bridge driver for Blackfin video capture device. diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 35809278e349..b04016e8532d 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -2,6 +2,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -17,6 +18,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -30,6 +32,7 @@ config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || ARCH_OMAP3 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -45,6 +48,7 @@ config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces @@ -59,6 +63,7 @@ config VIDEO_DM355_CCDC config VIDEO_DM365_ISIF tristate "TI DM365 ISIF video capture driver" depends on VIDEO_V4L2 && ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG help Enables ISIF hw module. This is the hardware module for @@ -71,6 +76,7 @@ config VIDEO_DM365_ISIF config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on ARCH_DAVINCI + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPBE module used for display devices. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 811872195f36..77c951237744 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -16,6 +16,7 @@ config VIDEO_EXYNOS4_IS_COMMON config VIDEO_S5P_FIMC tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select MFD_SYSCON @@ -43,6 +44,7 @@ if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 config VIDEO_EXYNOS_FIMC_LITE tristate "EXYNOS FIMC-LITE camera interface driver" depends on I2C + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select VIDEO_EXYNOS4_IS_COMMON help @@ -55,6 +57,7 @@ endif config VIDEO_EXYNOS4_FIMC_IS tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG depends on OF select FW_LOADER diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index bf739e3b3398..6265d36adceb 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on PCI && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -12,6 +13,7 @@ config VIDEO_CAFE_CCIC config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on ARCH_MMP && I2C && VIDEO_V4L2 + depends on HAS_DMA select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/s5p-tv/Kconfig b/drivers/media/platform/s5p-tv/Kconfig index 9f38b3dbe0a8..a9d56f8936b4 100644 --- a/drivers/media/platform/s5p-tv/Kconfig +++ b/drivers/media/platform/s5p-tv/Kconfig @@ -71,6 +71,7 @@ config VIDEO_SAMSUNG_S5P_MIXER tristate "Samsung Mixer and Video Processor Driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on VIDEO_SAMSUNG_S5P_TV + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Say Y here if you want support for the Mixer in Samsung S5P SoCs. diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index c0d4c0f822ea..6af6c6dccda8 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -21,6 +21,7 @@ config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA depends on MX3_IPU || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface @@ -36,6 +37,7 @@ config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_SHMOBILE || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -52,6 +54,7 @@ config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select SOC_CAMERA_SCALE_CROP ---help--- @@ -61,6 +64,7 @@ config VIDEO_OMAP1 tristate "OMAP1 Camera Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_OMAP1 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF_DMA_CONTIG select VIDEOBUF_DMA_SG ---help--- @@ -70,6 +74,7 @@ config VIDEO_MX2 tristate "i.MX27 Camera Sensor Interface driver" depends on VIDEO_DEV && SOC_CAMERA depends on SOC_IMX27 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the i.MX27 Camera Sensor Interface @@ -78,6 +83,7 @@ config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_AT91 || COMPILE_TEST + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig index 12f321dd2399..4de2f082491d 100644 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ b/drivers/staging/media/davinci_vpfe/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DM365_VPFE tristate "DM365 VPFE Media Controller Capture Driver" depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG help Support for DM365 VPFE based Media Controller Capture driver. diff --git a/drivers/staging/media/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig index 226a1ca90b3c..2d496001b6e8 100644 --- a/drivers/staging/media/dt3155v4l/Kconfig +++ b/drivers/staging/media/dt3155v4l/Kconfig @@ -1,6 +1,7 @@ config VIDEO_DT3155 tristate "DT3155 frame grabber, Video4Linux interface" depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG default n ---help--- diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 8afc6fee40c5..b78643f907e7 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,6 +1,7 @@ config VIDEO_OMAP4 bool "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 + depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG ---help--- Driver for an OMAP 4 ISS controller. -- cgit v1.2.3 From a7d3eabd77402828a5d5a84604626cb824571e0b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 04:50:14 -0300 Subject: [media] cx23885: fix querycap Set device_caps to fix the v4l2-compliance QUERYCAP complaints. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 91e4cb457296..2666ac415ec2 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1146,19 +1146,22 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; + cap->device_caps |= V4L2_CAP_TUNER; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From d43be757b945b292402edc28aa67cf53581d3428 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 05:24:58 -0300 Subject: [media] cx23885: fix audio input handling Fix a bunch of v4l2-compliance errors relating to audio input handling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2666ac415ec2..79de4acbf533 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1153,7 +1153,7 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; if (vdev->vfl_type == VFL_TYPE_VBI) @@ -1302,16 +1302,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); + i->std = CX23885_NORMS; if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || (CX23885_VMUX_CABLE == INPUT(n)->type)) { i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX23885_NORMS; + i->audioset = 4; + } else { + /* Two selectable audio inputs for non-tv inputs */ + i->audioset = 3; } - /* Two selectable audio inputs for non-tv inputs */ - if (INPUT(n)->type != CX23885_VMUX_TELEVISION) - i->audioset = 0x3; - if (dev->input == n) { /* enum'd input matches our configured input. * Ask the video decoder to process the call @@ -1397,19 +1397,19 @@ static int cx23885_query_audinput(struct file *file, void *priv, static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", + [2] = "TV", }; unsigned int n; dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 2) + if (n >= 3) return -EINVAL; memset(i, 0, sizeof(*i)); i->index = n; strcpy(i->name, iname[n]); - i->capability = V4L2_AUDCAP_STEREO; - i->mode = V4L2_AUDMODE_AVL; + i->capability = V4L2_AUDCAP_STEREO; return 0; } @@ -1425,7 +1425,11 @@ static int vidioc_g_audinput(struct file *file, void *priv, { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - i->index = dev->audinput; + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) + i->index = 2; + else + i->index = dev->audinput; dprintk(1, "%s(input=%d)\n", __func__, i->index); return cx23885_query_audinput(file, priv, i); @@ -1435,7 +1439,12 @@ static int vidioc_s_audinput(struct file *file, void *priv, const struct v4l2_audio *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - if (i->index >= 2) + + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) { + return i->index != 2 ? -EINVAL : 0; + } + if (i->index > 1) return -EINVAL; dprintk(1, "%s(%d)\n", __func__, i->index); -- cgit v1.2.3 From 86dd9831aea494e3e5c565c697df60484f55780c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 05:32:58 -0300 Subject: [media] cx23885: support v4l2_fh and g/s_priority Add support for struct v4l2_fh and priority handling. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 5 +++++ drivers/media/pci/cx23885/cx23885-video.c | 6 +++++- drivers/media/pci/cx23885/cx23885.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index bf89fc88692e..b65de33a6e23 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1550,6 +1550,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int mpeg_open(struct file *file) { + struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; @@ -1560,6 +1561,7 @@ static int mpeg_open(struct file *file) if (!fh) return -ENOMEM; + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; @@ -1569,6 +1571,7 @@ static int mpeg_open(struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct cx23885_buffer), fh, NULL); + v4l2_fh_add(&fh->fh); return 0; } @@ -1601,6 +1604,8 @@ static int mpeg_release(struct file *file) videobuf_read_stop(&fh->mpegq); videobuf_mmap_free(&fh->mpegq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 79de4acbf533..d575bfc8ac41 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -883,7 +883,8 @@ static int video_open(struct file *file) if (NULL == fh) return -ENOMEM; - file->private_data = fh; + v4l2_fh_init(&fh->fh, vdev); + file->private_data = &fh->fh; fh->dev = dev; fh->radio = radio; fh->type = type; @@ -905,6 +906,7 @@ static int video_open(struct file *file) sizeof(struct cx23885_buffer), fh, NULL); + v4l2_fh_add(&fh->fh); dprintk(1, "post videobuf_queue_init()\n"); @@ -1003,6 +1005,8 @@ static int video_release(struct file *file) videobuf_mmap_free(&fh->vidq); videobuf_mmap_free(&fh->vbiq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0e086c03da67..de164c986b1d 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -147,6 +148,7 @@ struct cx23885_tvnorm { }; struct cx23885_fh { + struct v4l2_fh fh; struct cx23885_dev *dev; enum v4l2_buf_type type; int radio; -- cgit v1.2.3 From 24a8f7b5648ff8dfd8d26f8444ab4b04286dba98 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 11:29:55 -0300 Subject: [media] cx23885: use core locking, switch to unlocked_ioctl Enable core locking which allows us to safely switch to unlocked_ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 5 ++-- drivers/media/pci/cx23885/cx23885-video.c | 43 +++++++------------------------ 2 files changed, 12 insertions(+), 36 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index b65de33a6e23..395f7a987d61 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1235,9 +1235,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) dev->encodernorm = cx23885_tvnorms[i]; /* Have the drier core notify the subdevices */ - mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, id); - mutex_unlock(&dev->lock); return 0; } @@ -1661,7 +1659,7 @@ static struct v4l2_file_operations mpeg_fops = { .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { @@ -1770,6 +1768,7 @@ int cx23885_417_register(struct cx23885_dev *dev) dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); video_set_drvdata(dev->v4l_device, dev); + dev->v4l_device->lock = &dev->lock; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index d575bfc8ac41..ba93e29bf158 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -345,6 +345,7 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; + vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); @@ -381,17 +382,14 @@ static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, return 1; /* is it free? */ - mutex_lock(&dev->lock); if (dev->resources & bit) { /* no, someone else uses it */ - mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); return 1; } @@ -411,11 +409,9 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, BUG_ON((fh->resources & bits) != bits); dprintk(1, "%s()\n", __func__); - mutex_lock(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); } int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) @@ -1272,9 +1268,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; dprintk(1, "%s()\n", __func__); - mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, tvnorms); - mutex_unlock(&dev->lock); return 0; } @@ -1364,13 +1358,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i) if (INPUT(i)->type == 0) return -EINVAL; - mutex_lock(&dev->lock); cx23885_video_mux(dev, i); /* By default establish the default audio input for the card also */ /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ cx23885_audio_mux(dev, i); - mutex_unlock(&dev->lock); return 0; } @@ -1544,7 +1536,6 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ @@ -1561,8 +1552,6 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency ctrl.value = 0; cx23885_set_control(dev, &ctrl); - mutex_unlock(&dev->lock); - return 0; } @@ -1580,7 +1569,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, .frequency = f->frequency }; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ @@ -1594,7 +1582,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { - mutex_unlock(&dev->lock); return -EINVAL; } @@ -1619,8 +1606,6 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, ctrl.value = 0; cx23885_set_control(dev, &ctrl); - mutex_unlock(&dev->lock); - return 0; } @@ -1742,7 +1727,7 @@ static const struct v4l2_file_operations video_fops = { .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1791,14 +1776,6 @@ static struct video_device cx23885_video_template = { .tvnorms = CX23885_NORMS, }; -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, -}; - - void cx23885_video_unregister(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); @@ -1909,6 +1886,14 @@ int cx23885_video_register(struct cx23885_dev *dev) } } + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + init_controls(dev); + cx23885_video_mux(dev, 0); + cx23885_audio_mux(dev, 0); + mutex_unlock(&dev->lock); + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); @@ -1938,14 +1923,6 @@ int cx23885_video_register(struct cx23885_dev *dev) /* Register ALSA audio device */ dev->audio_dev = cx23885_audio_register(dev); - /* initial device configuration */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); - cx23885_video_mux(dev, 0); - cx23885_audio_mux(dev, 0); - mutex_unlock(&dev->lock); - return 0; fail_unreg: -- cgit v1.2.3 From da59a4deb2e2430aac82e775bb2b0a67cbb48f11 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 06:34:44 -0300 Subject: [media] cx23885: convert to the control framework This is part 1, converting the uncompressed video/vbi nodes to use the control framework. The next patch converts the compressed video node as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 20 --- drivers/media/pci/cx23885/cx23885-core.c | 17 ++- drivers/media/pci/cx23885/cx23885-video.c | 246 +++++------------------------- drivers/media/pci/cx23885/cx23885.h | 12 +- 4 files changed, 51 insertions(+), 244 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 395f7a987d61..d44395ca3b77 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1313,22 +1313,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, return cx23885_set_frequency(file, priv, f); } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1672,8 +1656,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1689,8 +1671,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_log_status = vidioc_log_status, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_queryctrl = vidioc_queryctrl, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, .vidioc_g_register = cx23885_g_register, diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index edcd79db1e4e..075b28eda8de 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2087,6 +2087,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct cx23885_dev *dev; + struct v4l2_ctrl_handler *hdl; int err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -2097,6 +2098,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev, if (err < 0) goto fail_free; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 6); + if (hdl->error) { + err = hdl->error; + goto fail_ctrl; + } + dev->v4l2_dev.ctrl_handler = hdl; + /* Prepare to handle notifications from subdevices */ cx23885_v4l2_dev_notify_init(dev); @@ -2104,12 +2113,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev, dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { err = -EIO; - goto fail_unreg; + goto fail_ctrl; } if (cx23885_dev_setup(dev) < 0) { err = -EINVAL; - goto fail_unreg; + goto fail_ctrl; } /* print pci info */ @@ -2157,7 +2166,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev, fail_irq: cx23885_dev_unregister(dev); -fail_unreg: +fail_ctrl: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); fail_free: kfree(dev); @@ -2180,6 +2190,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev) free_irq(pci_dev->irq, dev); cx23885_dev_unregister(dev); + v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(v4l2_dev); kfree(dev); } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index ba93e29bf158..090d48b427fd 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -35,6 +35,7 @@ #include "cx23885-video.h" #include #include +#include #include "cx23885-ioctl.h" #include "tuner-xc2028.h" @@ -170,119 +171,6 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) /* ------------------------------------------------------------------- */ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx23885_ctrl cx23885_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = -127, - .maximum = 128, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535 / 100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); - -/* Must be sorted from low to high control ID! */ -static const u32 cx23885_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx23885_user_ctrls, - NULL -}; - void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { @@ -352,24 +240,6 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == qctrl->id) - break; - if (i == CX23885_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx23885_ctls[i].v; - return 0; -} - /* ------------------------------------------------------------------- */ /* resource management */ @@ -936,12 +806,20 @@ static unsigned int video_poll(struct file *file, { struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; - unsigned int rc = POLLERR; + unsigned long req_events = poll_requested_events(wait); + unsigned int rc = 0; + + if (v4l2_event_pending(&fh->fh)) + rc = POLLPRI; + else + poll_wait(file, &fh->fh.wait, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return rc; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); + return rc | POLLERR; + return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } mutex_lock(&fh->vidq.vb_lock); @@ -960,9 +838,7 @@ static unsigned int video_poll(struct file *file, poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; + rc |= POLLIN | POLLRDNORM; done: mutex_unlock(&fh->vidq.vb_lock); return rc; @@ -1021,39 +897,6 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) return videobuf_mmap_mapper(get_queue(fh), vma); } -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -int cx23885_get_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); - call_all(dev, core, g_ctrl, ctl); - return 0; -} - -int cx23885_set_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); - call_all(dev, core, s_ctrl, ctl); - - return 0; -} - -static void init_controls(struct cx23885_dev *dev) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX23885_CTLS; i++) { - ctrl.id = cx23885_ctls[i].v.id; - ctrl.value = cx23885_ctls[i].v.default_value; - - cx23885_set_control(dev, &ctrl); - } -} - /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -1453,31 +1296,6 @@ static int vidioc_s_audinput(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx23885_ctrl_query(qctrl); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1529,7 +1347,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; + struct v4l2_ctrl *mute; + int old_mute_val = 1; if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1539,9 +1358,12 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } call_all(dev, tuner, s_frequency, f); @@ -1549,8 +1371,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1558,7 +1380,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; + struct v4l2_ctrl *mute; + int old_mute_val = 1; struct videobuf_dvb_frontend *vfe; struct dvb_frontend *fe; @@ -1572,9 +1395,12 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } /* If HVR1850 */ dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, @@ -1603,8 +1429,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1749,9 +1575,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, @@ -1766,6 +1589,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enumaudio = vidioc_enum_audinput, .vidioc_g_audio = vidioc_g_audinput, .vidioc_s_audio = vidioc_s_audinput, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx23885_vbi_template; @@ -1889,7 +1714,6 @@ int cx23885_video_register(struct cx23885_dev *dev) /* initial device configuration */ mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); cx23885_video_mux(dev, 0); cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index de164c986b1d..516435c021e4 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -132,14 +133,6 @@ struct cx23885_fmt { u32 cxformat; }; -struct cx23885_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - struct cx23885_tvnorm { char *name; v4l2_std_id id; @@ -370,6 +363,7 @@ struct cx23885_audio_dev { struct cx23885_dev { atomic_t refcount; struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; /* pci stuff */ struct pci_dev *pci; @@ -597,8 +591,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); int cx23885_set_input(struct file *file, void *priv, unsigned int i); int cx23885_get_input(struct file *file, void *priv, unsigned int *i); int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f); -int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); -int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); /* ----------------------------------------------------------- */ -- cgit v1.2.3 From 5150392cd94c5a5a89b92e58ddc579f0de2d1a89 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:02:15 -0300 Subject: [media] cx23885: convert 417 to the control framework Convert the -417 source to the control framework as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 133 +++++------------------------- drivers/media/pci/cx23885/cx23885-video.c | 6 -- drivers/media/pci/cx23885/cx23885.h | 2 +- 3 files changed, 20 insertions(+), 121 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index d44395ca3b77..4142c15b259e 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -865,6 +865,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev, return err; } +static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + return cx23885_mbox_func(priv, cmd, in, out, data); +} + static int cx23885_find_mailbox(struct cx23885_dev *dev) { u32 signature[4] = { @@ -1033,12 +1038,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); - dev->mpeg_params.width = dev->ts1.width; - dev->mpeg_params.height = dev->ts1.height; - dev->mpeg_params.is_50hz = + dev->cxhdl.width = dev->ts1.width; + dev->cxhdl.height = dev->ts1.height; + dev->cxhdl.is_50hz = (dev->encodernorm.id & V4L2_STD_625_50) != 0; - cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); + cx2341x_handler_setup(&dev->cxhdl); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); @@ -1182,36 +1187,6 @@ static struct videobuf_queue_ops cx23885_qops = { /* ------------------------------------------------------------------ */ -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; - -static int cx23885_queryctrl(struct cx23885_dev *dev, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - - return 0; -} - -static int cx23885_querymenu(struct cx23885_dev *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx23885_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); -} - static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_fh *fh = file->private_data; @@ -1445,55 +1420,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->mpegq); } -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - - if (err == 0) { - err = cx2341x_update(dev, cx23885_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - return err; -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_fh *fh = priv; @@ -1501,35 +1427,11 @@ static int vidioc_log_status(struct file *file, void *priv) char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); - printk(KERN_INFO - "%s/2: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - printk(KERN_INFO - "%s/2: ============= END LOG STATUS =============\n", - dev->name); + v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); return 0; } -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_queryctrl(dev, c); -} - static int mpeg_open(struct file *file) { struct video_device *vdev = video_devdata(file); @@ -1667,9 +1569,6 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_log_status = vidioc_log_status, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, @@ -1694,6 +1593,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev) video_unregister_device(dev->v4l_device); else video_device_release(dev->v4l_device); + v4l2_ctrl_handler_free(&dev->cxhdl.hdl); dev->v4l_device = NULL; } } @@ -1740,9 +1640,14 @@ int cx23885_417_register(struct cx23885_dev *dev) tsport->height = 576; tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); - - dev->mpeg_params.port = CX2341X_PORT_SERIAL; + dev->cxhdl.port = CX2341X_PORT_SERIAL; + err = cx2341x_handler_init(&dev->cxhdl, 50); + if (err) + return err; + dev->cxhdl.priv = dev; + dev->cxhdl.func = cx23885_api_func; + cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576); + v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL); /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 090d48b427fd..116ce34c5168 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1219,13 +1219,7 @@ static int vidioc_log_status(struct file *file, void *priv) struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; - printk(KERN_INFO - "%s/0: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - printk(KERN_INFO - "%s/0: ============= END LOG STATUS =============\n", - dev->name); return 0; } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 516435c021e4..2d57af74b692 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -439,7 +439,7 @@ struct cx23885_dev { /* MPEG Encoder ONLY settings */ u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; + struct cx2341x_handler cxhdl; struct video_device *v4l_device; atomic_t v4l_reader_count; struct cx23885_tvnorm encodernorm; -- cgit v1.2.3 From 1af2ddd8b3fab054c908d24e00cb41f6b2b7d719 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:11:49 -0300 Subject: [media] cx23885: fix format colorspace compliance error Fix v4l2-compliance failure relating to formatting. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 116ce34c5168..ad02912e9ac3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -913,6 +913,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fh->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -957,6 +958,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } -- cgit v1.2.3 From 200e0841ee4a05d06041fb25a8931a5dfb15c767 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:18:12 -0300 Subject: [media] cx23885: map invalid fields to a valid field If field format is not valid, map it as V4L2_FIELD_INTERLACED, instead of pretending to support an invalid format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index ad02912e9ac3..9bb19fdfac02 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -948,7 +948,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, case V4L2_FIELD_INTERLACED: break; default: - return -EINVAL; + field = V4L2_FIELD_INTERLACED; + break; } f->fmt.pix.field = field; -- cgit v1.2.3 From 8696193320118ba55e6469f49b33b4526c5cd5fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:22:06 -0300 Subject: [media] cx23885: drop radio-related dead code Currently no radio device nodes are ever created, so remove the dead radio code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 15 +++------------ drivers/media/pci/cx23885/cx23885.h | 3 --- 2 files changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 9bb19fdfac02..50694c6f13d3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -49,15 +49,12 @@ MODULE_LICENSE("GPL"); static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug; module_param(video_debug, int, 0644); @@ -727,7 +724,6 @@ static int video_open(struct file *file) struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; enum v4l2_buf_type type = 0; - int radio = 0; switch (vdev->vfl_type) { case VFL_TYPE_GRABBER: @@ -736,13 +732,10 @@ static int video_open(struct file *file) case VFL_TYPE_VBI: type = V4L2_BUF_TYPE_VBI_CAPTURE; break; - case VFL_TYPE_RADIO: - radio = 1; - break; } - dprintk(1, "open dev=%s radio=%d type=%s\n", - video_device_node_name(vdev), radio, v4l2_type_names[type]); + dprintk(1, "open dev=%s type=%s\n", + video_device_node_name(vdev), v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -752,7 +745,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->radio = radio; fh->type = type; fh->width = 320; fh->height = 240; @@ -1333,8 +1325,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->type = V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; call_all(dev, tuner, g_frequency, f); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 2d57af74b692..94ab000ca16b 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -144,7 +144,6 @@ struct cx23885_fh { struct v4l2_fh fh; struct cx23885_dev *dev; enum v4l2_buf_type type; - int radio; u32 resources; /* video overlay */ @@ -413,7 +412,6 @@ struct cx23885_dev { unsigned int tuner_bus; unsigned int radio_type; unsigned char radio_addr; - unsigned int has_radio; struct v4l2_subdev *sd_cx25840; struct work_struct cx25840_work; @@ -431,7 +429,6 @@ struct cx23885_dev { u32 freq; struct video_device *video_dev; struct video_device *vbi_dev; - struct video_device *radio_dev; struct cx23885_dmaqueue vidq; struct cx23885_dmaqueue vbiq; -- cgit v1.2.3 From 1f159c77d068aff4c8ee7f7c84312b64ebef121c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:35:54 -0300 Subject: [media] cx23885: drop type field from struct cx23885_fh This information is available elsewhere as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 89 ++++++++++++++----------------- drivers/media/pci/cx23885/cx23885.h | 1 - 2 files changed, 40 insertions(+), 50 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 50694c6f13d3..a68ab59b39f7 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -692,28 +692,31 @@ static struct videobuf_queue_ops cx23885_video_qops = { .buf_release = buffer_release, }; -static struct videobuf_queue *get_queue(struct cx23885_fh *fh) +static struct videobuf_queue *get_queue(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + struct cx23885_fh *fh = file->private_data; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return &fh->vbiq; default: - BUG(); + WARN_ON(1); return NULL; } } -static int get_resource(struct cx23885_fh *fh) +static int get_resource(u32 type) { - switch (fh->type) { + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: return RESOURCE_VIDEO; case V4L2_BUF_TYPE_VBI_CAPTURE: return RESOURCE_VBI; default: - BUG(); + WARN_ON(1); return 0; } } @@ -723,19 +726,9 @@ static int video_open(struct file *file) struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; - enum v4l2_buf_type type = 0; - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - } - - dprintk(1, "open dev=%s type=%s\n", - video_device_node_name(vdev), v4l2_type_names[type]); + dprintk(1, "open dev=%s\n", + video_device_node_name(vdev)); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -745,7 +738,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->type = type; fh->width = 320; fh->height = 240; fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); @@ -774,28 +766,29 @@ static int video_open(struct file *file) static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = file->private_data; - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: if (res_locked(fh->dev, RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: if (!res_get(fh->dev, fh, RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, file->f_flags & O_NONBLOCK); default: - BUG(); - return 0; + return -EINVAL; } } static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; unsigned long req_events = poll_requested_events(wait); @@ -808,7 +801,7 @@ static unsigned int video_poll(struct file *file, if (!(req_events & (POLLIN | POLLRDNORM))) return rc; - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (vdev->vfl_type == VFL_TYPE_VBI) { if (!res_get(fh->dev, fh, RESOURCE_VBI)) return rc | POLLERR; return rc | videobuf_poll_stream(file, &fh->vbiq, wait); @@ -884,9 +877,7 @@ static int video_release(struct file *file) static int video_mmap(struct file *file, struct vm_area_struct *vma) { - struct cx23885_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); + return videobuf_mmap_mapper(get_queue(file), vma); } /* ------------------------------------------------------------------ */ @@ -1019,73 +1010,73 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct cx23885_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); + return videobuf_reqbufs(get_queue(file), p); } static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); + return videobuf_querybuf(get_queue(file), p); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); + return videobuf_qbuf(get_queue(file), p); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx23885_fh *fh = priv; - return videobuf_dqbuf(get_queue(fh), p, + return videobuf_dqbuf(get_queue(file), p, file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + if (vdev->vfl_type == VFL_TYPE_VBI && + i != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; - if (unlikely(i != fh->type)) + if (vdev->vfl_type == VFL_TYPE_GRABBER && + i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (unlikely(!res_get(dev, fh, get_resource(fh)))) + if (unlikely(!res_get(dev, fh, get_resource(i)))) return -EBUSY; /* Don't start VBI streaming unless vida streaming * has already started. */ - if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && + if ((i == V4L2_BUF_TYPE_VBI_CAPTURE) && ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) return -EINVAL; - return videobuf_streamon(get_queue(fh)); + return videobuf_streamon(get_queue(file)); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; int err, res; dprintk(1, "%s()\n", __func__); - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) + if (vdev->vfl_type == VFL_TYPE_VBI && + i != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; - if (i != fh->type) + if (vdev->vfl_type == VFL_TYPE_GRABBER && + i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - res = get_resource(fh); - err = videobuf_streamoff(get_queue(fh)); + res = get_resource(i); + err = videobuf_streamoff(get_queue(file)); if (err < 0) return err; res_free(dev, fh, res); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 94ab000ca16b..aba1e6af41d6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -143,7 +143,6 @@ struct cx23885_tvnorm { struct cx23885_fh { struct v4l2_fh fh; struct cx23885_dev *dev; - enum v4l2_buf_type type; u32 resources; /* video overlay */ -- cgit v1.2.3 From e749c6e64c6a8b1323fad2330d73855cf072a3b9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:37:35 -0300 Subject: [media] cx23885: drop unused clip fields from struct cx23885_fh There is no overlay support, so drop these unused fields. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index aba1e6af41d6..a88e951a91b8 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -145,11 +145,6 @@ struct cx23885_fh { struct cx23885_dev *dev; u32 resources; - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - /* video capture */ struct cx23885_fmt *fmt; unsigned int width, height; -- cgit v1.2.3 From 91d2d6745205774b712727ede2a35c91e1eb4c48 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 07:52:07 -0300 Subject: [media] cx23885: fmt, width and height are global, not per-fh Move these fields from cx23885_fh to cx23885_dev. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 125 +++++++----------------------- drivers/media/pci/cx23885/cx23885.h | 8 +- 2 files changed, 34 insertions(+), 99 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index a68ab59b39f7..3dcee0a01787 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -77,77 +77,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); /* static data */ #define FORMAT_FLAGS_PACKED 0x01 -#if 0 static struct cx23885_fmt formats[] = { { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, -}; -#else -static struct cx23885_fmt formats[] = { - { -#if 0 - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { -#endif .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, } }; -#endif static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) { @@ -156,13 +93,6 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) return formats+i; - - printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, - (fourcc & 0xff), - ((fourcc >> 8) & 0xff), - ((fourcc >> 16) & 0xff), - ((fourcc >> 24) & 0xff) - ); return NULL; } @@ -502,8 +432,9 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; - *size = fh->fmt->depth*fh->width*fh->height >> 3; + *size = (dev->fmt->depth * dev->width * dev->height) >> 3; if (0 == *count) *count = 32; if (*size * *count > vid_limit * 1024 * 1024) @@ -523,21 +454,23 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int field_tff; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) + if (WARN_ON(NULL == dev->fmt)) + return -EINVAL; + + if (dev->width < 48 || dev->width > norm_maxw(dev->tvnorm) || + dev->height < 32 || dev->height > norm_maxh(dev->tvnorm)) return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || + if (buf->fmt != dev->fmt || + buf->vb.width != dev->width || + buf->vb.height != dev->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; + buf->fmt = dev->fmt; + buf->vb.width = dev->width; + buf->vb.height = dev->height; buf->vb.field = field; init_buffer = 1; } @@ -612,7 +545,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; @@ -738,9 +671,6 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; fh->dev = dev; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, @@ -887,13 +817,14 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; + (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -951,7 +882,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = fh->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -960,12 +891,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; fh->vidq.field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - fh->width, fh->height, fh->vidq.field); + dev->width, dev->height, fh->vidq.field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); @@ -976,7 +907,8 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, @@ -1619,6 +1551,9 @@ int cx23885_video_register(struct cx23885_dev *dev) strcpy(cx23885_vbi_template.name, "cx23885-vbi"); dev->tvnorm = V4L2_STD_NTSC_M; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); + dev->width = norm_maxw(dev->tvnorm); + dev->height = norm_maxh(dev->tvnorm); /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index a88e951a91b8..260d17712ab4 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -145,10 +145,6 @@ struct cx23885_fh { struct cx23885_dev *dev; u32 resources; - /* video capture */ - struct cx23885_fmt *fmt; - unsigned int width, height; - /* vbi capture */ struct videobuf_queue vidq; struct videobuf_queue vbiq; @@ -424,6 +420,10 @@ struct cx23885_dev { struct video_device *video_dev; struct video_device *vbi_dev; + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + struct cx23885_dmaqueue vidq; struct cx23885_dmaqueue vbiq; spinlock_t slock; -- cgit v1.2.3 From 9529a4b0cf49163e489446ec159a2dfb64f78df8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 08:27:00 -0300 Subject: [media] cx23885: drop videobuf abuse in cx23885-alsa The alsa driver uses videobuf low-level functions that are not available in vb2, so replace them by driver-specific functions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-alsa.c | 96 ++++++++++++++++++++++++++++---- drivers/media/pci/cx23885/cx23885.h | 7 ++- 2 files changed, 88 insertions(+), 15 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 554798dcedd0..31dbf0c64578 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -84,6 +84,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); #define AUD_INT_MCHG_IRQ (1 << 21) #define GP_COUNT_CONTROL_RESET 0x3 +static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) +{ + struct cx23885_audio_buffer *buf = chip->buf; + struct page *pg; + int i; + + buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == buf->vaddr) { + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); + return -ENOMEM; + } + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)buf->vaddr, + nr_pages << PAGE_SHIFT); + + memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); + buf->nr_pages = nr_pages; + + buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + if (NULL == buf->sglist) + goto vzalloc_err; + + sg_init_table(buf->sglist, buf->nr_pages); + for (i = 0; i < buf->nr_pages; i++) { + pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); + if (NULL == pg) + goto vmalloc_to_page_err; + sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); + } + return 0; + +vmalloc_to_page_err: + vfree(buf->sglist); + buf->sglist = NULL; +vzalloc_err: + vfree(buf->vaddr); + buf->vaddr = NULL; + return -ENOMEM; +} + +static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, + buf->nr_pages, PCI_DMA_FROMDEVICE); + + if (0 == buf->sglen) { + pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + if (!buf->sglen) + return 0; + + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + buf->sglen = 0; + return 0; +} + +static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf) +{ + vfree(buf->sglist); + buf->sglist = NULL; + vfree(buf->vaddr); + buf->vaddr = NULL; + return 0; +} + /* * BOARD Specific: Sets audio DMA */ @@ -201,12 +277,12 @@ static int dsp_buffer_free(struct cx23885_audio_dev *chip) BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); + cx23885_alsa_dma_unmap(chip); + cx23885_alsa_dma_free(chip->buf); btcx_riscmem_free(chip->pci, &chip->buf->risc); kfree(chip->buf); - chip->dma_risc = NULL; + chip->buf = NULL; chip->dma_size = 0; return 0; @@ -289,6 +365,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream) return 0; } + /* * hw_params callback */ @@ -296,8 +373,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - struct cx23885_audio_buffer *buf; int ret; @@ -319,18 +394,16 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->bpl = chip->period_size; - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + ret = cx23885_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_dma_map(&chip->pci->dev, dma); + ret = cx23885_alsa_dma_map(chip); if (ret < 0) goto error; - ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist, + ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist, chip->period_size, chip->num_periods, 1); if (ret < 0) goto error; @@ -341,9 +414,8 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ chip->buf = buf; - chip->dma_risc = dma; - substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 260d17712ab4..9cd2b1b31cec 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -324,7 +324,10 @@ struct cx23885_kernel_ir { struct cx23885_audio_buffer { unsigned int bpl; struct btcx_riscmem risc; - struct videobuf_dmabuf dma; + void *vaddr; + struct scatterlist *sglist; + int sglen; + int nr_pages; }; struct cx23885_audio_dev { @@ -342,8 +345,6 @@ struct cx23885_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf *dma_risc; - struct cx23885_audio_buffer *buf; struct snd_pcm_substream *substream; -- cgit v1.2.3 From 568f44a18e9b63fbb44fcb3292c3530087ae527b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 Apr 2014 08:43:51 -0300 Subject: [media] cx23885: use video_drvdata to get cx23885_dev pointer Use video_drvdata(file) instead of fh->dev to get the cx23885_dev pointer. This prepares for the vb2 conversion where fh->dev (renamed to fh->q_dev in this patch) will be removed completely. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 56 +++++++++++++---------------- drivers/media/pci/cx23885/cx23885-ioctl.c | 6 ++-- drivers/media/pci/cx23885/cx23885-vbi.c | 7 ++-- drivers/media/pci/cx23885/cx23885-video.c | 60 +++++++++++++++---------------- drivers/media/pci/cx23885/cx23885.h | 2 +- 5 files changed, 60 insertions(+), 71 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 4142c15b259e..0948b44b1c5e 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1147,10 +1147,10 @@ static int bb_buf_setup(struct videobuf_queue *q, { struct cx23885_fh *fh = q->priv_data; - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; + fh->q_dev->ts1.ts_packet_size = mpeglinesize; + fh->q_dev->ts1.ts_packet_count = mpeglines; - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + *size = fh->q_dev->ts1.ts_packet_size * fh->q_dev->ts1.ts_packet_count; *count = mpegbufs; return 0; @@ -1160,7 +1160,7 @@ static int bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->dev->ts1, + return cx23885_buf_prepare(q, &fh->q_dev->ts1, (struct cx23885_buffer *)vb, field); } @@ -1169,7 +1169,7 @@ static void bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); + cx23885_buf_queue(&fh->q_dev->ts1, (struct cx23885_buffer *)vb); } static void bb_buf_release(struct videobuf_queue *q, @@ -1189,8 +1189,7 @@ static struct videobuf_queue_ops cx23885_qops = { static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); *id = dev->tvnorm; return 0; @@ -1198,8 +1197,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); unsigned int i; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) @@ -1218,7 +1216,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } @@ -1236,8 +1234,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1254,8 +1251,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1269,8 +1265,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1291,8 +1286,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_tsport *tsport = &dev->ts1; strlcpy(cap->driver, dev->name, sizeof(cap->driver)); @@ -1325,8 +1319,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1344,8 +1338,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1360,8 +1354,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1422,8 +1415,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); @@ -1434,8 +1426,8 @@ static int vidioc_log_status(struct file *file, void *priv) static int mpeg_open(struct file *file) { - struct video_device *vdev = video_devdata(file); struct cx23885_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh; dprintk(2, "%s()\n", __func__); @@ -1447,7 +1439,7 @@ static int mpeg_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; - fh->dev = dev; + fh->q_dev = dev; videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, &dev->pci->dev, &dev->ts1.slock, @@ -1461,8 +1453,8 @@ static int mpeg_open(struct file *file) static int mpeg_release(struct file *file) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); @@ -1471,14 +1463,14 @@ static int mpeg_release(struct file *file) if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { if (atomic_dec_return(&dev->v4l_reader_count) == 0) { /* stop mpeg capture */ - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, CX23885_END_NOW, CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); msleep(500); cx23885_417_check_encoder(dev); - cx23885_cancel_buffers(&fh->dev->ts1); + cx23885_cancel_buffers(&dev->ts1); } } @@ -1499,8 +1491,8 @@ static int mpeg_release(struct file *file) static ssize_t mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); @@ -1520,8 +1512,8 @@ static ssize_t mpeg_read(struct file *file, char __user *data, static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s\n", __func__); @@ -1530,8 +1522,8 @@ static unsigned int mpeg_poll(struct file *file, static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; dprintk(2, "%s()\n", __func__); diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 271d69d1ca8c..9c16786371a2 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -28,7 +28,7 @@ int cx23885_g_chip_info(struct file *file, void *fh, struct v4l2_dbg_chip_info *chip) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (chip->match.addr > 1) return -EINVAL; @@ -64,7 +64,7 @@ static int cx23417_g_register(struct cx23885_dev *dev, int cx23885_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; @@ -96,7 +96,7 @@ static int cx23417_s_register(struct cx23885_dev *dev, int cx23885_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index a1154f035bc1..1cb67d38022a 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -50,8 +50,7 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ @@ -201,7 +200,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); @@ -242,7 +241,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vbiq; /* add jump to stopper */ diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 3dcee0a01787..b3740038cefb 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -432,7 +432,7 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; *size = (dev->fmt->depth * dev->width * dev->height) >> 3; if (0 == *count) @@ -446,7 +446,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); int rc, init_buffer = 0; @@ -562,7 +562,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct cx23885_buffer, vb); struct cx23885_buffer *prev; struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vidq; /* add jump to stopper */ @@ -670,7 +670,7 @@ static int video_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); file->private_data = &fh->fh; - fh->dev = dev; + fh->q_dev = dev; videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, &dev->pci->dev, &dev->slock, @@ -697,16 +697,17 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; switch (vdev->vfl_type) { case VFL_TYPE_GRABBER: - if (res_locked(fh->dev, RESOURCE_VIDEO)) + if (res_locked(dev, RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); case VFL_TYPE_VBI: - if (!res_get(fh->dev, fh, RESOURCE_VBI)) + if (!res_get(dev, fh, RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, file->f_flags & O_NONBLOCK); @@ -719,6 +720,7 @@ static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; struct cx23885_buffer *buf; unsigned long req_events = poll_requested_events(wait); @@ -732,7 +734,7 @@ static unsigned int video_poll(struct file *file, return rc; if (vdev->vfl_type == VFL_TYPE_VBI) { - if (!res_get(fh->dev, fh, RESOURCE_VBI)) + if (!res_get(dev, fh, RESOURCE_VBI)) return rc | POLLERR; return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } @@ -761,8 +763,8 @@ done: static int video_release(struct file *file) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { @@ -816,8 +818,8 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -835,7 +837,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; @@ -881,8 +883,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -906,9 +908,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, @@ -967,9 +968,9 @@ static int vidioc_dqbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; dprintk(1, "%s()\n", __func__); if (vdev->vfl_type == VFL_TYPE_VBI && @@ -994,9 +995,9 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx23885_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; int err, res; dprintk(1, "%s()\n", __func__); @@ -1017,7 +1018,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); *id = dev->tvnorm; @@ -1026,7 +1027,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); cx23885_set_tvnorm(dev, tvnorms); @@ -1086,14 +1087,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); *i = dev->input; dprintk(1, "%s() returns %d\n", __func__, *i); @@ -1107,7 +1108,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) int cx23885_set_input(struct file *file, void *priv, unsigned int i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s(%d)\n", __func__, i); @@ -1134,8 +1135,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); call_all(dev, core, log_status); return 0; @@ -1144,7 +1144,7 @@ static int vidioc_log_status(struct file *file, void *priv) static int cx23885_query_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", @@ -1174,7 +1174,7 @@ static int vidioc_enum_audinput(struct file *file, void *priv, static int vidioc_g_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) @@ -1189,7 +1189,7 @@ static int vidioc_g_audinput(struct file *file, void *priv, static int vidioc_s_audinput(struct file *file, void *priv, const struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) { @@ -1211,7 +1211,7 @@ static int vidioc_s_audinput(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1227,7 +1227,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1242,8 +1242,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1349,8 +1348,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); int ret; switch (dev->board) { diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 9cd2b1b31cec..95f8c422a3d6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -142,8 +142,8 @@ struct cx23885_tvnorm { struct cx23885_fh { struct v4l2_fh fh; - struct cx23885_dev *dev; u32 resources; + struct cx23885_dev *q_dev; /* vbi capture */ struct videobuf_queue vidq; -- cgit v1.2.3 From 0310539723fb173c398ad1a0da2683d41d20dba5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 20:43:16 -0300 Subject: [media] cx23885: remove FSF address as per checkpatch These addresses are usually out-of-date and the top-level license will always have the right address. So drop it from these sources. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/altera-ci.c | 4 ---- drivers/media/pci/cx23885/altera-ci.h | 4 ---- drivers/media/pci/cx23885/cimax2.c | 4 ---- drivers/media/pci/cx23885/cimax2.h | 4 ---- drivers/media/pci/cx23885/cx23885-417.c | 4 ---- drivers/media/pci/cx23885/cx23885-alsa.c | 4 ---- drivers/media/pci/cx23885/cx23885-av.c | 5 ----- drivers/media/pci/cx23885/cx23885-av.h | 5 ----- drivers/media/pci/cx23885/cx23885-cards.c | 6 ------ drivers/media/pci/cx23885/cx23885-core.c | 4 ---- drivers/media/pci/cx23885/cx23885-dvb.c | 5 ----- drivers/media/pci/cx23885/cx23885-f300.c | 4 ---- drivers/media/pci/cx23885/cx23885-i2c.c | 12 ------------ drivers/media/pci/cx23885/cx23885-input.c | 5 ----- drivers/media/pci/cx23885/cx23885-input.h | 5 ----- drivers/media/pci/cx23885/cx23885-ioctl.c | 4 ---- drivers/media/pci/cx23885/cx23885-ioctl.h | 4 ---- drivers/media/pci/cx23885/cx23885-ir.c | 5 ----- drivers/media/pci/cx23885/cx23885-ir.h | 5 ----- drivers/media/pci/cx23885/cx23885-reg.h | 4 ---- drivers/media/pci/cx23885/cx23885-vbi.c | 4 ---- drivers/media/pci/cx23885/cx23885-video.c | 5 ----- drivers/media/pci/cx23885/cx23885-video.h | 5 ----- drivers/media/pci/cx23885/cx23885.h | 4 ---- drivers/media/pci/cx23885/cx23888-ir.c | 5 ----- drivers/media/pci/cx23885/cx23888-ir.h | 5 ----- drivers/media/pci/cx23885/netup-eeprom.c | 4 ---- drivers/media/pci/cx23885/netup-eeprom.h | 4 ---- drivers/media/pci/cx23885/netup-init.c | 4 ---- drivers/media/pci/cx23885/netup-init.h | 4 ---- 30 files changed, 141 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 2926f7fadccd..8302d444a0ba 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -16,10 +16,6 @@ * 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. */ /* diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 4998c96caebe..5028f0cf83f4 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -16,10 +16,6 @@ * 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 __ALTERA_CI_H #define __ALTERA_CI_H diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 16fa7ea4d4aa..631e4f24aea6 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -17,10 +17,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h index 518744a4c8a5..565e958f6f8d 100644 --- a/drivers/media/pci/cx23885/cimax2.h +++ b/drivers/media/pci/cx23885/cimax2.h @@ -17,10 +17,6 @@ * 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 CIMAX2_H diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 0948b44b1c5e..56673b52c559 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -18,10 +18,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 31dbf0c64578..c17e4740d47c 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -15,10 +15,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c index c443b7ac5adf..877dad89107e 100644 --- a/drivers/media/pci/cx23885/cx23885-av.c +++ b/drivers/media/pci/cx23885/cx23885-av.c @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h index d2915c3e53a2..97f232f8efb9 100644 --- a/drivers/media/pci/cx23885/cx23885-av.h +++ b/drivers/media/pci/cx23885/cx23885-av.h @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_AV_H_ diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c2b608007190..21e500b0a220 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -13,10 +13,6 @@ * 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 @@ -1970,5 +1966,3 @@ void cx23885_card_setup(struct cx23885_dev *dev) } } } - -/* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 075b28eda8de..0b6bbac6990f 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 968fecc32f9c..ccf413f3c4ff 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -13,10 +13,6 @@ * 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 @@ -1668,4 +1664,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } - diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 5444cc526008..6f817d8732da 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -22,10 +22,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 4887314339cb..fd71306af6e2 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -13,10 +13,6 @@ * 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 @@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable) i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); } - -/* ----------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 1940c18e186c..9d37fe661691 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -28,11 +28,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h index 87dc44e69977..6199c7e86e83 100644 --- a/drivers/media/pci/cx23885/cx23885-input.h +++ b/drivers/media/pci/cx23885/cx23885-input.h @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_INPUT_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 9c16786371a2..d2cdd40f79f5 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -15,10 +15,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h index 92d9f0774366..cc5dbb6c1afc 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.h +++ b/drivers/media/pci/cx23885/cx23885-ioctl.h @@ -15,10 +15,6 @@ * 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 _CX23885_IOCTL_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c index bfef19359291..89dc4cc3e1ce 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.c +++ b/drivers/media/pci/cx23885/cx23885-ir.c @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h index 0c9d8bda9e28..8e93d1f10ae0 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.h +++ b/drivers/media/pci/cx23885/cx23885-ir.h @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_IR_H_ diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h index a99936e0cbc2..2d3cbafe2402 100644 --- a/drivers/media/pci/cx23885/cx23885-reg.h +++ b/drivers/media/pci/cx23885/cx23885-reg.h @@ -13,10 +13,6 @@ * 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 _CX23885_REG_H_ diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 1cb67d38022a..23790fadc6d5 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index b3740038cefb..9cd8cf48334b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -13,10 +13,6 @@ * 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 @@ -1665,4 +1661,3 @@ fail_unreg: cx23885_video_unregister(dev); return err; } - diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h index c961a2b0de0f..291e8f3189f0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.h +++ b/drivers/media/pci/cx23885/cx23885-video.h @@ -12,11 +12,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_VIDEO_H_ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 95f8c422a3d6..5f5d8e8aa472 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -13,10 +13,6 @@ * 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 diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index c2ff5fc01157..c1aa888af705 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h index d2de41caaf1d..ff74a93575d6 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.h +++ b/drivers/media/pci/cx23885/cx23888-ir.h @@ -14,11 +14,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23888_IR_H_ diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c index 98a48f500684..b6542ee4385b 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.c +++ b/drivers/media/pci/cx23885/netup-eeprom.c @@ -17,10 +17,6 @@ * 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. */ # diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h index 13926e18feba..90cac5b655d5 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.h +++ b/drivers/media/pci/cx23885/netup-eeprom.h @@ -16,10 +16,6 @@ * 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 NETUP_EEPROM_H diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c index 0044fef7ca24..76d9487aafc8 100644 --- a/drivers/media/pci/cx23885/netup-init.c +++ b/drivers/media/pci/cx23885/netup-init.c @@ -17,10 +17,6 @@ * 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 "cx23885.h" diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h index d26ae4b1590e..daaa212adfba 100644 --- a/drivers/media/pci/cx23885/netup-init.h +++ b/drivers/media/pci/cx23885/netup-init.h @@ -17,9 +17,5 @@ * 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. */ extern void netup_initialize(struct cx23885_dev *dev); -- cgit v1.2.3 From c44b6484db6e285cbc63bb8d400b5e8873e3a8d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 16:27:38 -0300 Subject: [media] solo6x10: fix sparse warnings drivers/media/pci/solo6x10/solo6x10-disp.c:184:24: warning: incorrect type in assignment (different base types) drivers/media/pci/solo6x10/solo6x10-disp.c:223:32: warning: incorrect type in assignment (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-disp.c | 4 ++-- drivers/media/pci/solo6x10/solo6x10-eeprom.c | 8 ++++---- drivers/media/pci/solo6x10/solo6x10.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c index 5ea9cac03968..11c98f0625e4 100644 --- a/drivers/media/pci/solo6x10/solo6x10-disp.c +++ b/drivers/media/pci/solo6x10/solo6x10-disp.c @@ -172,7 +172,7 @@ static void solo_vout_config(struct solo_dev *solo_dev) static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, u16 val, int reg_size) { - u16 *buf; + __le16 *buf; const int n = 64, size = n * sizeof(*buf); int i, ret = 0; @@ -211,7 +211,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, { const unsigned size = sizeof(u16) * 64; u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; - u16 *buf; + __le16 *buf; int x, y; int ret = 0; diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c index af40b3aba410..da25ce4a6952 100644 --- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c +++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c @@ -100,7 +100,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) return retval; } -unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) +__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc) { int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); unsigned short retval = 0; @@ -117,11 +117,11 @@ unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) solo_eeprom_reg_write(solo_dev, ~EE_CS); - return retval; + return (__force __be16)retval; } int solo_eeprom_write(struct solo_dev *solo_dev, int loc, - unsigned short data) + __be16 data) { int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); unsigned int retval; @@ -130,7 +130,7 @@ int solo_eeprom_write(struct solo_dev *solo_dev, int loc, solo_eeprom_cmd(solo_dev, write_cmd); for (i = 15; i >= 0; i--) { - unsigned int dataval = (data >> i) & 1; + unsigned int dataval = ((__force unsigned)data >> i) & 1; solo_eeprom_reg_write(solo_dev, EE_ENB); solo_eeprom_reg_write(solo_dev, diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index c6154b00fcbd..72017b7f0a75 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -394,9 +394,9 @@ int solo_osd_print(struct solo_enc_dev *solo_enc); /* EEPROM commands */ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en); -unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc); +__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc); int solo_eeprom_write(struct solo_dev *solo_dev, int loc, - unsigned short data); + __be16 data); /* JPEG Qp functions */ void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, -- cgit v1.2.3 From b5c00cc5a56ce0060fb17380cc606514eb5bcd9e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:25:00 -0300 Subject: [media] ddbridge: fix sparse warnings drivers/media/pci/ddbridge/ddbridge-core.c:88:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:93:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:95:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:99:15: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:117:58: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:119:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:123:68: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:130:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:131:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:136:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:138:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:152:22: warning: symbol 'ddb_i2c_algo' was not declared. Should it be static? drivers/media/pci/ddbridge/ddbridge-core.c:183:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:184:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:246:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:247:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:255:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:256:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:269:35: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:358:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:359:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:360:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:362:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:366:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:368:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:369:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:370:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:380:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:381:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:393:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:394:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:395:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:396:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:397:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:401:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:403:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:404:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:406:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:416:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:417:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:475:36: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:484:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:494:20: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:501:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:524:36: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:534:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:852:21: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:973:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ddbridge/ddbridge-core.c:974:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ddbridge/ddbridge-core.c:978:20: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:982:20: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1003:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1006:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1009:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1015:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1017:39: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1035:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1041:20: warning: symbol 'cxd_cfg' was not declared. Should it be static? drivers/media/pci/ddbridge/ddbridge-core.c:1130:44: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1183:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1188:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1193:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1198:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1213:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1214:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1215:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1216:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1231:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1232:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1233:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1289:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1333:23: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1295:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1347:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1353:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1354:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1359:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1361:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1373:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1374:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1378:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1382:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1385:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1386:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1388:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1393:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1394:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1395:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1398:16: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1399:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1451:42: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1462:45: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1467:37: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1538:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1550:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1561:31: warning: Using plain integer as NULL pointer drivers/media/pci/ddbridge/ddbridge-core.c:1585:19: warning: incorrect type in assignment (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1591:47: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1591:60: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ddbridge/ddbridge-core.c:1607:9: warning: too many warnings Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-core.c | 30 ++++++++++++++---------------- drivers/media/pci/ddbridge/ddbridge.h | 12 +++++------- 2 files changed, 19 insertions(+), 23 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index da8f848be3b8..c82e855a0814 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -149,7 +149,7 @@ static u32 ddb_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -struct i2c_algorithm ddb_i2c_algo = { +static struct i2c_algorithm ddb_i2c_algo = { .master_xfer = ddb_i2c_master_xfer, .functionality = ddb_i2c_functionality, }; @@ -266,7 +266,7 @@ static void io_free(struct pci_dev *pdev, u8 **vbuf, for (i = 0; i < num; i++) { if (vbuf[i]) { pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); - vbuf[i] = 0; + vbuf[i] = NULL; } } } @@ -440,7 +440,7 @@ static u32 ddb_output_free(struct ddb_output *output) } static ssize_t ddb_output_write(struct ddb_output *output, - const u8 *buf, size_t count) + const __user u8 *buf, size_t count) { struct ddb *dev = output->port->dev; u32 idx, off, stat = output->stat; @@ -506,7 +506,7 @@ static u32 ddb_input_avail(struct ddb_input *input) return 0; } -static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) +static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count) { struct ddb *dev = input->port->dev; u32 left = count; @@ -849,7 +849,7 @@ static int dvb_input_attach(struct ddb_input *input) return ret; input->attached = 4; - input->fe = 0; + input->fe = NULL; switch (port->type) { case DDB_TUNER_DVBS_ST: if (demod_attach_stv0900(input, 0) < 0) @@ -895,7 +895,7 @@ static int dvb_input_attach(struct ddb_input *input) /****************************************************************************/ /****************************************************************************/ -static ssize_t ts_write(struct file *file, const char *buf, +static ssize_t ts_write(struct file *file, const __user char *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -920,7 +920,7 @@ static ssize_t ts_write(struct file *file, const char *buf, return (left == count) ? -EAGAIN : (count - left); } -static ssize_t ts_read(struct file *file, char *buf, +static ssize_t ts_read(struct file *file, __user char *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -975,11 +975,9 @@ static const struct file_operations ci_fops = { .open = dvb_generic_open, .release = dvb_generic_release, .poll = ts_poll, - .mmap = 0, }; static struct dvb_device dvbdev_ci = { - .priv = 0, .readers = -1, .writers = -1, .users = -1, @@ -1038,7 +1036,7 @@ static void output_tasklet(unsigned long data) } -struct cxd2099_cfg cxd_cfg = { +static struct cxd2099_cfg cxd_cfg = { .bitrate = 62000, .adr = 0x40, .polarity = 1, @@ -1127,7 +1125,7 @@ static void ddb_ports_detach(struct ddb *dev) ddb_output_stop(port->output); dvb_ca_en50221_release(port->en); kfree(port->en); - port->en = 0; + port->en = NULL; dvb_unregister_adapter(&port->output->adap); } break; @@ -1413,9 +1411,9 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) #define DDB_MAGIC 'd' struct ddb_flashio { - __u8 *write_buf; + __user __u8 *write_buf; __u32 write_len; - __u8 *read_buf; + __user __u8 *read_buf; __u32 read_len; }; @@ -1439,7 +1437,7 @@ static int ddb_open(struct inode *inode, struct file *file) static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ddb *dev = file->private_data; - void *parg = (void *)arg; + __user void *parg = (__user void *)arg; int res; switch (cmd) { @@ -1558,7 +1556,7 @@ static void ddb_remove(struct pci_dev *pdev) ddb_device_destroy(dev); ddb_unmap(dev); - pci_set_drvdata(pdev, 0); + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); } @@ -1637,7 +1635,7 @@ fail1: fail: printk(KERN_ERR "fail\n"); ddb_unmap(dev); - pci_set_drvdata(pdev, 0); + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); return -1; } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 8b1b41d2a52d..be87fbd90456 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -156,7 +156,7 @@ struct ddb_port { struct ddb { struct pci_dev *pdev; - unsigned char *regs; + unsigned char __iomem *regs; struct ddb_port port[DDB_MAX_PORT]; struct ddb_i2c i2c[DDB_MAX_I2C]; struct ddb_input input[DDB_MAX_INPUT]; @@ -173,12 +173,10 @@ struct ddb { /****************************************************************************/ #define ddbwritel(_val, _adr) writel((_val), \ - (char *) (dev->regs+(_adr))) -#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) -#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ - (dev->regs+(_adr)), (_src), (_count)) -#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ - (dev->regs+(_adr)), (_count)) + dev->regs+(_adr)) +#define ddbreadl(_adr) readl(dev->regs+(_adr)) +#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count)) +#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count)) /****************************************************************************/ -- cgit v1.2.3 From c463c9797c43dd66b72daa397716d6c6675087b8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 17:43:22 -0300 Subject: [media] ngene: fix sparse warnings drivers/media/pci/ngene/ngene-core.c:188:27: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:190:25: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:199:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:260:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:263:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:282:32: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:283:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:284:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:285:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:286:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:287:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:288:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:292:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:293:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:294:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:295:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:296:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:297:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:303:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:316:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:368:17: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:372:9: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1160:28: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1199:20: warning: incorrect type in assignment (different address spaces) drivers/media/pci/ngene/ngene-core.c:1213:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1214:30: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1223:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1225:24: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1227:31: warning: incorrect type in argument 1 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1296:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1297:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1298:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1299:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1300:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1301:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1302:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1363:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1365:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1376:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1391:17: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-core.c:1596:18: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-core.c:1615:9: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-cards.c:699:29: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:32: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:35: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-cards.c:699:38: warning: Using plain integer as NULL pointer drivers/media/pci/ngene/ngene-dvb.c:84:59: warning: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-dvb.c:93:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ngene/ngene-dvb.c:94:20: warning: incorrect type in initializer (incompatible argument 2 (different address spaces)) drivers/media/pci/ngene/ngene-dvb.c:100:20: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ngene/ngene-cards.c | 2 +- drivers/media/pci/ngene/ngene-core.c | 14 ++++++-------- drivers/media/pci/ngene/ngene-dvb.c | 5 ++--- drivers/media/pci/ngene/ngene.h | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 9e82d2105d53..039bed3cc919 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -696,7 +696,7 @@ static struct ngene_info ngene_info_m780 = { .demod_attach = { NULL, demod_attach_lg330x }, /* Ensure these are NULL else the frame will call them (as funcs) */ - .tuner_attach = { 0, 0, 0, 0 }, + .tuner_attach = { NULL, NULL, NULL, NULL }, .fe_config = { NULL, &aver_m780 }, .avf = { 0 }, diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 4930b55fd5f4..e29bc3af4baf 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -57,15 +57,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define dprintk if (debug) printk -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) -#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr))) -#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr))) +#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) +#define ngwritel(dat, adr) writel((dat), dev->iomem + (adr)) +#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr)) #define ngreadl(adr) readl(dev->iomem + (adr)) #define ngreadb(adr) readb(dev->iomem + (adr)) -#define ngcpyto(adr, src, count) memcpy_toio((char *) \ - (dev->iomem + (adr)), (src), (count)) -#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \ - (dev->iomem + (adr)), (count)) +#define ngcpyto(adr, src, count) memcpy_toio(dev->iomem + (adr), (src), (count)) +#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count)) /****************************************************************************/ /* nGene interrupt handler **************************************************/ @@ -1592,7 +1590,7 @@ static void cxd_detach(struct ngene *dev) dvb_ca_en50221_release(ci->en); kfree(ci->en); - ci->en = 0; + ci->en = NULL; } /***********************************/ diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index fcb16a615aab..a8a4045f66d7 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -47,7 +47,7 @@ /* COMMAND API interface ****************************************************/ /****************************************************************************/ -static ssize_t ts_write(struct file *file, const char *buf, +static ssize_t ts_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -64,7 +64,7 @@ static ssize_t ts_write(struct file *file, const char *buf, return count; } -static ssize_t ts_read(struct file *file, char *buf, +static ssize_t ts_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dvb_device *dvbdev = file->private_data; @@ -97,7 +97,6 @@ static const struct file_operations ci_fops = { }; struct dvb_device ngene_dvbdev_ci = { - .priv = 0, .readers = -1, .writers = -1, .users = -1, diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 22c39ff6bfa0..51e2fbd18b1b 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -737,7 +737,7 @@ typedef void (tx_cb_t)(struct ngene *, u32); struct ngene { int nr; struct pci_dev *pci_dev; - unsigned char *iomem; + unsigned char __iomem *iomem; /*struct i2c_adapter i2c_adapter;*/ -- cgit v1.2.3 From 967a37830573a1fa4b7bdb7ce203c7ea8a91e0c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Aug 2014 18:26:40 -0300 Subject: [media] mantis: fix sparse warnings drivers/media/pci/mantis/hopper_vp3028.c:37:23: warning: symbol 'hopper_vp3028_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1033.c:38:4: warning: symbol 'lgtdqcs001f_inittab' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1033.c:153:23: warning: symbol 'lgtdqcs001f_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1034.c:39:23: warning: symbol 'vp1034_mb86a16_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1041.c:266:23: warning: symbol 'vp1041_stb0899_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp1041.c:303:23: warning: symbol 'vp1041_stb6100_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2033.c:40:24: warning: symbol 'vp2033_tda1002x_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2033.c:45:24: warning: symbol 'vp2033_tda10023_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2040.c:40:24: warning: symbol 'vp2040_tda1002x_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp2040.c:45:24: warning: symbol 'vp2040_tda10023_cu1216_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp3030.c:38:23: warning: symbol 'mantis_vp3030_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_vp3030.c:42:23: warning: symbol 'env57h12d5_config' was not declared. Should it be static? drivers/media/pci/mantis/mantis_dma.c:167:33: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:172:33: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:174:25: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:178:9: warning: incorrect type in assignment (different base types) drivers/media/pci/mantis/mantis_dma.c:179:9: warning: incorrect type in assignment (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/mantis/hopper_vp3028.c | 2 +- drivers/media/pci/mantis/mantis_common.h | 2 +- drivers/media/pci/mantis/mantis_vp1033.c | 4 ++-- drivers/media/pci/mantis/mantis_vp1034.c | 2 +- drivers/media/pci/mantis/mantis_vp1041.c | 4 ++-- drivers/media/pci/mantis/mantis_vp2033.c | 4 ++-- drivers/media/pci/mantis/mantis_vp2040.c | 4 ++-- drivers/media/pci/mantis/mantis_vp3030.c | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c index 68a29f8bdf73..1032db6bb789 100644 --- a/drivers/media/pci/mantis/hopper_vp3028.c +++ b/drivers/media/pci/mantis/hopper_vp3028.c @@ -34,7 +34,7 @@ #include "mantis_dvb.h" #include "hopper_vp3028.h" -struct zl10353_config hopper_vp3028_config = { +static struct zl10353_config hopper_vp3028_config = { .demod_address = 0x0f, }; diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index f2410cf0a6bf..8ff448bb792d 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -127,7 +127,7 @@ struct mantis_pci { u32 last_block; u8 *buf_cpu; dma_addr_t buf_dma; - u32 *risc_cpu; + __le32 *risc_cpu; dma_addr_t risc_dma; struct tasklet_struct tasklet; diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c index 115003e8d19d..12a6adb2bd7e 100644 --- a/drivers/media/pci/mantis/mantis_vp1033.c +++ b/drivers/media/pci/mantis/mantis_vp1033.c @@ -35,7 +35,7 @@ #include "mantis_vp1033.h" #include "mantis_reg.h" -u8 lgtdqcs001f_inittab[] = { +static u8 lgtdqcs001f_inittab[] = { 0x01, 0x15, 0x02, 0x30, 0x03, 0x00, @@ -150,7 +150,7 @@ static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, return 0; } -struct stv0299_config lgtdqcs001f_config = { +static struct stv0299_config lgtdqcs001f_config = { .demod_address = 0x68, .inittab = lgtdqcs001f_inittab, .mclk = 88000000UL, diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c index 430ae84ce528..7c1bd167225c 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.c +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -36,7 +36,7 @@ #include "mantis_vp1034.h" #include "mantis_reg.h" -struct mb86a16_config vp1034_mb86a16_config = { +static struct mb86a16_config vp1034_mb86a16_config = { .demod_address = 0x08, .set_voltage = vp1034_set_voltage, }; diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c index 07a20748b707..7082fcbc94a1 100644 --- a/drivers/media/pci/mantis/mantis_vp1041.c +++ b/drivers/media/pci/mantis/mantis_vp1041.c @@ -263,7 +263,7 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { { 0xffff , 0xff }, }; -struct stb0899_config vp1041_stb0899_config = { +static struct stb0899_config vp1041_stb0899_config = { .init_dev = vp1041_stb0899_s1_init_1, .init_s2_demod = stb0899_s2_init_2, .init_s1_demod = vp1041_stb0899_s1_init_3, @@ -300,7 +300,7 @@ struct stb0899_config vp1041_stb0899_config = { .tuner_set_rfsiggain = NULL, }; -struct stb6100_config vp1041_stb6100_config = { +static struct stb6100_config vp1041_stb6100_config = { .tuner_address = 0x60, .refclock = 27000000, }; diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c index 1ca6837fbe46..8d48b5abe04a 100644 --- a/drivers/media/pci/mantis/mantis_vp2033.c +++ b/drivers/media/pci/mantis/mantis_vp2033.c @@ -37,12 +37,12 @@ #define MANTIS_MODEL_NAME "VP-2033" #define MANTIS_DEV_TYPE "DVB-C" -struct tda1002x_config vp2033_tda1002x_cu1216_config = { +static struct tda1002x_config vp2033_tda1002x_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; -struct tda10023_config vp2033_tda10023_cu1216_config = { +static struct tda10023_config vp2033_tda10023_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c index d480741afd78..8dd17d7c0881 100644 --- a/drivers/media/pci/mantis/mantis_vp2040.c +++ b/drivers/media/pci/mantis/mantis_vp2040.c @@ -37,12 +37,12 @@ #define MANTIS_MODEL_NAME "VP-2040" #define MANTIS_DEV_TYPE "DVB-C" -struct tda1002x_config vp2040_tda1002x_cu1216_config = { +static struct tda1002x_config vp2040_tda1002x_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; -struct tda10023_config vp2040_tda10023_cu1216_config = { +static struct tda10023_config vp2040_tda10023_cu1216_config = { .demod_address = 0x18 >> 1, .invert = 1, }; diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c index c09308cd3ac6..5c1dd925bdd5 100644 --- a/drivers/media/pci/mantis/mantis_vp3030.c +++ b/drivers/media/pci/mantis/mantis_vp3030.c @@ -35,11 +35,11 @@ #include "mantis_dvb.h" #include "mantis_vp3030.h" -struct zl10353_config mantis_vp3030_config = { +static struct zl10353_config mantis_vp3030_config = { .demod_address = 0x0f, }; -struct tda665x_config env57h12d5_config = { +static struct tda665x_config env57h12d5_config = { .name = "ENV57H12D5 (ET-50DT)", .addr = 0x60, .frequency_min = 47000000, -- cgit v1.2.3 From 38b2b8794d0ae7e086199e6077d2f234a3b69ab8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:26:29 -0300 Subject: [media] cx25821: fix sparse warning drivers/media/pci/cx25821/cx25821-video-upstream.c:334:25: warning: incorrect type in argument 2 (different address spaces) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video-upstream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 1f43be0b04c8..a664997e1958 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan, if (frame_size - curpos < count) count = frame_size - curpos; - memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos, - data, count); + if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos, + data, count)) + return -EFAULT; curpos += count; if (curpos == frame_size) { out->_frame_count++; -- cgit v1.2.3 From 888bd5dcb68437273ffc3752c4976f851205b25d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:50:34 -0300 Subject: [media] dm1105: fix sparse warning drivers/media/pci/dm1105/dm1105.c:617:9: warning: incorrect type in argument 1 (different base types) Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/dm1105/dm1105.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index e8826c535ccd..ed11716731e9 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -614,7 +614,7 @@ static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) static void dm1105_set_dma_addr(struct dm1105_dev *dev) { - dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr)); + dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr)); } static int dm1105_dma_map(struct dm1105_dev *dev) -- cgit v1.2.3 From 711c31192057689e59c2a2095d3a7e0fadbfd213 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 11:56:42 -0300 Subject: [media] cx23885: fix sparse warning drivers/media/pci/cx23885/cx23885-dvb.c:1494:72: warning: Using plain integer as NULL pointer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index ccf413f3c4ff..d71d59f6c6d6 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1487,7 +1487,7 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr4400_si2165_config, &i2c_bus->i2c_adap); if (fe0->dvb.frontend != NULL) { - fe0->dvb.frontend->ops.i2c_gate_ctrl = 0; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (!dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &i2c_bus2->i2c_adap, -- cgit v1.2.3 From 3efb8ab6d4f0f38440a819d8302be18596899ebf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:31:51 -0300 Subject: [media] ivtv: fix sparse warnings drivers/media/pci/ivtv/ivtv-irq.c:195:25: warning: incorrect type in argument 1 (different base types) drivers/media/pci/ivtv/ivtv-irq.c:199:25: warning: incorrect type in argument 1 (different base types) drivers/media/pci/ivtv/ivtv-irq.c:278:35: warning: restricted __le32 degrades to integer drivers/media/pci/ivtv/ivtv-irq.c:281:51: warning: restricted __le32 degrades to integer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-irq.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index 19a7c9b990a3..ab6d5d25aa6f 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -192,11 +192,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || s->type == IVTV_DEC_STREAM_TYPE_VBI)) { s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET); - write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); + write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET); } else { s->pending_backup = read_enc(offset); - write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); + write_enc_sync(DMA_MAGIC_COOKIE, offset); } s->pending_offset = offset; } @@ -275,13 +275,11 @@ static void dma_post(struct ivtv_stream *s) if (x == 0 && ivtv_use_dma(s)) { offset = s->dma_last_offset; - if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) + if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE) { - for (offset = 0; offset < 64; offset++) { - if (u32buf[offset] == DMA_MAGIC_COOKIE) { + for (offset = 0; offset < 64; offset++) + if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE) break; - } - } offset *= 4; if (offset == 256) { IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); -- cgit v1.2.3 From 39fd44607a5ec904b84ecd92bf1710a9ecb3f68c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 21 Aug 2014 16:38:04 -0300 Subject: [media] cx18: fix sparse warnings /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:169:32: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:170:32: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:171:31: warning: cast to restricted __le32 /home/hans/work/build/media-git/drivers/media/pci/cx18/cx18-firmware.c:172:31: warning: cast to restricted __le32 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index a1c1cec05f98..53a7578d525b 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; while (offset + sizeof(seghdr) < fw->size) { - const u32 *shptr = src + offset / 4; + const __le32 *shptr = (__force __le32 *)src + offset / 4; seghdr.sync1 = le32_to_cpu(shptr[0]); seghdr.sync2 = le32_to_cpu(shptr[1]); -- cgit v1.2.3 From c3142a61e62481c8f7a4f19b92ff735516b54f87 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:32:07 -0300 Subject: [media] bttv-driver: remove an uneeded semicolon We don't use semicolons after curly braces in the middle of the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 970e542d3a51..750bdab8aacb 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3856,7 +3856,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), BT848_INT_MASK); - }; + } bttv_print_irqbits(stat,astat); -- cgit v1.2.3 From 1b21e2187adea385d9de53c8c861d9f56ea5bebe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:39:01 -0300 Subject: [media] lm3560: simplify a boolean test lml33dpatch is boolean. So, the possible values are true or false. Instead of using if (lml33dpath), just use if (!lml33dpath). That allows a faster mental parsing when analyzing the code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index bf34b93f23ee..b6801e035ea4 100644 --- a/drivers/media/pci/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -682,7 +682,7 @@ set_videobus_dir (struct zoran *zr, switch (zr->card.type) { case LML33: case LML33R10: - if (lml33dpath == 0) + if (!lml33dpath) GPIO(zr, 5, val); else GPIO(zr, 5, 1); -- cgit v1.2.3 From a896dc7a1f416e2b76efabff27c624c69645cc50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:30:41 -0300 Subject: [media] bt8xx: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 3 +-- drivers/media/pci/bt8xx/dst_ca.c | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 750bdab8aacb..4a8176c09fc9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, { struct bttv_buffer *old; unsigned long flags; - int retval = 0; dprintk("switch_overlay: enter [new=%p]\n", new); if (new) @@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, if (NULL == new) free_btres_lock(btv,fh,RESOURCE_OVERLAY); dprintk("switch_overlay: done\n"); - return retval; + return 0; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index 0e788fca992c..c22c4ae06844 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file) static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { - ssize_t bytes_read = 0; - dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); - return bytes_read; + return 0; } static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) -- cgit v1.2.3 From 5b0eb8271d9126db2daa2cf41422cc84ba319a6e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 15:36:12 -0300 Subject: [media] saa7164: just return 0 instead of using a var Instead of allocating a var to store 0 and just return it, change the code to return 0 directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index e042963d377d..4f3b1dd18ba4 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -680,7 +680,6 @@ static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) { struct saa7164_dev *dev = port->dev; - int ret = 0; u8 agc_disable; dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std); @@ -733,7 +732,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */ msleep(100); - return ret; + return 0; } /* Ensure the dif is in the correct state for the operating mode -- cgit v1.2.3 From 5740f4e75f713015067e2667a52bd3b35ef91e07 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 03:31:07 -0300 Subject: [media] tw68: add original tw68 code This tw68 driver has been out-of-tree for many years on gitorious: https://gitorious.org/tw68/tw68-v2. This copies that code to the kernel as a record of that original code. Note that William Brack's email address in these sources is no longer valid and I have not been able to contact him. However, all the code is standard GPL. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-cards.c | 172 +++ drivers/media/pci/tw68/tw68-core.c | 1091 ++++++++++++++++ drivers/media/pci/tw68/tw68-i2c.c | 245 ++++ drivers/media/pci/tw68/tw68-reg.h | 195 +++ drivers/media/pci/tw68/tw68-risc.c | 268 ++++ drivers/media/pci/tw68/tw68-ts.c | 66 + drivers/media/pci/tw68/tw68-tvaudio.c | 80 ++ drivers/media/pci/tw68/tw68-vbi.c | 76 ++ drivers/media/pci/tw68/tw68-video.c | 2230 +++++++++++++++++++++++++++++++++ drivers/media/pci/tw68/tw68.h | 588 +++++++++ 10 files changed, 5011 insertions(+) create mode 100644 drivers/media/pci/tw68/tw68-cards.c create mode 100644 drivers/media/pci/tw68/tw68-core.c create mode 100644 drivers/media/pci/tw68/tw68-i2c.c create mode 100644 drivers/media/pci/tw68/tw68-reg.h create mode 100644 drivers/media/pci/tw68/tw68-risc.c create mode 100644 drivers/media/pci/tw68/tw68-ts.c create mode 100644 drivers/media/pci/tw68/tw68-tvaudio.c create mode 100644 drivers/media/pci/tw68/tw68-vbi.c create mode 100644 drivers/media/pci/tw68/tw68-video.c create mode 100644 drivers/media/pci/tw68/tw68.h (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/tw68/tw68-cards.c b/drivers/media/pci/tw68/tw68-cards.c new file mode 100644 index 000000000000..62aec4faa0d1 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-cards.c @@ -0,0 +1,172 @@ +/* + * device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include /* must appear before i2c-algo-bit.h */ +#include + +#include +#include + +#include "tw68.h" +#include "tw68-reg.h" + +/* commly used strings */ +#if 0 +static char name_mute[] = "mute"; +static char name_radio[] = "Radio"; +static char name_tv[] = "Television"; +static char name_tv_mono[] = "TV (mono only)"; +static char name_svideo[] = "S-Video"; +static char name_comp[] = "Composite"; +#endif +static char name_comp1[] = "Composite1"; +static char name_comp2[] = "Composite2"; +static char name_comp3[] = "Composite3"; +static char name_comp4[] = "Composite4"; + +/* ------------------------------------------------------------------ */ +/* board config info */ + +/* If radio_type !=UNSET, radio_addr should be specified + */ + +struct tw68_board tw68_boards[] = { + [TW68_BOARD_UNKNOWN] = { + .name = "GENERIC", + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + + .inputs = { + { + .name = name_comp1, + .vmux = 0, + }, { + .name = name_comp2, + .vmux = 1, + }, { + .name = name_comp3, + .vmux = 2, + }, { + .name = name_comp4, + .vmux = 3, + }, { /* Must have a NULL entry at end of list */ + .name = NULL, + .vmux = 0, + } + }, + }, +}; + +const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards); + +/* + * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps + * the PCI ID database up to date. Note that the entries must be + * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. + */ +struct pci_device_id tw68_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6800, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6801, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6804, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + .vendor = PCI_VENDOR_ID_TECHWELL, + .device = PCI_DEVICE_ID_6816_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = TW68_BOARD_UNKNOWN, + }, { + /* end of list */ + } +}; +MODULE_DEVICE_TABLE(pci, tw68_pci_tbl); + +/* ------------------------------------------------------------ */ +/* stuff done before i2c enabled */ +int tw68_board_init1(struct tw68_dev *dev) +{ + /* Clear GPIO outputs */ + tw_writel(TW68_GPOE, 0); + /* Remainder of setup according to board ID */ + switch (dev->board) { + case TW68_BOARD_UNKNOWN: + printk(KERN_INFO "%s: Unable to determine board type, " + "using generic values\n", dev->name); + break; + } + dev->input = dev->hw_input = &card_in(dev,0); + return 0; +} + +int tw68_tuner_setup(struct tw68_dev *dev) +{ + return 0; +} + +/* stuff which needs working i2c */ +int tw68_board_init2(struct tw68_dev *dev) +{ + return 0; +} + + diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c new file mode 100644 index 000000000000..2c5d7a5f3f8e --- /dev/null +++ b/drivers/media/pci/tw68/tw68-core.c @@ -0,0 +1,1091 @@ +/* + * tw68-core.c + * Core functions for the Techwell 68xx driver + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "tw68.h" +#include "tw68-reg.h" + +MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); +MODULE_AUTHOR("William M. Brack "); +MODULE_LICENSE("GPL"); + +static unsigned int core_debug; +module_param(core_debug, int, 0644); +MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); + +static unsigned int gpio_tracking; +module_param(gpio_tracking, int, 0644); +MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); + +static unsigned int alsa = 1; +module_param(alsa, int, 0644); +MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); + +static unsigned int latency = UNSET; +module_param(latency, int, 0444); +MODULE_PARM_DESC(latency, "pci latency timer"); + +static unsigned int nocomb; +module_param(nocomb, int, 0644); +MODULE_PARM_DESC(nocomb, "disable comb filter"); + +static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); +module_param_array(tuner, int, NULL, 0444); +module_param_array(card, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device number"); +MODULE_PARM_DESC(vbi_nr, "vbi device number"); +MODULE_PARM_DESC(radio_nr, "radio device number"); +MODULE_PARM_DESC(tuner, "tuner type"); +MODULE_PARM_DESC(card, "card type"); + +LIST_HEAD(tw68_devlist); +EXPORT_SYMBOL(tw68_devlist); +DEFINE_MUTEX(tw68_devlist_lock); +EXPORT_SYMBOL(tw68_devlist_lock); +static LIST_HEAD(mops_list); +static unsigned int tw68_devcount; /* curr tot num of devices present */ + +int (*tw68_dmasound_init)(struct tw68_dev *dev); +EXPORT_SYMBOL(tw68_dmasound_init); +int (*tw68_dmasound_exit)(struct tw68_dev *dev); +EXPORT_SYMBOL(tw68_dmasound_exit); + +#define dprintk(level, fmt, arg...) if (core_debug & (level)) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) + +/* ------------------------------------------------------------------ */ + +void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) +{ + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + BUG_ON(in_interrupt()); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + videobuf_waiton(&buf->vb, 0, 0); +#else + videobuf_waiton(q, &buf->vb, 0, 0); +#endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + videobuf_dma_unmap(q, dma); +#else + videobuf_dma_unmap(q->dev, dma); +#endif + videobuf_dma_free(dma); + /* if no risc area allocated, btcx_riscmem_free just returns */ + btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +/* ------------------------------------------------------------------ */ +/* ------------- placeholders for later development ----------------- */ + +static int tw68_input_init1(struct tw68_dev *dev) +{ + return 0; +} + +static void tw68_input_fini(struct tw68_dev *dev) +{ + return; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) +{ + return; +} + +static void tw68_ir_stop(struct tw68_dev *dev) +{ + return; +} +#endif + +/* ------------------------------------------------------------------ */ +/* + * Buffer handling routines + * + * These routines are "generic", i.e. are intended to be used by more + * than one module, e.g. the video and the transport stream modules. + * To accomplish this generality, callbacks are used whenever some + * module-specific test or action is required. + */ + +/* resends a current buffer in queue after resume */ +int tw68_buffer_requeue(struct tw68_dev *dev, + struct tw68_dmaqueue *q) +{ + struct tw68_buf *buf, *prev; + + dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, + buf, buf->vb.i); + q->start_dma(dev, q, buf); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); + /* if nothing precedes this one */ + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + q->start_dma(dev, q, buf); + buf->activate(dev, buf, NULL); + dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", + __func__, buf, buf->vb.i); + + } else if (q->buf_compat(prev, buf) && + (prev->fmt == buf->fmt)) { + list_move_tail(&buf->vb.queue, &q->active); + buf->activate(dev, buf, NULL); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", + __func__, buf, buf->vb.i); + } else { + dprintk(DBG_BUFF, "%s: no action taken\n", __func__); + return 0; + } + prev = buf; + } +} + +/* nr of (tw68-)pages for the given buffer size */ +static int tw68_buffer_pages(int size) +{ + size = PAGE_ALIGN(size); + size += PAGE_SIZE; /* for non-page-aligned buffers */ + size /= 4096; + return size; +} + +/* calc max # of buffers from size (must not exceed the 4MB virtual + * address space per DMA channel) */ +int tw68_buffer_count(unsigned int size, unsigned int count) +{ + unsigned int maxcount; + + maxcount = 1024 / tw68_buffer_pages(size); + if (count > maxcount) + count = maxcount; + return count; +} + +/* + * tw68_wakeup + * + * Called when the driver completes filling a buffer, and tasks waiting + * for the data need to be awakened. + */ +void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) +{ + struct tw68_dev *dev = q->dev; + struct tw68_buf *buf; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (list_empty(&q->active)) { + dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", + __func__); + del_timer(&q->timeout); + return; + } + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + do_gettimeofday(&buf->vb.ts); + buf->vb.field_count = (*fc)++; + dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", + __func__, buf, buf->vb.i, *fc); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); +} + +/* + * tw68_buffer_queue + * + * Add specified buffer to specified queue + */ +void tw68_buffer_queue(struct tw68_dev *dev, + struct tw68_dmaqueue *q, + struct tw68_buf *buf) +{ + struct tw68_buf *prev; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + assert_spin_locked(&dev->slock); + dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); + + /* append a 'JUMP to stopper' to the buffer risc program */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + + /* if this buffer is not "compatible" (in dimensions and format) + * with the currently active chain of buffers, we must change + * settings before filling it; if a previous buffer has already + * been determined to require changes, this buffer must follow + * it. To do this, we maintain a "queued" chain. If that + * chain exists, append this buffer to it */ + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", + __func__, buf, buf->vb.i); + + /* else if the 'active' chain doesn't yet exist we create it now */ + } else if (list_empty(&q->active)) { + dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", + __func__, buf, buf->vb.i); + list_add_tail(&buf->vb.queue, &q->active); + q->start_dma(dev, q, buf); /* 1st one - start dma */ + /* TODO - why have we removed buf->count and q->count? */ + buf->activate(dev, buf, NULL); + + /* else we would like to put this buffer on the tail of the + * active chain, provided it is "compatible". */ + } else { + /* "compatibility" depends upon the type of buffer */ + prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); + if (q->buf_compat(prev, buf)) { + /* If "compatible", append to active chain */ + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* the param 'prev' is only for debug printing */ + buf->activate(dev, buf, prev); + list_add_tail(&buf->vb.queue, &q->active); + dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", + __func__, buf, buf->vb.i); + } else { + /* If "incompatible", append to queued chain */ + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " + "to queued\n", __func__, buf, buf->vb.i); + } + } +} + +/* + * tw68_buffer_timeout + * + * This routine is set as the video_q.timeout.function + * + * Log the event, try to reset the h/w. + * Flag the current buffer as failed, try to start again with next buff + */ +void tw68_buffer_timeout(unsigned long data) +{ + struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; + struct tw68_dev *dev = q->dev; + struct tw68_buf *buf; + unsigned long flags; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + spin_lock_irqsave(&dev->slock, flags); + + /* flag all current active buffers as failed */ + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct tw68_buf, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + dev->name, buf, buf->vb.i, + (unsigned long)buf->risc.dma); + } + tw68_buffer_requeue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +/* ------------------------------------------------------------------ */ +/* early init (no i2c, no irq) */ + +/* Called from tw68_hw_init1 and tw68_resume */ +static int tw68_hw_enable1(struct tw68_dev *dev) +{ + return 0; +} + +/* + * The device is given a "soft reset". According to the specifications, + * after this "all register content remain unchanged", so we also write + * to all specified registers manually as well (mostly to manufacturer's + * specified reset values) + */ +static int tw68_hw_init1(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + /* Assure all interrupts are disabled */ + tw_writel(TW68_INTMASK, 0); /* 020 */ + /* Clear any pending interrupts */ + tw_writel(TW68_INTSTAT, 0xffffffff); /* 01C */ + /* Stop risc processor, set default buffer level */ + tw_writel(TW68_DMAC, 0x1600); + + tw_writeb(TW68_ACNTL, 0x80); /* 218 soft reset */ + msleep(100); + + tw_writeb(TW68_INFORM, 0x40); /* 208 mux0, 27mhz xtal */ + tw_writeb(TW68_OPFORM, 0x04); /* 20C analog line-lock */ + tw_writeb(TW68_HSYNC, 0); /* 210 color-killer high sens */ + tw_writeb(TW68_ACNTL, 0x42); /* 218 int vref #2, chroma adc off */ + + tw_writeb(TW68_CROP_HI, 0x02); /* 21C Hactive m.s. bits */ + tw_writeb(TW68_VDELAY_LO, 0x12);/* 220 Mfg specified reset value */ + tw_writeb(TW68_VACTIVE_LO, 0xf0); + tw_writeb(TW68_HDELAY_LO, 0x0f); + tw_writeb(TW68_HACTIVE_LO, 0xd0); + + tw_writeb(TW68_CNTRL1, 0xcd); /* 230 Wide Chroma BPF B/W + * Secam reduction, Adap comb for + * NTSC, Op Mode 1 */ + + tw_writeb(TW68_VSCALE_LO, 0); /* 234 */ + tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */ + tw_writeb(TW68_HSCALE_LO, 0); /* 23c */ + tw_writeb(TW68_BRIGHT, 0); /* 240 */ + tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */ + tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */ + tw_writeb(TW68_SAT_U, 0x80); /* 24C */ + tw_writeb(TW68_SAT_V, 0x80); /* 250 */ + tw_writeb(TW68_HUE, 0x00); /* 254 */ + + /* TODO - Check that none of these are set by control defaults */ + tw_writeb(TW68_SHARP2, 0x53); /* 258 Mfg specified reset val */ + tw_writeb(TW68_VSHARP, 0x80); /* 25C Sharpness Coring val 8 */ + tw_writeb(TW68_CORING, 0x44); /* 260 CTI and Vert Peak coring */ + tw_writeb(TW68_CNTRL2, 0x00); /* 268 No power saving enabled */ + tw_writeb(TW68_SDT, 0x07); /* 270 Enable shadow reg, auto-det */ + tw_writeb(TW68_SDTR, 0x7f); /* 274 All stds recog, don't start */ + tw_writeb(TW68_CLMPG, 0x50); /* 280 Clamp end at 40 sys clocks */ + tw_writeb(TW68_IAGC, 0x22); /* 284 Mfg specified reset val */ + tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ + tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ + tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ +// tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ + tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ + tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ + tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ + /* Bit DETV of VCNTL1 helps sync multi cams/chip board */ + tw_writeb(TW68_VCNTL1, 0x04); /* 2A0 */ + tw_writeb(TW68_VCNTL2, 0); /* 2A4 */ + tw_writeb(TW68_CKILL, 0x68); /* 2A8 Mfg specified reset val */ + tw_writeb(TW68_COMB, 0x44); /* 2AC Mfg specified reset val */ + tw_writeb(TW68_LDLY, 0x30); /* 2B0 Max positive luma delay */ + tw_writeb(TW68_MISC1, 0x14); /* 2B4 Mfg specified reset val */ + tw_writeb(TW68_LOOP, 0xa5); /* 2B8 Mfg specified reset val */ + tw_writeb(TW68_MISC2, 0xe0); /* 2BC Enable colour killer */ + tw_writeb(TW68_MVSN, 0); /* 2C0 */ + tw_writeb(TW68_CLMD, 0x05); /* 2CC slice level auto, clamp med. */ + tw_writeb(TW68_IDCNTL, 0); /* 2D0 Writing zero to this register + * selects NTSC ID detection, + * but doesn't change the + * sensitivity (which has a reset + * value of 1E). Since we are + * not doing auto-detection, it + * has no real effect */ + tw_writeb(TW68_CLCNTL1, 0); /* 2D4 */ + tw_writel(TW68_VBIC, 0x03); /* 010 */ + tw_writel(TW68_CAP_CTL, 0x03); /* 040 Enable both even & odd flds */ + tw_writel(TW68_DMAC, 0x2000); /* patch set had 0x2080 */ + tw_writel(TW68_TESTREG, 0); /* 02C */ + + /* + * Some common boards, especially inexpensive single-chip models, + * use the GPIO bits 0-3 to control an on-board video-output mux. + * For these boards, we need to set up the GPIO register into + * "normal" mode, set bits 0-3 as output, and then set those bits + * zero. + * + * Eventually, it would be nice if we could identify these boards + * uniquely, and only do this initialisation if the board has been + * identify. For the moment, however, it shouldn't hurt anything + * to do these steps. + */ + tw_writel(TW68_GPIOC, 0); /* Set the GPIO to "normal", no ints */ + tw_writel(TW68_GPOE, 0x0f); /* Set bits 0-3 to "output" */ + tw_writel(TW68_GPDATA, 0); /* Set all bits to low state */ + + /* Initialize the device control structures */ + mutex_init(&dev->lock); + spin_lock_init(&dev->slock); + + /* Initialize any subsystems */ + tw68_video_init1(dev); + tw68_vbi_init1(dev); + if (card_has_mpeg(dev)) + tw68_ts_init1(dev); + tw68_input_init1(dev); + + /* Do any other h/w early initialisation at this point */ + tw68_hw_enable1(dev); + + return 0; +} + +/* late init (with i2c + irq) */ +static int tw68_hw_enable2(struct tw68_dev *dev) +{ + + dprintk(DBG_FLOW, "%s: called\n", __func__); +#ifdef TW68_TESTING + dev->pci_irqmask |= TW68_I2C_INTS; +#endif + tw_setl(TW68_INTMASK, dev->pci_irqmask); + return 0; +} + +static int tw68_hw_init2(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + tw68_video_init2(dev); /* initialise video function first */ + tw68_tvaudio_init2(dev);/* audio next */ + + /* all other board-related things, incl. enabling interrupts */ + tw68_hw_enable2(dev); + return 0; +} + +/* shutdown */ +static int tw68_hwfini(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (card_has_mpeg(dev)) + tw68_ts_fini(dev); + tw68_input_fini(dev); + tw68_vbi_fini(dev); + tw68_tvaudio_fini(dev); + return 0; +} + +static void __devinit must_configure_manually(void) +{ + unsigned int i, p; + + printk(KERN_WARNING + "tw68: \n" + "tw68: Congratulations! Your TV card vendor saved a few\n" + "tw68: cents for a eeprom, thus your pci board has no\n" + "tw68: subsystem ID and I can't identify it automatically\n" + "tw68: \n" + "tw68: I feel better now. Ok, here is the good news:\n" + "tw68: You can use the card= insmod option to specify\n" + "tw68: which board you have. The list:\n"); + for (i = 0; i < tw68_bcount; i++) { + printk(KERN_WARNING "tw68: card=%d -> %-40.40s", + i, tw68_boards[i].name); + for (p = 0; tw68_pci_tbl[p].driver_data; p++) { + if (tw68_pci_tbl[p].driver_data != i) + continue; + printk(" %04x:%04x", + tw68_pci_tbl[p].subvendor, + tw68_pci_tbl[p].subdevice); + } + printk("\n"); + } +} + + +static irqreturn_t tw68_irq(int irq, void *dev_id) +{ + struct tw68_dev *dev = dev_id; + u32 status, orig; + int loop; + + status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; + /* Check if anything to do */ + if (0 == status) + return IRQ_RETVAL(0); /* Nope - return */ + for (loop = 0; loop < 10; loop++) { + if (status & dev->board_virqmask) /* video interrupt */ + tw68_irq_video_done(dev, status); +#ifdef TW68_TESTING + if (status & TW68_I2C_INTS) + tw68_irq_i2c(dev, status); +#endif + status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; + if (0 == status) + goto out; + } + dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" + " (orig 0x%08x, cur 0x%08x)", + dev->name, orig, tw_readl(TW68_INTSTAT)); + dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " + "0x%08x ****\n", dev->name, + dev->pci_irqmask, dev->board_virqmask); + tw_clearl(TW68_INTMASK, dev->pci_irqmask); +out: + return IRQ_RETVAL(1); +} + +int tw68_set_dmabits(struct tw68_dev *dev) +{ + return 0; +} + +static struct video_device *vdev_init(struct tw68_dev *dev, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->parent = &dev->pci->dev; + vfd->release = video_device_release; + /* vfd->debug = tw_video_debug; */ + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + dev->name, type, tw68_boards[dev->board].name); + return vfd; +} + +static void tw68_unregister_video(struct tw68_dev *dev) +{ + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (dev->video_dev) { + if (-1 != dev->video_dev->minor) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + } + if (dev->vbi_dev) { + if (-1 != dev->vbi_dev->minor) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->radio_dev) { + if (-1 != dev->radio_dev->minor) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } +} + +static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, + struct tw68_dev *dev) +{ + int err; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + if (NULL != dev->mops) + return; + if (tw68_boards[dev->board].mpeg != ops->type) + return; + err = ops->init(dev); + if (0 != err) + return; + dev->mops = ops; +} + +static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, + struct tw68_dev *dev) +{ + + if (NULL == dev->mops) + return; + if (dev->mops != ops) + return; + dev->mops->fini(dev); + dev->mops = NULL; +} + +static int __devinit tw68_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct tw68_dev *dev; + struct tw68_mpeg_ops *mops; + int err; + + if (tw68_devcount == TW68_MAXBOARDS) + return -ENOMEM; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err) + goto fail0; + + /* pci init */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail1; + } + + dev->nr = tw68_devcount; + sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); + + /* pci quirks */ + if (pci_pci_problems) { + if (pci_pci_problems & PCIPCI_TRITON) + printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", + dev->name); + if (pci_pci_problems & PCIPCI_NATOMA) + printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", + dev->name); + if (pci_pci_problems & PCIPCI_VIAETBF) + printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", + dev->name); + if (pci_pci_problems & PCIPCI_VSFX) + printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", + dev->name); +#ifdef PCIPCI_ALIMAGIK + if (pci_pci_problems & PCIPCI_ALIMAGIK) { + printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " + "-- latency fixup\n", dev->name); + latency = 0x0A; + } +#endif + } + if (UNSET != latency) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + dev->name, latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); + } + + /* print pci info */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%llx\n", dev->name, + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, + (unsigned long long)pci_resource_start(pci_dev, 0)); + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { + printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); + err = -EIO; + goto fail1; + } + + switch (pci_id->device) { + case PCI_DEVICE_ID_6800: /* TW6800 */ + dev->vdecoder = TW6800; + dev->board_virqmask = TW68_VID_INTS; + break; + case PCI_DEVICE_ID_6801: /* Video decoder for TW6802 */ + dev->vdecoder = TW6801; + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ + dev->vdecoder = TW6804; + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + default: + dev->vdecoder = TWXXXX; /* To be announced */ + dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; + break; + } + /* board config */ + dev->board = pci_id->driver_data; + if (card[dev->nr] >= 0 && + card[dev->nr] < tw68_bcount) + dev->board = card[dev->nr]; + if (TW68_BOARD_NOAUTO == dev->board) { + must_configure_manually(); + dev->board = TW68_BOARD_UNKNOWN; + } + dev->autodetected = card[dev->nr] != dev->board; + dev->tuner_type = tw68_boards[dev->board].tuner_type; + dev->tuner_addr = tw68_boards[dev->board].tuner_addr; + dev->radio_type = tw68_boards[dev->board].radio_type; + dev->radio_addr = tw68_boards[dev->board].radio_addr; + dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; + if (UNSET != tuner[dev->nr]) + dev->tuner_type = tuner[dev->nr]; + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, pci_dev->subsystem_vendor, + pci_dev->subsystem_device, tw68_boards[dev->board].name, + dev->board, dev->autodetected ? + "autodetected" : "insmod option"); + + /* get mmio */ + if (!request_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0), + dev->name)) { + err = -EBUSY; + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + dev->name, + (unsigned long long)pci_resource_start(pci_dev, 0)); + goto fail1; + } + dev->lmmio = ioremap(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + dev->bmmio = (__u8 __iomem *)dev->lmmio; + if (NULL == dev->lmmio) { + err = -EIO; + printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + dev->name); + goto fail2; + } + /* initialize hardware #1 */ + /* First, take care of anything unique to a particular card */ + tw68_board_init1(dev); + /* Then do any initialisation wanted before interrupts are on */ + tw68_hw_init1(dev); + + /* get irq */ + err = request_irq(pci_dev->irq, tw68_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name, pci_dev->irq); + goto fail3; + } + +#ifdef TW68_TESTING + dev->pci_irqmask |= TW68_SBDONE; + tw_setl(TW68_INTMASK, dev->pci_irqmask); + printk(KERN_INFO "Calling tw68_i2c_register\n"); + /* Register the i2c bus */ + tw68_i2c_register(dev); +#endif + + /* + * Now do remainder of initialisation, first for + * things unique for this card, then for general board + */ + tw68_board_init2(dev); + + tw68_hw_init2(dev); + +#if 0 + /* load i2c helpers */ + if (card_is_empress(dev)) { + struct v4l2_subdev *sd = + v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", + "saa6752hs", 0x20); + + if (sd) + sd->grp_id = GRP_EMPRESS; + } + + request_submodules(dev); +#endif + + v4l2_prio_init(&dev->prio); + + mutex_lock(&tw68_devlist_lock); + list_for_each_entry(mops, &mops_list, next) + mpeg_ops_attach(mops, dev); + list_add_tail(&dev->devlist, &tw68_devlist); + mutex_unlock(&tw68_devlist_lock); + + /* check for signal */ + tw68_irq_video_signalchange(dev); + +#if 0 + if (TUNER_ABSENT != dev->tuner_type) + tw_call_all(dev, core, s_standby, 0); +#endif + + dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); + err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device video%d [v4l2]\n", + dev->name, dev->video_dev->num); + + dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); + + err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register vbi device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device vbi%d\n", + dev->name, dev->vbi_dev->num); + + if (card_has_radio(dev)) { + dev->radio_dev = vdev_init(dev, &tw68_radio_template, + "radio"); + err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->nr]); + if (err < 0) { + /* TODO - need to unregister vbi? */ + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device radio%d\n", + dev->name, dev->radio_dev->num); + } + + /* everything worked */ + tw68_devcount++; + + if (tw68_dmasound_init && !dev->dmasound.priv_data) + tw68_dmasound_init(dev); + + return 0; + + fail4: + tw68_unregister_video(dev); +#ifdef TW68_TESTING + tw68_i2c_unregister(dev); +#endif + free_irq(pci_dev->irq, dev); + fail3: + tw68_hwfini(dev); + iounmap(dev->lmmio); + fail2: + release_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + fail1: + v4l2_device_unregister(&dev->v4l2_dev); + fail0: + kfree(dev); + return err; +} + +static void __devexit tw68_finidev(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = + container_of(v4l2_dev, struct tw68_dev, v4l2_dev); + struct tw68_mpeg_ops *mops; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + /* Release DMA sound modules if present */ + if (tw68_dmasound_exit && dev->dmasound.priv_data) + tw68_dmasound_exit(dev); + + /* shutdown subsystems */ + tw68_hwfini(dev); + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + tw_writel(TW68_INTMASK, 0); + + /* unregister */ + mutex_lock(&tw68_devlist_lock); + list_del(&dev->devlist); + list_for_each_entry(mops, &mops_list, next) + mpeg_ops_detach(mops, dev); + mutex_unlock(&tw68_devlist_lock); + tw68_devcount--; + +#ifdef TW68_TESTING + tw68_i2c_unregister(dev); +#endif + tw68_unregister_video(dev); + + + /* the DMA sound modules should be unloaded before reaching + this, but just in case they are still present... */ + if (dev->dmasound.priv_data != NULL) { + free_irq(pci_dev->irq, &dev->dmasound); + dev->dmasound.priv_data = NULL; + } + + + /* release resources */ + free_irq(pci_dev->irq, dev); + iounmap(dev->lmmio); + release_mem_region(pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + + v4l2_device_unregister(&dev->v4l2_dev); + + /* free memory */ + kfree(dev); +} + +#ifdef CONFIG_PM + +static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = container_of(v4l2_dev, + struct tw68_dev, v4l2_dev); + + dprintk(DBG_FLOW, "%s: called\n", __func__); + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + dev->pci_irqmask &= ~TW68_VID_INTS; + tw_writel(TW68_INTMASK, 0); + + dev->insuspend = 1; + synchronize_irq(pci_dev->irq); + + /* Disable timeout timers - if we have active buffers, we will + fill them on resume*/ + + del_timer(&dev->video_q.timeout); + del_timer(&dev->vbi_q.timeout); + del_timer(&dev->ts_q.timeout); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (dev->remote) + tw68_ir_stop(dev); +#endif + + pci_save_state(pci_dev); + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + + return 0; +} + +static int tw68_resume(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct tw68_dev *dev = container_of(v4l2_dev, + struct tw68_dev, v4l2_dev); + unsigned long flags; + + dprintk(DBG_FLOW, "%s: called\n", __func__); + pci_set_power_state(pci_dev, PCI_D0); + pci_restore_state(pci_dev); + + /* Do things that are done in tw68_initdev , + except of initializing memory structures.*/ + + tw68_board_init1(dev); + + /* tw68_hw_init1 */ + if (tw68_boards[dev->board].video_out) + tw68_videoport_init(dev); + if (card_has_mpeg(dev)) + tw68_ts_init_hw(dev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (dev->remote) + tw68_ir_start(dev, dev->remote); +#endif + tw68_hw_enable1(dev); + + msleep(100); + + tw68_board_init2(dev); + + /*tw68_hw_init2*/ + tw68_set_tvnorm_hw(dev); + tw68_tvaudio_setmute(dev); +/* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ + tw68_tvaudio_init(dev); + tw68_irq_video_signalchange(dev); + + /*resume unfinished buffer(s)*/ + spin_lock_irqsave(&dev->slock, flags); + tw68_buffer_requeue(dev, &dev->video_q); + tw68_buffer_requeue(dev, &dev->vbi_q); + tw68_buffer_requeue(dev, &dev->ts_q); + + /* FIXME: Disable DMA audio sound - temporary till proper support + is implemented*/ + + dev->dmasound.dma_running = 0; + + /* start DMA now*/ + dev->insuspend = 0; + smp_wmb(); + tw68_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} +#endif + +/* ----------------------------------------------------------- */ + +static struct pci_driver tw68_pci_driver = { + .name = "tw68", + .id_table = tw68_pci_tbl, + .probe = tw68_initdev, + .remove = __devexit_p(tw68_finidev), +#ifdef CONFIG_PM + .suspend = tw68_suspend, + .resume = tw68_resume +#endif +}; + +static int tw68_init(void) +{ + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + INIT_LIST_HEAD(&tw68_devlist); + printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", + (TW68_VERSION_CODE >> 16) & 0xff, + (TW68_VERSION_CODE >> 8) & 0xff, + TW68_VERSION_CODE & 0xff); +#if 0 + printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&tw68_pci_driver); +} + +static void module_cleanup(void) +{ + if (core_debug & DBG_FLOW) + printk(KERN_DEBUG "%s: called\n", __func__); + pci_unregister_driver(&tw68_pci_driver); +} + +module_init(tw68_init); +module_exit(module_cleanup); diff --git a/drivers/media/pci/tw68/tw68-i2c.c b/drivers/media/pci/tw68/tw68-i2c.c new file mode 100644 index 000000000000..38659d0b1e18 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-i2c.c @@ -0,0 +1,245 @@ +/* + * tw68 code to handle the i2c interface. + * + * Much of this code is derived from the bt87x driver. The original + * work was by Gerd Knorr; more recently the code was enhanced by Mauro + * Carvalho Chehab. Their work is gratefully acknowledged. Full credit + * goes to them - any problems within this code are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "tw68.h" +#include +#include + +/*----------------------------------------------------------------*/ + +static unsigned int i2c_debug; +module_param(i2c_debug, int, 0644); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); + +#if 0 +static unsigned int i2c_scan; +module_param(i2c_scan, int, 0444); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); +#endif + +#define d1printk if (1 == i2c_debug) printk + +#define I2C_CLOCK 0xa6 /* 99.4 kHz */ + +/*----------------------------------------------------------------------*/ +/* Although the TW68xx i2c controller has a "hardware" mode, where all of + * the low-level i2c/smbbus is handled by the chip, it appears that mode + * is not suitable for linux i2c handling routines because extended "bursts" + * of data (sequences of bytes without intervening START/STOP bits) are + * not possible. Instead, we put the chip into "software" mode, and handle + * the i2c bus at a low level. To accomplish this, we use the routines + * from the i2c modules. + * + * Because the particular boards which I had for testing did not have any + * devices attached to the i2c bus, I have been unable to test these + * routines. + */ + +/*----------------------------------------------------------------------*/ +/* I2C functions - "bit-banging" adapter (software i2c) */ + +/* tw68_bit_setcl + * Handles "toggling" the i2c clock bit + */ +static void tw68_bit_setscl(void *data, int state) +{ + struct tw68_dev *dev = data; + + tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B); +} + +/* tw68_bit_setsda + * Handles "toggling" the i2c data bit + */ +static void tw68_bit_setsda(void *data, int state) +{ + struct tw68_dev *dev = data; + + tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B); +} + +/* tw68_bit_getscl + * + * Returns the current state of the clock bit + */ +static int tw68_bit_getscl(void *data) +{ + struct tw68_dev *dev = data; + + return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0; +} + +/* tw68_bit_getsda + * + * Returns the current state of the data bit + */ +static int tw68_bit_getsda(void *data) +{ + struct tw68_dev *dev = data; + + return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0; +} + +static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = { + .setsda = tw68_bit_setsda, + .setscl = tw68_bit_setscl, + .getsda = tw68_bit_getsda, + .getscl = tw68_bit_getscl, + .udelay = 16, + .timeout = 200, +}; + +static struct i2c_client tw68_client_template = { + .name = "tw68 internal", +}; + +/*----------------------------------------------------------------*/ + +static int attach_inform(struct i2c_client *client) +{ +/* struct tw68_dev *dev = client->adapter->algo_data; */ + + d1printk("%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, client->name); + + switch (client->addr) { + /* No info yet on what addresses to expect */ + } + + return 0; +} + +static struct i2c_adapter tw68_adap_sw_template = { + .owner = THIS_MODULE, + .name = "tw68_sw", + .client_register = attach_inform, +}; + +static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata, + int len) +{ + unsigned char buf; + int i, err; + + dev->i2c_client.addr = 0xa0 >> 1; + buf = 256 - len; + + err = i2c_master_send(&dev->i2c_client, &buf, 1); + if (1 != err) { + printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n", + dev->name, err); + return -1; + } + err = i2c_master_recv(&dev->i2c_client, eedata, len); + if (len != err) { + printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", + dev->name, err); + return -1; + } + + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + printk(KERN_INFO "%s: i2c eeprom %02x:", + dev->name, i); + printk(KERN_INFO " %02x", eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + return 0; +} + +#if 0 +static char *i2c_devs[128] = { + [0xa0 >> 1] = "eeprom", +}; + +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, 1); + if (rc < 0) + continue; + printk(KERN_INFO "%s: i2c scan: found device " + "@ 0x%x [%s]\n", name, i << 1, + i2c_devs[i] ? i2c_devs[i] : "???"); + } +} +#endif + +int __devinit tw68_i2c_register(struct tw68_dev *dev) +{ + int rc; + +printk(KERN_DEBUG "%s: Registering i2c module\n", __func__); + tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */ + + memcpy(&dev->i2c_client, &tw68_client_template, + sizeof(tw68_client_template)); + + memcpy(&dev->i2c_adap, &tw68_adap_sw_template, + sizeof(tw68_adap_sw_template)); + dev->i2c_adap.algo_data = &dev->i2c_algo; + dev->i2c_adap.dev.parent = &dev->pci->dev; + + memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template, + sizeof(tw68_i2c_algo_bit_template)); + dev->i2c_algo.data = dev; + /* TODO - may want to set better name (see bttv code) */ + + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + dev->i2c_client.adapter = &dev->i2c_adap; + + /* Assure chip is in "software" mode */ + tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK); + tw68_bit_setscl(dev, 1); + tw68_bit_setsda(dev, 1); + + rc = i2c_bit_add_bus(&dev->i2c_adap); + + tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); +#if 0 + if (i2c_scan) + do_i2c_scan(dev->name, &dev->i2c_client); +#endif + + return rc; +} + +int tw68_i2c_unregister(struct tw68_dev *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h new file mode 100644 index 000000000000..314bc43cd9d3 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-reg.h @@ -0,0 +1,195 @@ +/* + * tw68-reg.h - TW68xx register offsets + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) William M. Brack + * + * 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 _TW68_REG_H_ +#define _TW68_REG_H_ + +/* ---------------------------------------------------------------------- */ +#define TW68_DMAC 0x000 +#define TW68_DMAP_SA 0x004 +#define TW68_DMAP_EXE 0x008 +#define TW68_DMAP_PP 0x00c +#define TW68_VBIC 0x010 +#define TW68_SBUSC 0x014 +#define TW68_SBUSSD 0x018 +#define TW68_INTSTAT 0x01C +#define TW68_INTMASK 0x020 +#define TW68_GPIOC 0x024 +#define TW68_GPOE 0x028 +#define TW68_TESTREG 0x02C +#define TW68_SBUSRD 0x030 +#define TW68_SBUS_TRIG 0x034 +#define TW68_CAP_CTL 0x040 +#define TW68_SUBSYS 0x054 +#define TW68_I2C_RST 0x064 +#define TW68_VBIINST 0x06C +/* define bits in FIFO and DMAP Control reg */ +#define TW68_DMAP_EN (1 << 0) +#define TW68_FIFO_EN (1 << 1) +/* define the Interrupt Status Register bits */ +#define TW68_SBDONE (1 << 0) +#define TW68_DMAPI (1 << 1) +#define TW68_GPINT (1 << 2) +#define TW68_FFOF (1 << 3) +#define TW68_FDMIS (1 << 4) +#define TW68_DMAPERR (1 << 5) +#define TW68_PABORT (1 << 6) +#define TW68_SBDONE2 (1 << 12) +#define TW68_SBERR2 (1 << 13) +#define TW68_PPERR (1 << 14) +#define TW68_FFERR (1 << 15) +#define TW68_DET50 (1 << 16) +#define TW68_FLOCK (1 << 17) +#define TW68_CCVALID (1 << 18) +#define TW68_VLOCK (1 << 19) +#define TW68_FIELD (1 << 20) +#define TW68_SLOCK (1 << 21) +#define TW68_HLOCK (1 << 22) +#define TW68_VDLOSS (1 << 23) +#define TW68_SBERR (1 << 24) +/* define the i2c control register bits */ +#define TW68_SBMODE (0) +#define TW68_WREN (1) +#define TW68_SSCLK (6) +#define TW68_SSDAT (7) +#define TW68_SBCLK (8) +#define TW68_WDLEN (16) +#define TW68_RDLEN (20) +#define TW68_SBRW (24) +#define TW68_SBDEV (25) + +#define TW68_SBMODE_B (1 << TW68_SBMODE) +#define TW68_WREN_B (1 << TW68_WREN) +#define TW68_SSCLK_B (1 << TW68_SSCLK) +#define TW68_SSDAT_B (1 << TW68_SSDAT) +#define TW68_SBRW_B (1 << TW68_SBRW) + +#define TW68_GPDATA 0x100 +#define TW68_STATUS1 0x204 +#define TW68_INFORM 0x208 +#define TW68_OPFORM 0x20C +#define TW68_HSYNC 0x210 +#define TW68_ACNTL 0x218 +#define TW68_CROP_HI 0x21C +#define TW68_VDELAY_LO 0x220 +#define TW68_VACTIVE_LO 0x224 +#define TW68_HDELAY_LO 0x228 +#define TW68_HACTIVE_LO 0x22C +#define TW68_CNTRL1 0x230 +#define TW68_VSCALE_LO 0x234 +#define TW68_SCALE_HI 0x238 +#define TW68_HSCALE_LO 0x23C +#define TW68_BRIGHT 0x240 +#define TW68_CONTRAST 0x244 +#define TW68_SHARPNESS 0x248 +#define TW68_SAT_U 0x24C +#define TW68_SAT_V 0x250 +#define TW68_HUE 0x254 +#define TW68_SHARP2 0x258 +#define TW68_VSHARP 0x25C +#define TW68_CORING 0x260 +#define TW68_VBICNTL 0x264 +#define TW68_CNTRL2 0x268 +#define TW68_CC_DATA 0x26C +#define TW68_SDT 0x270 +#define TW68_SDTR 0x274 +#define TW68_RESERV2 0x278 +#define TW68_RESERV3 0x27C +#define TW68_CLMPG 0x280 +#define TW68_IAGC 0x284 +#define TW68_AGCGAIN 0x288 +#define TW68_PEAKWT 0x28C +#define TW68_CLMPL 0x290 +#define TW68_SYNCT 0x294 +#define TW68_MISSCNT 0x298 +#define TW68_PCLAMP 0x29C +#define TW68_VCNTL1 0x2A0 +#define TW68_VCNTL2 0x2A4 +#define TW68_CKILL 0x2A8 +#define TW68_COMB 0x2AC +#define TW68_LDLY 0x2B0 +#define TW68_MISC1 0x2B4 +#define TW68_LOOP 0x2B8 +#define TW68_MISC2 0x2BC +#define TW68_MVSN 0x2C0 +#define TW68_STATUS2 0x2C4 +#define TW68_HFREF 0x2C8 +#define TW68_CLMD 0x2CC +#define TW68_IDCNTL 0x2D0 +#define TW68_CLCNTL1 0x2D4 + +/* Audio */ +#define TW68_ACKI1 0x300 +#define TW68_ACKI2 0x304 +#define TW68_ACKI3 0x308 +#define TW68_ACKN1 0x30C +#define TW68_ACKN2 0x310 +#define TW68_ACKN3 0x314 +#define TW68_SDIV 0x318 +#define TW68_LRDIV 0x31C +#define TW68_ACCNTL 0x320 + +#define TW68_VSCTL 0x3B8 +#define TW68_CHROMAGVAL 0x3BC + +#define TW68_F2CROP_HI 0x3DC +#define TW68_F2VDELAY_LO 0x3E0 +#define TW68_F2VACTIVE_LO 0x3E4 +#define TW68_F2HDELAY_LO 0x3E8 +#define TW68_F2HACTIVE_LO 0x3EC +#define TW68_F2CNT 0x3F0 +#define TW68_F2VSCALE_LO 0x3F4 +#define TW68_F2SCALE_HI 0x3F8 +#define TW68_F2HSCALE_LO 0x3FC + +#define RISC_INT_BIT 0x08000000 +#define RISC_SYNCO 0xC0000000 +#define RISC_SYNCE 0xD0000000 +#define RISC_JUMP 0xB0000000 +#define RISC_LINESTART 0x90000000 +#define RISC_INLINE 0xA0000000 + +#define VideoFormatNTSC 0 +#define VideoFormatNTSCJapan 0 +#define VideoFormatPALBDGHI 1 +#define VideoFormatSECAM 2 +#define VideoFormatNTSC443 3 +#define VideoFormatPALM 4 +#define VideoFormatPALN 5 +#define VideoFormatPALNC 5 +#define VideoFormatPAL60 6 +#define VideoFormatAuto 7 + +#define ColorFormatRGB32 0x00 +#define ColorFormatRGB24 0x10 +#define ColorFormatRGB16 0x20 +#define ColorFormatRGB15 0x30 +#define ColorFormatYUY2 0x40 +#define ColorFormatBSWAP 0x04 +#define ColorFormatWSWAP 0x08 +#define ColorFormatGamma 0x80 +#endif diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c new file mode 100644 index 000000000000..66273bbd51c5 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -0,0 +1,268 @@ +/* + * tw68_risc.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tw68.h" + +#define NO_SYNC_LINE (-1U) + +/** + * @rp pointer to current risc program position + * @sglist pointer to "scatter-gather list" of buffer pointers + * @offset offset to target memory buffer + * @sync_line 0 -> no sync, 1 -> odd sync, 2 -> even sync + * @bpl number of bytes per scan line + * @padding number of bytes of padding to add + * @lines number of lines in field + * @lpi lines per IRQ, or 0 to not generate irqs + * Note: IRQ to be generated _after_ lpi lines are transferred + */ +static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines, unsigned int lpi) +{ + struct scatterlist *sg; + unsigned int line, todo, done; + + /* sync instruction */ + if (sync_line != NO_SYNC_LINE) { + if (sync_line == 1) + *(rp++) = cpu_to_le32(RISC_SYNCO); + else + *(rp++) = cpu_to_le32(RISC_SYNCE); + *(rp++) = 0; + } + /* scan lines */ + sg = sglist; + for (line = 0; line < lines; line++) { + /* calculate next starting position */ + 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(RISC_LINESTART | + /* (offset<<12) |*/ bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + offset += bpl; + } else { + /* + * scanline needs to be split. Put the start in + * whatever memory remains using RISC_LINESTART, + * then the remainder into following addresses + * given by the scatter-gather list. + */ + todo = bpl; /* one full line to be done */ + /* first fragment */ + done = (sg_dma_len(sg) - offset); + *(rp++) = cpu_to_le32(RISC_LINESTART | + (7 << 24) | + done); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + todo -= done; + sg++; + /* succeeding fragments have no offset */ + while (todo > sg_dma_len(sg)) { + *(rp++) = cpu_to_le32(RISC_INLINE | + (done << 12) | + sg_dma_len(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + todo -= sg_dma_len(sg); + sg++; + done += sg_dma_len(sg); + } + if (todo) { + /* final chunk - offset 0, count 'todo' */ + *(rp++) = cpu_to_le32(RISC_INLINE | + (done << 12) | + todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); + } + offset = todo; + } + offset += padding; + /* If this line needs an interrupt, put it in */ + if (lpi && line > 0 && !(line % lpi)) + *(rp-2) |= RISC_INT_BIT; + } + + return rp; +} + +/** + * tw68_risc_buffer + * + * This routine is called by tw68-video. It allocates + * memory for the dma controller "program" and then fills in that + * memory with the appropriate "instructions". + * + * @pci_dev structure with info about the pci + * slot which our device is in. + * @risc structure with info about the memory + * used for our controller program. + * @sglist scatter-gather list entry + * @top_offset offset within the risc program area for the + * first odd frame line + * @bottom_offset offset within the risc program area for the + * first even frame line + * @bpl number of data bytes per scan line + * @padding number of extra bytes to add at end of line + * @lines number of scan lines + */ +int tw68_risc_buffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, + unsigned int bottom_offset, + unsigned int bpl, + unsigned int padding, + unsigned int lines) +{ + u32 instructions, fields; + __le32 *rp; + int rc; + + fields = 0; + if (UNSET != top_offset) + fields++; + if (UNSET != bottom_offset) + fields++; + /* + * estimate risc mem: worst case is one write per page border + + * one write per scan line + syncs + 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 = fields * (1 + (((bpl + padding) * lines) / + PAGE_SIZE) + lines) + 2; + rc = btcx_riscmem_alloc(pci, risc, instructions * 8); + if (rc < 0) + return rc; + + /* write risc instructions */ + rp = risc->cpu; + if (UNSET != top_offset) /* generates SYNCO */ + rp = tw68_risc_field(rp, sglist, top_offset, 1, + bpl, padding, lines, 0); + if (UNSET != bottom_offset) /* generates SYNCE */ + rp = tw68_risc_field(rp, sglist, bottom_offset, 2, + bpl, padding, lines, 0); + + /* save pointer to jmp instruction address */ + risc->jmp = rp; + /* assure risc buffer hasn't overflowed */ + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + return 0; +} + +#if 0 +/* ------------------------------------------------------------------ */ +/* debug helper code */ + +static void tw68_risc_decode(u32 risc, u32 addr) +{ +#define RISC_OP(reg) (((reg) >> 28) & 7) + static struct instr_details { + char *name; + u8 has_data_type; + u8 has_byte_info; + u8 has_addr; + } instr[8] = { + [RISC_OP(RISC_SYNCO)] = {"syncOdd", 0, 0, 0}, + [RISC_OP(RISC_SYNCE)] = {"syncEven", 0, 0, 0}, + [RISC_OP(RISC_JUMP)] = {"jump", 0, 0, 1}, + [RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1}, + [RISC_OP(RISC_INLINE)] = {"inline", 1, 1, 1}, + }; + u32 p; + + p = RISC_OP(risc); + if (!(risc & 0x80000000) || !instr[p].name) { + printk(KERN_DEBUG "0x%08x [ INVALID ]\n", risc); + return; + } + printk(KERN_DEBUG "0x%08x %-9s IRQ=%d", + risc, instr[p].name, (risc >> 27) & 1); + if (instr[p].has_data_type) + printk(KERN_DEBUG " Type=%d", (risc >> 24) & 7); + if (instr[p].has_byte_info) + printk(KERN_DEBUG " Start=0x%03x Count=%03u", + (risc >> 12) & 0xfff, risc & 0xfff); + if (instr[p].has_addr) + printk(KERN_DEBUG " StartAddr=0x%08x", addr); + printk(KERN_DEBUG "\n"); +} + +void tw68_risc_program_dump(struct tw68_core *core, + struct btcx_riscmem *risc) +{ + __le32 *addr; + + printk(KERN_DEBUG "%s: risc_program_dump: risc=%p, " + "risc->cpu=0x%p, risc->jmp=0x%p\n", + core->name, risc, risc->cpu, risc->jmp); + for (addr = risc->cpu; addr <= risc->jmp; addr += 2) + tw68_risc_decode(*addr, *(addr+1)); +} +EXPORT_SYMBOL_GPL(tw68_risc_program_dump); +#endif + +/* + * tw68_risc_stopper + * Normally, the risc code generated for a buffer ends with a + * JUMP instruction to direct the DMAP processor to the code for + * the next buffer. However, when there is no additional buffer + * currently available, the code instead jumps to this routine. + * + * My first try for a "stopper" program was just a simple + * "jump to self" instruction. Unfortunately, this caused the + * video FIFO to overflow. My next attempt was to just disable + * the DMAP processor. Unfortunately, this caused the video + * decoder to lose its synchronization. The solution to this was to + * add a "Sync-Odd" instruction, which "eats" all the video data + * until the start of the next odd field. + */ +int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc) +{ + __le32 *rp; + int rc; + + rc = btcx_riscmem_alloc(pci, risc, 8*4); + if (rc < 0) + return rc; + + /* write risc inststructions */ + rp = risc->cpu; + *(rp++) = cpu_to_le32(RISC_SYNCO); + *(rp++) = 0; + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(risc->dma); + risc->jmp = risc->cpu; + return 0; +} diff --git a/drivers/media/pci/tw68/tw68-ts.c b/drivers/media/pci/tw68/tw68-ts.c new file mode 100644 index 000000000000..dacd6e621bae --- /dev/null +++ b/drivers/media/pci/tw68/tw68-ts.c @@ -0,0 +1,66 @@ +/* + * tw68_ts.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tw68.h" + +int tw68_ts_init1(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_ts_ini(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_ts_fini(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status) +{ + return; +} + +int tw68_ts_register(struct tw68_mpeg_ops *ops) +{ + return 0; +} + +void tw68_ts_unregister(struct tw68_mpeg_ops *ops) +{ + return; +} + +int tw68_ts_init_hw(struct tw68_dev *dev) +{ + return 0; +} + + diff --git a/drivers/media/pci/tw68/tw68-tvaudio.c b/drivers/media/pci/tw68/tw68-tvaudio.c new file mode 100644 index 000000000000..656d462196f4 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-tvaudio.c @@ -0,0 +1,80 @@ +/* + * tw68_controls.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tw68.h" + +int tw68_tvaudio_rx2mode(u32 rx) +{ + return 0; +} + +void tw68_tvaudio_setmute(struct tw68_dev *dev) +{ + return; +} + +void tw68_tvaudio_setinput(struct tw68_dev *dev, struct tw68_input *in) +{ + return; +} + +void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level) +{ + return; +} + +int tw68_tvaudio_getstereo(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_tvaudio_init(struct tw68_dev *dev) +{ + return; +} + +int tw68_tvaudio_init2(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_tvaudio_fini(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_tvaudio_do_scan(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_enable_i2s(struct tw68_dev *dev) +{ + return; +} + diff --git a/drivers/media/pci/tw68/tw68-vbi.c b/drivers/media/pci/tw68/tw68-vbi.c new file mode 100644 index 000000000000..fbad3b998848 --- /dev/null +++ b/drivers/media/pci/tw68/tw68-vbi.c @@ -0,0 +1,76 @@ +/* + * tw68_controls.c + * Part of the device driver for Techwell 68xx based cards + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "tw68.h" + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) { + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); + return 0; +} +static int buffer_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, + enum v4l2_field field) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); + return 0; +} +static void buffer_queue(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); +} +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + printk(KERN_INFO "%s: shouldn't be here!\n", __func__); +} +struct videobuf_queue_ops tw68_vbi_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +int tw68_vbi_init1(struct tw68_dev *dev) +{ + return 0; +} + +int tw68_vbi_fini(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status) +{ + return; +} + diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c new file mode 100644 index 000000000000..ca08ca38d3bd --- /dev/null +++ b/drivers/media/pci/tw68/tw68-video.c @@ -0,0 +1,2230 @@ +/* + * tw68 functions to handle video data + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "tw68.h" +#include "tw68-reg.h" + +unsigned int video_debug; + +static unsigned int gbuffers = 8; +static unsigned int noninterlaced; /* 0 */ +static unsigned int gbufsz = 768*576*4; +static unsigned int gbufsz_max = 768*576*4; +static char secam[] = "--"; + +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); +module_param(gbuffers, int, 0444); +MODULE_PARM_DESC(gbuffers, "number of capture buffers, range 2-32"); +module_param(noninterlaced, int, 0644); +MODULE_PARM_DESC(noninterlaced, "capture non interlaced video"); +module_param_string(secam, secam, sizeof(secam), 0644); +MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); + +#define dprintk(level, fmt, arg...) if (video_debug & (level)) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) + +/* ------------------------------------------------------------------ */ +/* data structs for video */ +/* + * FIXME - + * Note that the saa7134 has formats, e.g. YUV420, which are classified + * as "planar". These affect overlay mode, and are flagged with a field + * ".planar" in the format. Do we need to implement this in this driver? + */ +static struct tw68_format formats[] = { + { + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = 16, + .twformat = ColorFormatRGB15, + }, { + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .twformat = ColorFormatRGB15 | ColorFormatBSWAP, + }, { + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .twformat = ColorFormatRGB16, + }, { + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .twformat = ColorFormatRGB16 | ColorFormatBSWAP, + }, { + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .twformat = ColorFormatRGB24, + }, { + .name = "24 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .twformat = ColorFormatRGB24 | ColorFormatBSWAP, + }, { + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, + .twformat = ColorFormatRGB32, + }, { + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .twformat = ColorFormatRGB32 | ColorFormatBSWAP | + ColorFormatWSWAP, + }, { + .name = "4:2:2 packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .twformat = ColorFormatYUY2, + }, { + .name = "4:2:2 packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .twformat = ColorFormatYUY2 | ColorFormatBSWAP, + } +}; +#define FORMATS ARRAY_SIZE(formats) + +#define NORM_625_50 \ + .h_delay = 3, \ + .h_delay0 = 133, \ + .h_start = 0, \ + .h_stop = 719, \ + .v_delay = 24, \ + .vbi_v_start_0 = 7, \ + .vbi_v_stop_0 = 22, \ + .video_v_start = 24, \ + .video_v_stop = 311, \ + .vbi_v_start_1 = 319 + +#define NORM_525_60 \ + .h_delay = 8, \ + .h_delay0 = 138, \ + .h_start = 0, \ + .h_stop = 719, \ + .v_delay = 22, \ + .vbi_v_start_0 = 10, \ + .vbi_v_stop_0 = 21, \ + .video_v_start = 22, \ + .video_v_stop = 262, \ + .vbi_v_start_1 = 273 + +/* + * The following table is searched by tw68_s_std, first for a specific + * match, then for an entry which contains the desired id. The table + * entries should therefore be ordered in ascending order of specificity. + */ +static struct tw68_tvnorm tvnorms[] = { + { + .name = "PAL-BG", + .id = V4L2_STD_PAL_BG, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL-I", + .id = V4L2_STD_PAL_I, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL-DK", + .id = V4L2_STD_PAL_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "PAL", /* autodetect */ + .id = V4L2_STD_PAL, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0x89, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatNTSC, + + }, { + .name = "SECAM-DK", + .id = V4L2_STD_SECAM_DK, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM-L", + .id = V4L2_STD_SECAM_L, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM-LC", + .id = V4L2_STD_SECAM_LC, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x1b, + .chroma_ctrl1 = 0xd1, + .chroma_gain = 0x80, + .chroma_ctrl2 = 0x00, + .vgate_misc = 0x1c, + .format = VideoFormatSECAM, + + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0xb9, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatPALM, + + }, { + .name = "PAL-Nc", + .id = V4L2_STD_PAL_Nc, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0xa1, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALNC, + + }, { + .name = "PAL-60", + .id = V4L2_STD_PAL_60, + .h_delay = 186, + .h_start = 0, + .h_stop = 719, + .v_delay = 26, + .video_v_start = 23, + .video_v_stop = 262, + .vbi_v_start_0 = 10, + .vbi_v_stop_0 = 21, + .vbi_v_start_1 = 273, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPAL60, + + }, { +/* + * FIXME: The following are meant to be "catch-all", and need + * to be further thought out! + */ + .name = "STD-525-60", + .id = V4L2_STD_525_60, + NORM_525_60, + + .sync_control = 0x59, + .luma_control = 0x40, + .chroma_ctrl1 = 0x89, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x0e, + .vgate_misc = 0x18, + .format = VideoFormatNTSC, + + }, { + .name = "STD-625-50", + .id = V4L2_STD_625_50, + NORM_625_50, + + .sync_control = 0x18, + .luma_control = 0x40, + .chroma_ctrl1 = 0x81, + .chroma_gain = 0x2a, + .chroma_ctrl2 = 0x06, + .vgate_misc = 0x1c, + .format = VideoFormatPALBDGHI, + } +}; +#define TVNORMS ARRAY_SIZE(tvnorms) + +static const struct v4l2_queryctrl no_ctrl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; +static const struct v4l2_queryctrl video_ctrls[] = { + /* --- video --- */ + { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 20, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 100, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 128, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = -128, + .maximum = 127, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_COLOR_KILLER, + .name = "Color Killer", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_CHROMA_AGC, + .name = "Chroma AGC", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + /* --- audio --- */ + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = -15, + .maximum = 15, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; +static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); + +/* + * Routine to lookup a control by its ID, and return a pointer + * to the entry in the video_ctrls array for that control. + */ +static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +{ + unsigned int i; + + for (i = 0; i < CTRLS; i++) + if (video_ctrls[i].id == id) + return video_ctrls+i; + return NULL; +} + +static struct tw68_format *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < FORMATS; i++) + if (formats[i].fourcc == fourcc) + return formats+i; + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct tw68_fh *fh, unsigned int bit) +{ + struct tw68_dev *dev = fh->dev; + + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&fh->dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(DBG_FLOW, "%s: %d\n", __func__, bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct tw68_fh *fh, unsigned int bit) +{ + return fh->resources & bit; +} + +static int res_locked(struct tw68_dev *dev, unsigned int bit) +{ + return dev->resources & bit; +} + +static void res_free(struct tw68_fh *fh, + unsigned int bits) +{ + struct tw68_dev *dev = fh->dev; + + BUG_ON((fh->resources & bits) != bits); + + mutex_lock(&fh->dev->lock); + fh->resources &= ~bits; + fh->dev->resources &= ~bits; + dprintk(DBG_FLOW, "%s: %d\n", __func__, bits); + mutex_unlock(&fh->dev->lock); +} + +/* ------------------------------------------------------------------ */ +/* + * Note that the cropping rectangles are described in terms of a single + * frame, i.e. line positions are only 1/2 the interlaced equivalent + */ +static void set_tvnorm(struct tw68_dev *dev, struct tw68_tvnorm *norm) +{ + dprintk(DBG_FLOW, "%s: %s\n", __func__, norm->name); + dev->tvnorm = norm; + + /* setup cropping */ + dev->crop_bounds.left = norm->h_start; + dev->crop_defrect.left = norm->h_start; + dev->crop_bounds.width = norm->h_stop - norm->h_start + 1; + dev->crop_defrect.width = norm->h_stop - norm->h_start + 1; + + dev->crop_bounds.top = norm->video_v_start; + dev->crop_defrect.top = norm->video_v_start; + dev->crop_bounds.height = (((norm->id & V4L2_STD_525_60) ? + 524 : 624)) / 2 - dev->crop_bounds.top; + dev->crop_defrect.height = (norm->video_v_stop - + norm->video_v_start + 1); + + dev->crop_current = dev->crop_defrect; + + if (norm != dev->tvnorm) { + dev->tvnorm = norm; + tw68_set_tvnorm_hw(dev); + } +} + +static void video_mux(struct tw68_dev *dev, int input) +{ + dprintk(DBG_FLOW, "%s: input = %d [%s]\n", __func__, input, + card_in(dev, input).name); + /* + * dev->input shows current application request, + * dev->hw_input shows current hardware setting + */ + dev->input = &card_in(dev, input); + tw68_tvaudio_setinput(dev, &card_in(dev, input)); +} + +/* + * tw68_set_scale + * + * Scaling and Cropping for video decoding + * + * We are working with 3 values for horizontal and vertical - scale, + * delay and active. + * + * HACTIVE represent the actual number of pixels in the "usable" image, + * before scaling. HDELAY represents the number of pixels skipped + * between the start of the horizontal sync and the start of the image. + * HSCALE is calculated using the formula + * HSCALE = (HACTIVE / (#pixels desired)) * 256 + * + * The vertical registers are similar, except based upon the total number + * of lines in the image, and the first line of the image (i.e. ignoring + * vertical sync and VBI). + * + * Note that the number of bytes reaching the FIFO (and hence needing + * to be processed by the DMAP program) is completely dependent upon + * these values, especially HSCALE. + * + * Parameters: + * @dev pointer to the device structure, needed for + * getting current norm (as well as debug print) + * @width actual image width (from user buffer) + * @height actual image height + * @field indicates Top, Bottom or Interlaced + */ +static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field) +{ + + /* set individually for debugging clarity */ + int hactive, hdelay, hscale; + int vactive, vdelay, vscale; + int comb; + + if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ + height /= 2; /* we must set for 1-frame */ + + dprintk(DBG_FLOW, "%s: width=%d, height=%d, both=%d\n Crop rect: " + "top=%d, left=%d, width=%d height=%d\n" + " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " + "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, + width, height, V4L2_FIELD_HAS_BOTH(field), + dev->crop_bounds.top, dev->crop_bounds.left, + dev->crop_bounds.width, dev->crop_bounds.height, + dev->tvnorm->h_delay, dev->tvnorm->h_start, dev->tvnorm->h_stop, + dev->tvnorm->v_delay, dev->tvnorm->video_v_start, + dev->tvnorm->video_v_stop); + + switch (dev->vdecoder) { + case TW6800: + hdelay = dev->tvnorm->h_delay0; + break; + default: + hdelay = dev->tvnorm->h_delay; + break; + } + hdelay += dev->crop_bounds.left; + hactive = dev->crop_bounds.width; + + hscale = (hactive * 256) / (width); + + vdelay = dev->tvnorm->v_delay + dev->crop_bounds.top - + dev->crop_defrect.top; + vactive = dev->crop_bounds.height; + vscale = (vactive * 256) / height; + + dprintk(DBG_FLOW, "%s: %dx%d [%s%s,%s]\n", __func__, + width, height, + V4L2_FIELD_HAS_TOP(field) ? "T" : "", + V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", + v4l2_norm_to_name(dev->tvnorm->id)); + dprintk(DBG_FLOW, "%s: hactive=%d, hdelay=%d, hscale=%d; " + "vactive=%d, vdelay=%d, vscale=%d\n", __func__, + hactive, hdelay, hscale, vactive, vdelay, vscale); + + comb = ((vdelay & 0x300) >> 2) | + ((vactive & 0x300) >> 4) | + ((hdelay & 0x300) >> 6) | + ((hactive & 0x300) >> 8); + dprintk(DBG_FLOW, "%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " + "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", + __func__, comb, vdelay, vactive, hdelay, hactive); + tw_writeb(TW68_CROP_HI, comb); + tw_writeb(TW68_VDELAY_LO, vdelay & 0xff); + tw_writeb(TW68_VACTIVE_LO, vactive & 0xff); + tw_writeb(TW68_HDELAY_LO, hdelay & 0xff); + tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); + + comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); + dprintk(DBG_FLOW, "%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " + "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); + tw_writeb(TW68_SCALE_HI, comb); + tw_writeb(TW68_VSCALE_LO, vscale); + tw_writeb(TW68_HSCALE_LO, hscale); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, + struct tw68_buf *buf) { + + dprintk(DBG_FLOW, "%s: Starting risc program\n", __func__); + /* Assure correct input */ + if (dev->hw_input != dev->input) { + dev->hw_input = dev->input; + tw_andorb(TW68_INFORM, 0x03 << 2, dev->input->vmux << 2); + } + /* Set cropping and scaling */ + tw68_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + /* + * Set start address for RISC program. Note that if the DMAP + * processor is currently running, it must be stopped before + * a new address can be set. + */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN); + tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->risc.dma)); + /* Clear any pending interrupts */ + tw_writel(TW68_INTSTAT, dev->board_virqmask); + /* Enable the risc engine and the fifo */ + tw_andorl(TW68_DMAC, 0xff, buf->fmt->twformat | + ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); + dev->pci_irqmask |= dev->board_virqmask; + tw_setl(TW68_INTMASK, dev->pci_irqmask); + return 0; +} + +/* ------------------------------------------------------------------ */ +/* videobuf queue operations */ + +/* + * check_buf_fmt + * + * callback from tw68-core buffer_queue to determine whether the + * current buffer and the previous one are "compatible" (i.e. the + * risc programs can be chained without requiring a format change) + */ +static int tw68_check_video_fmt(struct tw68_buf *prev, struct tw68_buf *buf) +{ + return (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt); +} + +/* + * buffer_setup + * + * Calculate required size of buffer and maximum number allowed + */ +static int +buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct tw68_fh *fh = q->priv_data; + + *size = fh->fmt->depth * fh->width * fh->height >> 3; + if (0 == *count) + *count = gbuffers; + *count = tw68_buffer_count(*size, *count); + return 0; +} + +static int buffer_activate(struct tw68_dev *dev, struct tw68_buf *buf, + struct tw68_buf *next) +{ + dprintk(DBG_BUFF, "%s: dev=%p, buf=%p, next=%p\n", + __func__, dev, buf, next); + if (dev->hw_input != dev->input) { + dev->hw_input = dev->input; + tw_andorb(TW68_INFORM, 0x03 << 2, + dev->hw_input->vmux << 2); + } + buf->vb.state = VIDEOBUF_ACTIVE; + /* TODO - need to assure scaling/cropping are set correctly */ + mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +/* +* buffer_prepare +* +* Set the ancilliary information into the buffer structure. This +* includes generating the necessary risc program if it hasn't already +* been done for the current buffer format. +* The structure fh contains the details of the format requested by the +* user - type, width, height and #fields. This is compared with the +* last format set for the current buffer. If they differ, the risc +* code (which controls the filling of the buffer) is (re-)generated. +*/ +static int +buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct tw68_fh *fh = q->priv_data; + struct tw68_dev *dev = fh->dev; + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int rc, init_buffer = 0; + unsigned int maxw, maxh; + + BUG_ON(NULL == fh->fmt); + maxw = dev->tvnorm->h_stop - dev->tvnorm->h_start + 1; + maxh = 2*(dev->tvnorm->video_v_stop - dev->tvnorm->video_v_start + 1); + if (fh->width < 48 || fh->width > maxw || fh->height > maxh + || fh->height < 16) { + dprintk(DBG_UNEXPECTED, "%s: invalid dimensions - " + "fh->width=%d, fh->height=%d, maxw=%d, maxh=%d\n", + __func__, fh->width, fh->height, maxw, maxh); + return -EINVAL; + } + buf->vb.size = (fh->width * fh->height * (fh->fmt->depth)) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + dprintk(DBG_BUFF, "%s: buf - fmt=%p, width=%3d, height=%3d, " + "field=%d\n%s: fh - fmt=%p, width=%3d, height=%3d, " + "field=%d\n", __func__, buf->fmt, buf->vb.width, + buf->vb.height, buf->vb.field, __func__, fh->fmt, + fh->width, fh->height, field); + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; /* force risc code re-generation */ + } + buf->input = dev->input; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + init_buffer = 1; /* force risc code re-generation */ + } + dprintk(DBG_BUFF, "%s: q=%p, vb=%p, init_buffer=%d\n", + __func__, q, vb, init_buffer); + + if (init_buffer) { + buf->bpl = buf->vb.width * (buf->fmt->depth) >> 3; + dprintk(DBG_TESTING, "%s: Generating new risc code " + "[%dx%dx%d](%d)\n", __func__, buf->vb.width, + buf->vb.height, buf->fmt->depth, buf->bpl); + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, UNSET, + buf->bpl, 0, + buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + UNSET, 0, + buf->bpl, 0, + buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + tw68_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(DBG_BUFF, "%s: [%p/%d] - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + __func__, buf, buf->vb.i, fh->width, fh->height, + fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + buf->activate = buffer_activate; + return 0; + + fail: + tw68_dma_free(q, buf); + return rc; +} + +/* + * buffer_queue + * + * Callback whenever a buffer has been requested (by read() or QBUF) + */ +static void +buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct tw68_fh *fh = q->priv_data; + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + tw68_buffer_queue(fh->dev, &fh->dev->video_q, buf); +} + +/* + * buffer_release + * + * Free a buffer previously allocated. + */ +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + tw68_dma_free(q, buf); +} + +static struct videobuf_queue_ops video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +static int tw68_g_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, + struct v4l2_control *c) +{ + const struct v4l2_queryctrl *ctrl; + + dprintk(DBG_FLOW, "%s\n", __func__); + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = (char)tw_readb(TW68_BRIGHT); + break; + case V4L2_CID_HUE: + c->value = (char)tw_readb(TW68_HUE); + break; + case V4L2_CID_CONTRAST: + c->value = tw_readb(TW68_CONTRAST); + break; + case V4L2_CID_SATURATION: + c->value = tw_readb(TW68_SAT_U); + break; + case V4L2_CID_COLOR_KILLER: + c->value = 0 != (tw_readb(TW68_MISC2) & 0xe0); + break; + case V4L2_CID_CHROMA_AGC: + c->value = 0 != (tw_readb(TW68_LOOP) & 0x30); + break; + case V4L2_CID_AUDIO_MUTE: + /*hack to suppresss tvtime complaint */ + c->value = 0; + break; +#if 0 + case V4L2_CID_AUDIO_VOLUME: + c->value = dev->ctl_volume; + break; +#endif + default: + return -EINVAL; + } + return 0; +} + +static int tw68_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +{ + struct tw68_fh *fh = priv; + + return tw68_g_ctrl_internal(fh->dev, fh, c); +} + +static int tw68_s_ctrl_value(struct tw68_dev *dev, __u32 id, int val) +{ + int err = 0; + + dprintk(DBG_FLOW, "%s\n", __func__); + switch (id) { + case V4L2_CID_BRIGHTNESS: + tw_writeb(TW68_BRIGHT, val); + break; + case V4L2_CID_HUE: + tw_writeb(TW68_HUE, val); + break; + case V4L2_CID_CONTRAST: + tw_writeb(TW68_CONTRAST, val); + break; + case V4L2_CID_SATURATION: + tw_writeb(TW68_SAT_U, val); + tw_writeb(TW68_SAT_V, val); + break; + case V4L2_CID_COLOR_KILLER: + if (val) + tw_andorb(TW68_MISC2, 0xe0, 0xe0); + else + tw_andorb(TW68_MISC2, 0xe0, 0x00); + break; + case V4L2_CID_CHROMA_AGC: + if (val) + tw_andorb(TW68_LOOP, 0x30, 0x20); + else + tw_andorb(TW68_LOOP, 0x30, 0x00); + break; + case V4L2_CID_AUDIO_MUTE: + /* hack to suppress tvtime complaint */ + break; +#if 0 + case V4L2_CID_AUDIO_VOLUME: + dev->ctl_volume = val; + tw68_tvaudio_setvolume(dev, dev->ctl_volume); + break; + case V4L2_CID_HFLIP: + dev->ctl_mirror = val; + break; + case V4L2_CID_PRIVATE_AUTOMUTE: + { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + dev->ctl_automute = val; + if (dev->tda9887_conf) { + if (dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + else + dev->tda9887_conf &= ~TDA9887_AUTOMUTE; + + tw_call_all(dev, tuner, s_config, &tda9887_cfg); + } + break; + } +#endif + default: + err = -EINVAL; + } + return err; +} + +static int tw68_s_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, + struct v4l2_control *c) +{ + const struct v4l2_queryctrl *ctrl; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (fh) { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + return err; + } + + mutex_lock(&dev->lock); + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) { + err = -EINVAL; + goto error; + } + + dprintk(DBG_BUFF, "%s: name=%s val=%d\n", __func__, + ctrl->name, c->value); + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (c->value < ctrl->minimum) + c->value = ctrl->minimum; + if (c->value > ctrl->maximum) + c->value = ctrl->maximum; + break; + default: + /* nothing */; + }; + err = tw68_s_ctrl_value(dev, c->id, c->value); + +error: + mutex_unlock(&dev->lock); + return err; +} + +static int tw68_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +{ + struct tw68_fh *fh = f; + + return tw68_s_ctrl_internal(fh->dev, fh, c); +} + +/* ------------------------------------------------------------------ */ + +/* + * Returns a pointer to the currently used queue (e.g. video, vbi, etc.) + */ +static struct videobuf_queue *tw68_queue(struct tw68_fh *fh) +{ + struct videobuf_queue *q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int tw68_resource(struct tw68_fh *fh) +{ + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return RESOURCE_VIDEO; + + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) + return RESOURCE_VBI; + + BUG(); + return 0; +} + +static int video_open(struct file *file) +{ + int minor = video_devdata(file)->minor; + struct tw68_dev *dev; + struct tw68_fh *fh; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int radio = 0; + + mutex_lock(&tw68_devlist_lock); + list_for_each_entry(dev, &tw68_devlist, devlist) { + if (dev->video_dev && (dev->video_dev->minor == minor)) + goto found; + if (dev->radio_dev && (dev->radio_dev->minor == minor)) { + radio = 1; + goto found; + } + if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { + type = V4L2_BUF_TYPE_VBI_CAPTURE; + goto found; + } + } + mutex_unlock(&tw68_devlist_lock); + return -ENODEV; + +found: + mutex_unlock(&tw68_devlist_lock); + + dprintk(DBG_FLOW, "%s: minor=%d radio=%d type=%s\n", __func__, minor, + radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + fh->width = 720; + fh->height = 576; + v4l2_prio_open(&dev->prio, &fh->prio); + + videobuf_queue_sg_init(&fh->cap, &video_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct tw68_buf), +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + fh +#else + fh, &dev->lock +#endif + ); + videobuf_queue_sg_init(&fh->vbi, &tw68_vbi_qops, + &dev->pci->dev, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + V4L2_FIELD_SEQ_TB, + sizeof(struct tw68_buf), +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) + fh +#else + fh, &dev->lock +#endif + ); + if (fh->radio) { + /* switch to radio mode */ + tw68_tvaudio_setinput(dev, &card(dev).radio); + tw_call_all(dev, tuner, s_radio); + } else { + /* switch to video/vbi mode */ + tw68_tvaudio_setinput(dev, dev->input); + } + return 0; +} + +static ssize_t +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct tw68_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(tw68_queue(fh), + data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh, RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(tw68_queue(fh), + data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + break; + default: + BUG(); + return 0; + } +} + +static unsigned int +video_poll(struct file *file, struct poll_table_struct *wait) +{ + struct tw68_fh *fh = file->private_data; + struct videobuf_buffer *buf = NULL; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) + return videobuf_poll_stream(file, &fh->vbi, wait); + + if (res_check(fh, RESOURCE_VIDEO)) { + if (!list_empty(&fh->cap.stream)) + buf = list_entry(fh->cap.stream.next, + struct videobuf_buffer, stream); + } else { + mutex_lock(&fh->cap.vb_lock); + if (UNSET == fh->cap.read_off) { + /* need to capture a new frame */ + if (res_locked(fh->dev, RESOURCE_VIDEO)) + goto err; + if (0 != fh->cap.ops->buf_prepare(&fh->cap, + fh->cap.read_buf, fh->cap.field)) + goto err; + fh->cap.ops->buf_queue(&fh->cap, fh->cap.read_buf); + fh->cap.read_off = 0; + } + mutex_unlock(&fh->cap.vb_lock); + buf = fh->cap.read_buf; + } + + if (!buf) + return POLLERR; + + poll_wait(file, &buf->done, wait); + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) + return POLLIN | POLLRDNORM; + return 0; + +err: + mutex_unlock(&fh->cap.vb_lock); + return POLLERR; +} + +static int video_release(struct file *file) +{ + struct tw68_fh *fh = file->private_data; + struct tw68_dev *dev = fh->dev; + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_streamoff(&fh->cap); + res_free(fh , RESOURCE_VIDEO); + } + if (fh->cap.read_buf) { + buffer_release(&fh->cap, fh->cap.read_buf); + kfree(fh->cap.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + videobuf_stop(&fh->vbi); + res_free(fh, RESOURCE_VBI); + } + +#if 0 + tw_call_all(dev, core, s_standby, 0); +#endif + + /* free stuff */ + videobuf_mmap_free(&fh->cap); + videobuf_mmap_free(&fh->vbi); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + v4l2_prio_close(&dev->prio, &fh->prio); +#else + v4l2_prio_close(&dev->prio, fh->prio); +#endif + file->private_data = NULL; + kfree(fh); + return 0; +} + +static int video_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct tw68_fh *fh = file->private_data; + + return videobuf_mmap_mapper(tw68_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ + +#if 0 +static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + struct tw68_tvnorm *norm = dev->tvnorm; + + f->fmt.vbi.sampling_rate = 6750000 * 4; + f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 64 * 4; + f->fmt.vbi.start[0] = norm->vbi_v_start_0; + f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; + f->fmt.vbi.start[1] = norm->vbi_v_start_1; + f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ + +#if 0 + if (V4L2_STD_PAL == norm->id) { + /* FIXME */ + f->fmt.vbi.start[0] += 3; + f->fmt.vbi.start[1] += 3*2; + } +#endif + return 0; +} +#endif + +/* + * Note that this routine returns what is stored in the fh structure, and + * does not interrogate any of the device registers. + */ +static int tw68_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * (fh->fmt->depth)) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int tw68_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + struct tw68_format *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + dprintk(DBG_FLOW, "%s\n", __func__); + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); + maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + break; + case V4L2_FIELD_INTERLACED: + maxh = maxh * 2; + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * (fmt->depth)) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +/* + * Note that tw68_s_fmt_vid_cap sets the information into the fh structure, + * and it will be used for all future new buffers. However, there could be + * some number of buffers on the "active" chain which will be filled before + * the change takes place. + */ +static int tw68_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + err = tw68_try_fmt_vid_cap(file, priv, f); + if (0 != err) + return err; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->cap.field = f->fmt.pix.field; + /* + * The following lines are to make v4l2-test program happy. + * The docs should be checked to assure they make sense. + */ + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + return 0; +} + +static int tw68_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) +#if 0 + && (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1) +#endif + ) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + *c = *ctrl; + return 0; +} + +static int tw68_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + unsigned int n; + + n = i->index; + dprintk(DBG_FLOW, "%s: index is %d\n", __func__, n); + if (n >= TW68_INPUT_MAX) { + dprintk(DBG_FLOW, "%s: INPUT_MAX reached\n", __func__); + return -EINVAL; + } + if (NULL == card_in(dev, n).name) { + dprintk(DBG_FLOW, "%s: End of list\n", __func__); + return -EINVAL; + } + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, card_in(dev, n).name); + if (card_in(dev, n).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + i->audioset = 1; + /* If the query is for the current input, get live data */ + if (n == dev->hw_input->vmux) { + int v1 = tw_readb(TW68_STATUS1); + int v2 = tw_readb(TW68_MVSN); + + if (0 != (v1 & (1 << 7))) + i->status |= V4L2_IN_ST_NO_SYNC; + if (0 != (v1 & (1 << 6))) + i->status |= V4L2_IN_ST_NO_H_LOCK; + if (0 != (v1 & (1 << 2))) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 != (v1 & 1 << 1)) + i->status |= V4L2_IN_ST_NO_COLOR; + if (0 != (v2 & (1 << 2))) + i->status |= V4L2_IN_ST_MACROVISION; + } + i->std = TW68_NORMS; + return 0; +} + +static int tw68_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *i = dev->input->vmux; + return 0; +} + +static int tw68_s_input(struct file *file, void *priv, unsigned int i) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + + if (i < 0 || i >= TW68_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + unsigned int tuner_type = dev->tuner_type; + + dprintk(DBG_FLOW, "%s\n", __func__); + strcpy(cap->driver, "tw68"); + strlcpy(cap->card, tw68_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = TW68_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; + return 0; +} + +static int tw68_s_std_internal(struct tw68_dev *dev, struct tw68_fh *fh, + v4l2_std_id *id) +{ +/* unsigned long flags; */ + unsigned int i; + v4l2_std_id fixup; + int err; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (fh) { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + } + + /* Look for match on complete norm id (may have mult bits) */ + for (i = 0; i < TVNORMS; i++) { + if (*id == tvnorms[i].id) + break; + } + + /* If no exact match, look for norm which contains this one */ + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) { + if (*id & tvnorms[i].id) + break; + } + /* If still not matched, give up */ + if (i == TVNORMS) + return -EINVAL; + + /* TODO - verify this additional work with SECAM applies to TW */ + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; + } + + *id = tvnorms[i].id; + mutex_lock(&dev->lock); + set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ + tw68_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + return tw68_s_std_internal(fh->dev, fh, id); +} + +static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *id = dev->tvnorm->id; + return 0; +} + +static int tw68_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int n; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + for (n = 0; n < TW68_INPUT_MAX; n++) + if (card_in(dev, n).tv) + break; + if (n == TW68_INPUT_MAX) + return -EINVAL; +#if 0 + if (NULL != card_in(dev, n).name) { + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = tw68_tvaudio_getstereo(dev); + t->audmode = tw68_tvaudio_rx2mode(t->rxsubchans); + } + if (0 != (saa_readb(TW68_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; +#endif + return 0; +} + +static int tw68_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; +#if 0 + int rx, mode +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + +#if 0 + mode = dev->thread.mode; + if (UNSET == mode) { + rx = tw68_tvaudio_getstereo(dev); + mode = tw68_tvaudio_rx2mode(t->rxsubchans); + } + if (mode != t->audmode) + dev->thread.mode = t->audmode; +#endif + return 0; +} + +static int tw68_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + if (unlikely(dev->tuner_type)) + return -EINVAL; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; +/* f->frequency = dev->ctl_freq; */ + + return 0; +} + +static int tw68_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int err; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) + err = v4l2_prio_check(&dev->prio, &fh->prio); +#else + err = v4l2_prio_check(&dev->prio, fh->prio); +#endif + if (0 != err) + if (0 != err) + return err; + + if (0 != f->tuner) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + mutex_lock(&dev->lock); +/* dev->ctl_freq = f->frequency; */ + + tw_call_all(dev, tuner, s_frequency, f); + + tw68_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} + +static int tw68_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + strcpy(a->name, "audio"); + return 0; +} + +static int tw68_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return 0; +} + +static int tw68_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + *p = v4l2_prio_max(&dev->prio); + return 0; +} + +static int tw68_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + return v4l2_prio_change(&dev->prio, &fh->prio, prio); +} + +static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (f->index >= FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int tw68_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + } + return 0; +} + +static int tw68_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + crop->c = dev->crop_current; + return 0; +} + +static int tw68_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct tw68_fh *fh = f; + struct tw68_dev *dev = fh->dev; + struct v4l2_rect *b = &dev->crop_bounds; + + dprintk(DBG_FLOW, "%s\n", __func__); + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + + if ((crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (crop->c.height < 0) || (crop->c.width < 0)) { + dprintk(DBG_UNEXPECTED, "%s: invalid request\n", __func__); + return -EINVAL; + } + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dprintk(DBG_FLOW, "%s: setting cropping rectangle: top=%d, left=%d, " + "width=%d, height=%d\n", __func__, crop->c.top, + crop->c.left, crop->c.width, crop->c.height); + dev->crop_current = crop->c; + return 0; +} + +/* + * Wrappers for the v4l2_ioctl_ops functions + */ +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct tw68_fh *fh = file->private_data; + return videobuf_cgmbuf(tw68_queue(fh), mbuf, 8); +} +#endif + +static int tw68_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct tw68_fh *fh = priv; + return videobuf_reqbufs(tw68_queue(fh), p); +} + +static int tw68_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_querybuf(tw68_queue(fh), b); +} + +static int tw68_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_qbuf(tw68_queue(fh), b); +} + +static int tw68_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct tw68_fh *fh = priv; + return videobuf_dqbuf(tw68_queue(fh), b, + file->f_flags & O_NONBLOCK); +} + +static int tw68_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int res = tw68_resource(fh); + + dprintk(DBG_FLOW, "%s\n", __func__); + if (!res_get(fh, res)) + return -EBUSY; + + tw68_buffer_requeue(dev, &dev->video_q); + return videobuf_streamon(tw68_queue(fh)); +} + +static int tw68_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int err; + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + int res = tw68_resource(fh); + + dprintk(DBG_FLOW, "%s\n", __func__); + err = videobuf_streamoff(tw68_queue(fh)); + if (err < 0) + return err; + res_free(fh, res); + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * Used strictly for internal development and debugging, this routine + * prints out the current register contents for the tw68xx device. + */ +static void tw68_dump_regs(struct tw68_dev *dev) +{ + unsigned char line[80]; + int i, j, k; + unsigned char *cptr; + + printk(KERN_DEBUG "Full dump of TW68 registers:\n"); + /* First we do the PCI regs, 8 4-byte regs per line */ + for (i = 0; i < 0x100; i += 32) { + cptr = line; + cptr += sprintf(cptr, "%03x ", i); + /* j steps through the next 4 words */ + for (j = i; j < i + 16; j += 4) + cptr += sprintf(cptr, "%08x ", tw_readl(j)); + *cptr++ = ' '; + for (; j < i + 32; j += 4) + cptr += sprintf(cptr, "%08x ", tw_readl(j)); + *cptr++ = '\n'; + *cptr = 0; + printk(KERN_DEBUG "%s", line); + } + /* Next the control regs, which are single-byte, address mod 4 */ + while (i < 0x400) { + cptr = line; + cptr += sprintf(cptr, "%03x ", i); + /* Print out 4 groups of 4 bytes */ + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + cptr += sprintf(cptr, "%02x ", + tw_readb(i)); + i += 4; + } + *cptr++ = ' '; + } + *cptr++ = '\n'; + *cptr = 0; + printk(KERN_DEBUG "%s", line); + } +} + +static int vidioc_log_status(struct file *file, void *priv) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; + + tw68_dump_regs(dev); + return 0; +} + +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; /* needed for tw_readb */ + + dprintk(DBG_FLOW, "%s\n", __func__); + if (!v4l2_chip_match_host(®->match)) + dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); + return -EINVAL; + if (reg->size == 1) + reg->val = tw_readb(reg->reg); + else + reg->val = tw_readl(reg->reg); + return 0; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg) +{ + struct tw68_fh *fh = priv; + struct tw68_dev *dev = fh->dev; /* needed for tw_writeb */ + + dprintk(DBG_FLOW, "%s: request to set reg 0x%04x to 0x%02x\n", + __func__, (unsigned int)reg->reg, (unsigned int)reg->val); + if (!v4l2_chip_match_host(®->match)) { + dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); + return -EINVAL; + } + if (reg->size == 1) + tw_writeb(reg->reg, reg->val); + else + tw_writel(reg->reg & 0xffff, reg->val); + return 0; +} +#endif + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = tw68_querycap, + .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, + .vidioc_reqbufs = tw68_reqbufs, + .vidioc_querybuf = tw68_querybuf, + .vidioc_qbuf = tw68_qbuf, + .vidioc_dqbuf = tw68_dqbuf, + .vidioc_s_std = tw68_s_std, + .vidioc_g_std = tw68_g_std, + .vidioc_enum_input = tw68_enum_input, + .vidioc_g_input = tw68_g_input, + .vidioc_s_input = tw68_s_input, + .vidioc_queryctrl = tw68_queryctrl, + .vidioc_g_ctrl = tw68_g_ctrl, + .vidioc_s_ctrl = tw68_s_ctrl, + .vidioc_streamon = tw68_streamon, + .vidioc_streamoff = tw68_streamoff, + .vidioc_g_priority = tw68_g_priority, + .vidioc_s_priority = tw68_s_priority, + .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, + .vidioc_cropcap = tw68_cropcap, + .vidioc_g_crop = tw68_g_crop, + .vidioc_s_crop = tw68_s_crop, +/* + * Functions not yet implemented / not yet passing tests. + */ + +#if 0 + .vidioc_g_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, +#endif + .vidioc_g_audio = tw68_g_audio, + .vidioc_s_audio = tw68_s_audio, + .vidioc_g_tuner = tw68_g_tuner, + .vidioc_s_tuner = tw68_s_tuner, + .vidioc_g_frequency = tw68_g_frequency, + .vidioc_s_frequency = tw68_s_frequency, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_log_status = vidioc_log_status, + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +/* ------------------------------------------------------------------ */ +/* exported stuff */ +struct video_device tw68_video_template = { + .name = "tw68_video", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .minor = -1, + .tvnorms = TW68_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +struct video_device tw68_radio_template = { + .name = "tw68_radio", +}; + +int tw68_videoport_init(struct tw68_dev *dev) +{ + return 0; +} + +void tw68_set_tvnorm_hw(struct tw68_dev *dev) +{ + tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); + return; +} + +int tw68_video_init1(struct tw68_dev *dev) +{ + int i; + + dprintk(DBG_FLOW, "%s\n", __func__); + /* sanitycheck insmod options */ + if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) + gbuffers = 2; + if (gbufsz < 0 || gbufsz > gbufsz_max) + gbufsz = gbufsz_max; + gbufsz = (gbufsz + PAGE_SIZE - 1) & PAGE_MASK; + + /* put some sensible defaults into the data structures ... */ + for (i = 0; i < CTRLS; i++) + tw68_s_ctrl_value(dev, video_ctrls[i].id, + video_ctrls[i].default_value); +#if 0 + if (dev->tda9887_conf && dev->ctl_automute) + dev->tda9887_conf |= TDA9887_AUTOMUTE; + dev->automute = 0; +#endif + INIT_LIST_HEAD(&dev->video_q.queued); + INIT_LIST_HEAD(&dev->video_q.active); + init_timer(&dev->video_q.timeout); + dev->video_q.timeout.function = tw68_buffer_timeout; + dev->video_q.timeout.data = (unsigned long)(&dev->video_q); + dev->video_q.dev = dev; + dev->video_q.buf_compat = tw68_check_video_fmt; + dev->video_q.start_dma = tw68_video_start_dma; + tw68_risc_stopper(dev->pci, &dev->video_q.stopper); + + if (tw68_boards[dev->board].video_out) + tw68_videoport_init(dev); + + return 0; +} + +int tw68_video_init2(struct tw68_dev *dev) +{ + dprintk(DBG_FLOW, "%s\n", __func__); + set_tvnorm(dev, &tvnorms[0]); + video_mux(dev, 0); +/* + tw68_tvaudio_setmut(dev); + tw68_tvaudio_setvolume(dev, dev->ctl_volume); +*/ + return 0; +} + +/* + * tw68_irq_video_signalchange + * + * TODO: + * Check for presence of video signal. If not present, mute audio. + * If present, log type of signal present. + */ +void tw68_irq_video_signalchange(struct tw68_dev *dev) +{ + return; +} + +/* + * tw68_irq_video_done + */ +void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) +{ + __u32 reg; + + /* reset interrupts handled by this routine */ + tw_writel(TW68_INTSTAT, status); + /* + * Check most likely first + * + * DMAPI shows we have reached the end of the risc code + * for the current buffer. + */ + if (status & TW68_DMAPI) { + struct tw68_dmaqueue *q = &dev->video_q; + dprintk(DBG_FLOW | DBG_TESTING, "DMAPI interrupt\n"); + spin_lock(&dev->slock); + /* + * tw68_wakeup will take care of the buffer handling, + * plus any non-video requirements. + */ + tw68_wakeup(q, &dev->video_fieldcount); + spin_unlock(&dev->slock); + /* Check whether we have gotten into 'stopper' code */ + reg = tw_readl(TW68_DMAP_PP); + if ((reg >= q->stopper.dma) && + (reg < q->stopper.dma + q->stopper.size)) { + /* Yes - log the information */ + dprintk(DBG_FLOW | DBG_TESTING, + "%s: stopper risc code entered\n", __func__); + } + status &= ~(TW68_DMAPI); + if (0 == status) + return; + } + if (status & (TW68_VLOCK | TW68_HLOCK)) { /* lost sync */ + dprintk(DBG_UNUSUAL, "Lost sync\n"); + } + if (status & TW68_PABORT) { /* TODO - what should we do? */ + dprintk(DBG_UNEXPECTED, "PABORT interrupt\n"); + } + if (status & TW68_DMAPERR) { + dprintk(DBG_UNEXPECTED, "DMAPERR interrupt\n"); +#if 0 + /* Stop risc & fifo */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + tw_clearl(TW68_INTMASK, dev->board_virqmask); + dev->pci_irqmask &= ~dev->board_virqmask; +#endif + } + /* + * On TW6800, FDMIS is apparently generated if video input is switched + * during operation. Therefore, it is not enabled for that chip. + */ + if (status & TW68_FDMIS) { /* logic error somewhere */ + dprintk(DBG_UNEXPECTED, "FDMIS interrupt\n"); + /* Stop risc & fifo */ +// tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); +// tw_clearl(TW68_INTMASK, dev->board_virqmask); +// dev->pci_irqmask &= ~dev->board_virqmask; + } + if (status & TW68_FFOF) { /* probably a logic error */ + reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; + tw_clearl(TW68_DMAC, TW68_FIFO_EN); + dprintk(DBG_UNUSUAL, "FFOF interrupt\n"); + tw_setl(TW68_DMAC, reg); + } + if (status & TW68_FFERR) + dprintk(DBG_UNEXPECTED, "FFERR interrupt\n"); + return; +} diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h new file mode 100644 index 000000000000..e723efb5e623 --- /dev/null +++ b/drivers/media/pci/tw68/tw68.h @@ -0,0 +1,588 @@ +/* + * tw68 driver common header file + * + * Much of this code is derived from the cx88 and sa7134 drivers, which + * were in turn derived from the bt87x driver. The original work was by + * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, + * Hans Verkuil, Andy Walls and many others. Their work is gratefully + * acknowledged. Full credit goes to them - any problems within this code + * are mine. + * + * Copyright (C) 2009 William M. Brack + * + * 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 + */ + +#include +#define TW68_VERSION_CODE KERNEL_VERSION(0, 0, 8) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +# include +#endif +#include +#include + +#include "btcx-risc.h" +#include "tw68-reg.h" + +#define UNSET (-1U) + +/* + * dprintk statement within the code use a 'level' argument. For + * our purposes, we use the following levels: + */ +#define DBG_UNEXPECTED (1 << 0) +#define DBG_UNUSUAL (1 << 1) +#define DBG_TESTING (1 << 2) +#define DBG_BUFF (1 << 3) +#define DBG_FLOW (1 << 15) + +/* system vendor and device ID's */ +#define PCI_VENDOR_ID_TECHWELL 0x1797 +#define PCI_DEVICE_ID_6800 0x6800 +#define PCI_DEVICE_ID_6801 0x6801 +#define PCI_DEVICE_ID_AUDIO2 0x6802 +#define PCI_DEVICE_ID_TS3 0x6803 +#define PCI_DEVICE_ID_6804 0x6804 +#define PCI_DEVICE_ID_AUDIO5 0x6805 +#define PCI_DEVICE_ID_TS6 0x6806 + +/* tw6816 based cards */ +#define PCI_DEVICE_ID_6816_1 0x6810 +#define PCI_DEVICE_ID_6816_2 0x6811 +#define PCI_DEVICE_ID_6816_3 0x6812 +#define PCI_DEVICE_ID_6816_4 0x6813 + +/* subsystem vendor ID's */ +#define TW68_PCI_ID_TECHWELL 0x1797 + +#define TW68_NORMS (\ + V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60 | \ + V4L2_STD_525_60 | V4L2_STD_625_50 | \ + V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC | V4L2_STD_SECAM_DK) + +#define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ + TW68_FFOF | TW68_DMAPI) +/* TW6800 chips have trouble with these, so we don't set them for that chip */ +#define TW68_VID_INTSX (TW68_FDMIS | TW68_HLOCK | TW68_VLOCK) + +#define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ + TW68_SBDONE2) + +typedef enum { + TW6800, + TW6801, + TW6804, + TWXXXX, +} TW68_DECODER_TYPE; +/* ----------------------------------------------------------- */ +/* static data */ + +struct tw68_tvnorm { + char *name; + v4l2_std_id id; + + /* video decoder */ + u32 sync_control; + u32 luma_control; + u32 chroma_ctrl1; + u32 chroma_gain; + u32 chroma_ctrl2; + u32 vgate_misc; + + /* video scaler */ + u32 h_delay; + u32 h_delay0; /* for TW6800 */ + u32 h_start; + u32 h_stop; + u32 v_delay; + u32 video_v_start; + u32 video_v_stop; + u32 vbi_v_start_0; + u32 vbi_v_stop_0; + u32 vbi_v_start_1; + + /* Techwell specific */ + u32 format; +}; + +struct tw68_format { + char *name; + u32 fourcc; + u32 depth; + u32 twformat; +}; + +/* ----------------------------------------------------------- */ +/* card configuration */ + +#define TW68_BOARD_NOAUTO UNSET +#define TW68_BOARD_UNKNOWN 0 +#define TW68_BOARD_GENERIC_6802 1 + +#define TW68_MAXBOARDS 16 +#define TW68_INPUT_MAX 8 + +/* ----------------------------------------------------------- */ +/* enums */ + +enum tw68_mpeg_type { + TW68_MPEG_UNUSED, + TW68_MPEG_EMPRESS, + TW68_MPEG_DVB, +}; + +enum tw68_audio_in { + TV = 1, + LINE1 = 2, + LINE2 = 3, + LINE2_LEFT, +}; + +enum tw68_video_out { + CCIR656 = 1, +}; + +/* Structs for card definition */ +struct tw68_input { + char *name; /* text description */ + unsigned int vmux; /* mux value */ + enum tw68_audio_in mux; + unsigned int gpio; + unsigned int tv:1; +}; + +struct tw68_board { + char *name; + unsigned int audio_clock; + + /* input switching */ + unsigned int gpiomask; + struct tw68_input inputs[TW68_INPUT_MAX]; + struct tw68_input radio; + struct tw68_input mute; + + /* i2c chip info */ + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + unsigned int tda9887_conf; + unsigned int tuner_config; + + enum tw68_video_out video_out; + enum tw68_mpeg_type mpeg; + unsigned int vid_port_opts; +}; + +#define card_has_radio(dev) (NULL != tw68_boards[dev->board].radio.name) +#define card_has_mpeg(dev) (TW68_MPEG_UNUSED != \ + tw68_boards[dev->board].mpeg) +#define card_in(dev, n) (tw68_boards[dev->board].inputs[n]) +#define card(dev) (tw68_boards[dev->board]) + +/* ----------------------------------------------------------- */ +/* device / file handle status */ + +#define RESOURCE_VIDEO 1 +#define RESOURCE_VBI 2 + +#define INTERLACE_AUTO 0 +#define INTERLACE_ON 1 +#define INTERLACE_OFF 2 + +#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ + +struct tw68_dev; /* forward delclaration */ + +/* tvaudio thread status */ +struct tw68_thread { + struct task_struct *thread; + unsigned int scan1; + unsigned int scan2; + unsigned int mode; + unsigned int stopped; +}; + +/* buffer for one video/vbi/ts frame */ +struct tw68_buf { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* tw68 specific */ + struct tw68_format *fmt; + struct tw68_input *input; + unsigned int top_seen; + int (*activate)(struct tw68_dev *dev, + struct tw68_buf *buf, + struct tw68_buf *next); + struct btcx_riscmem risc; + unsigned int bpl; +}; + +struct tw68_dmaqueue { + struct tw68_dev *dev; + struct list_head active; + struct list_head queued; + struct timer_list timeout; + struct btcx_riscmem stopper; + int (*buf_compat)(struct tw68_buf *prev, + struct tw68_buf *buf); + int (*start_dma)(struct tw68_dev *dev, + struct tw68_dmaqueue *q, + struct tw68_buf *buf); +}; + +/* video filehandle status */ +struct tw68_fh { + struct tw68_dev *dev; + unsigned int radio; + enum v4l2_buf_type type; + unsigned int resources; + enum v4l2_priority prio; + + /* video capture */ + struct tw68_format *fmt; + unsigned int width, height; + struct videobuf_queue cap; /* also used for overlay */ + + /* vbi capture */ + struct videobuf_queue vbi; +}; + +/* dmasound dsp status */ +struct tw68_dmasound { + struct mutex lock; + int minor_mixer; + int minor_dsp; + unsigned int users_dsp; + + /* mixer */ + enum tw68_audio_in input; + unsigned int count; + unsigned int line1; + unsigned int line2; + + /* dsp */ + unsigned int afmt; + unsigned int rate; + unsigned int channels; + unsigned int recording_on; + unsigned int dma_running; + unsigned int blocks; + unsigned int blksize; + unsigned int bufsize; + struct videobuf_dmabuf dma; + unsigned int dma_blk; + unsigned int read_offset; + unsigned int read_count; + void *priv_data; + struct snd_pcm_substream *substream; +}; + +struct tw68_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 twformat; +}; + +/* ts/mpeg status */ +struct tw68_ts { + /* TS capture */ + int nr_packets; + int nr_bufs; +}; + +/* ts/mpeg ops */ +struct tw68_mpeg_ops { + enum tw68_mpeg_type type; + struct list_head next; + int (*init)(struct tw68_dev *dev); + int (*fini)(struct tw68_dev *dev); + void (*signal_change)(struct tw68_dev *dev); +}; + +enum tw68_ts_status { + TW68_TS_STOPPED, + TW68_TS_BUFF_DONE, + TW68_TS_STARTED, +}; + +/* global device status */ +struct tw68_dev { + struct list_head devlist; + struct mutex lock; + spinlock_t slock; + struct v4l2_prio_state prio; + struct v4l2_device v4l2_dev; + /* workstruct for loading modules */ + struct work_struct request_module_wk; + + /* insmod option/autodetected */ + int autodetected; + + /* various device info */ + TW68_DECODER_TYPE vdecoder; + unsigned int resources; + struct video_device *video_dev; + struct video_device *radio_dev; + struct video_device *vbi_dev; + struct tw68_dmasound dmasound; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) + /* infrared remote */ + int has_remote; + struct card_ir *remote; +#endif + + /* pci i/o */ + char name[32]; + int nr; + struct pci_dev *pci; + unsigned char pci_rev, pci_lat; + u32 __iomem *lmmio; + u8 __iomem *bmmio; + u32 pci_irqmask; + /* The irq mask to be used will depend upon the chip type */ + u32 board_virqmask; + + /* config info */ + unsigned int board; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + unsigned int tda9887_conf; + unsigned int gpio_value; + + /* i2c i/o */ + struct i2c_algo_bit_data i2c_algo; + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + u32 i2c_state; + u32 i2c_done; + wait_queue_head_t i2c_queue; + int i2c_rc; + unsigned char eedata[256]; + + /* video+ts+vbi capture */ + struct tw68_dmaqueue video_q; + struct tw68_dmaqueue vbi_q; + unsigned int video_fieldcount; + unsigned int vbi_fieldcount; + + /* various v4l controls */ + struct tw68_tvnorm *tvnorm; /* video */ + struct tw68_tvaudio *tvaudio; +#if 0 + unsigned int ctl_input; + int ctl_bright; + int ctl_contrast; + int ctl_hue; + int ctl_saturation; + int ctl_freq; + int ctl_mute; /* audio */ + int ctl_volume; + int ctl_invert; /* private */ + int ctl_mirror; + int ctl_y_odd; + int ctl_y_even; + int ctl_automute; +#endif + + /* crop */ + struct v4l2_rect crop_bounds; + struct v4l2_rect crop_defrect; + struct v4l2_rect crop_current; + + /* other global state info */ + unsigned int automute; + struct tw68_thread thread; + /* input is latest requested by app, hw_input is current hw setting */ + struct tw68_input *input; + struct tw68_input *hw_input; + unsigned int hw_mute; + int last_carrier; + int nosignal; + unsigned int insuspend; + + /* TW68_MPEG_* */ + struct tw68_ts ts; + struct tw68_dmaqueue ts_q; + enum tw68_ts_status ts_state; + unsigned int buff_cnt; + struct tw68_mpeg_ops *mops; + + void (*gate_ctrl)(struct tw68_dev *dev, int open); +}; + +/* ----------------------------------------------------------- */ + +#define tw_readl(reg) readl(dev->lmmio + ((reg) >> 2)) +#define tw_readb(reg) readb(dev->bmmio + (reg)) +#define tw_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2)) +#define tw_writeb(reg, value) writeb((value), dev->bmmio + (reg)) + +#define tw_andorl(reg, mask, value) \ + writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+((reg)>>2)) +#define tw_andorb(reg, mask, value) \ + writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\ + ((value) & (mask)), dev->bmmio+(reg)) +#define tw_setl(reg, bit) tw_andorl((reg), (bit), (bit)) +#define tw_setb(reg, bit) tw_andorb((reg), (bit), (bit)) +#define tw_clearl(reg, bit) \ + writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \ + dev->lmmio + ((reg) >> 2)) +#define tw_clearb(reg, bit) \ + writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ + dev->bmmio + (reg)) +#define tw_call_all(dev, o, f, args...) do { \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 1); \ + v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ + if (dev->gate_ctrl) \ + dev->gate_ctrl(dev, 0); \ +} while (0) + +#define tw_wait(us) { udelay(us); } + +static inline struct tw68_dev *to_tw68_dev(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct tw68_dev, v4l2_dev); +} + +/* ----------------------------------------------------------- */ +/* tw68-core.c */ + +extern struct list_head tw68_devlist; +extern struct mutex tw68_devlist_lock; +extern unsigned int irq_debug; + +int tw68_buffer_count(unsigned int size, unsigned int count); +void tw68_buffer_queue(struct tw68_dev *dev, struct tw68_dmaqueue *q, + struct tw68_buf *buf); +void tw68_buffer_timeout(unsigned long data); +int tw68_set_dmabits(struct tw68_dev *dev); +void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf); +void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *field_count); +int tw68_buffer_requeue(struct tw68_dev *dev, struct tw68_dmaqueue *q); + +/* ----------------------------------------------------------- */ +/* tw68-cards.c */ + +extern struct tw68_board tw68_boards[]; +extern const unsigned int tw68_bcount; +extern struct pci_device_id __devinitdata tw68_pci_tbl[]; + +int tw68_board_init1(struct tw68_dev *dev); +int tw68_board_init2(struct tw68_dev *dev); +int tw68_tuner_callback(void *priv, int component, int command, int arg); + +/* ----------------------------------------------------------- */ +/* tw68-i2c.c */ + +int tw68_i2c_register(struct tw68_dev *dev); +int tw68_i2c_unregister(struct tw68_dev *dev); +void tw68_irq_i2c(struct tw68_dev *dev, int status); + +/* ----------------------------------------------------------- */ +/* tw68-video.c */ + +extern unsigned int video_debug; +extern struct video_device tw68_video_template; +extern struct video_device tw68_radio_template; + +int tw68_videoport_init(struct tw68_dev *dev); +void tw68_set_tvnorm_hw(struct tw68_dev *dev); + +int tw68_video_init1(struct tw68_dev *dev); +int tw68_video_init2(struct tw68_dev *dev); +void tw68_irq_video_signalchange(struct tw68_dev *dev); +void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); + +/* ----------------------------------------------------------- */ +/* tw68-ts.c */ + +int tw68_ts_init1(struct tw68_dev *dev); +int tw68_ts_fini(struct tw68_dev *dev); +void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status); + +int tw68_ts_register(struct tw68_mpeg_ops *ops); +void tw68_ts_unregister(struct tw68_mpeg_ops *ops); + +int tw68_ts_init_hw(struct tw68_dev *dev); + +/* ----------------------------------------------------------- */ +/* tw68-vbi.c */ + +extern struct videobuf_queue_ops tw68_vbi_qops; +extern struct video_device tw68_vbi_template; + +int tw68_vbi_init1(struct tw68_dev *dev); +int tw68_vbi_fini(struct tw68_dev *dev); +void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status); + +/* ----------------------------------------------------------- */ +/* tw68-tvaudio.c */ + +int tw68_tvaudio_rx2mode(u32 rx); + +void tw68_tvaudio_setmute(struct tw68_dev *dev); +void tw68_tvaudio_setinput(struct tw68_dev *dev, + struct tw68_input *in); +void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level); +int tw68_tvaudio_getstereo(struct tw68_dev *dev); +void tw68_tvaudio_init(struct tw68_dev *dev); +int tw68_tvaudio_init2(struct tw68_dev *dev); +int tw68_tvaudio_fini(struct tw68_dev *dev); +int tw68_tvaudio_do_scan(struct tw68_dev *dev); +int tw_dsp_writel(struct tw68_dev *dev, int reg, u32 value); +void tw68_enable_i2s(struct tw68_dev *dev); + +/* ----------------------------------------------------------- */ +/* tw68-risc.c */ + +int tw68_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int top_offset, + unsigned int bottom_offset, unsigned int bpl, + unsigned int padding, unsigned int lines); +int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc); +int tw68_risc_overlay(struct tw68_fh *fh, struct btcx_riscmem *risc, + int field_type); -- cgit v1.2.3 From e15d1c12c5878b3a80d6573af1721e17264e0286 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Sep 2014 03:36:14 -0300 Subject: [media] tw68: refactor and cleanup the tw68 driver Refactor and clean up the tw68 driver. It's now using the proper V4L2 core frameworks. Tested with my Techwell tw6805a and tw6816 grabber boards. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/tw68/Kconfig | 10 + drivers/media/pci/tw68/Makefile | 3 + drivers/media/pci/tw68/tw68-cards.c | 172 --- drivers/media/pci/tw68/tw68-core.c | 801 ++------------ drivers/media/pci/tw68/tw68-i2c.c | 245 ----- drivers/media/pci/tw68/tw68-reg.h | 10 +- drivers/media/pci/tw68/tw68-risc.c | 156 +-- drivers/media/pci/tw68/tw68-ts.c | 66 -- drivers/media/pci/tw68/tw68-tvaudio.c | 80 -- drivers/media/pci/tw68/tw68-vbi.c | 76 -- drivers/media/pci/tw68/tw68-video.c | 1922 +++++++-------------------------- drivers/media/pci/tw68/tw68.h | 435 +------- 14 files changed, 566 insertions(+), 3412 deletions(-) create mode 100644 drivers/media/pci/tw68/Kconfig create mode 100644 drivers/media/pci/tw68/Makefile delete mode 100644 drivers/media/pci/tw68/tw68-cards.c delete mode 100644 drivers/media/pci/tw68/tw68-i2c.c delete mode 100644 drivers/media/pci/tw68/tw68-ts.c delete mode 100644 drivers/media/pci/tw68/tw68-tvaudio.c delete mode 100644 drivers/media/pci/tw68/tw68-vbi.c (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 5c16c9c2203e..933280740176 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig" source "drivers/media/pci/zoran/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" +source "drivers/media/pci/tw68/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index dc2ebbe27306..73d9c0f11127 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ +obj-$(CONFIG_VIDEO_TW68) += tw68/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig new file mode 100644 index 000000000000..5425ba1e320d --- /dev/null +++ b/drivers/media/pci/tw68/Kconfig @@ -0,0 +1,10 @@ +config VIDEO_TW68 + tristate "Techwell tw68x Video For Linux" + depends on VIDEO_DEV && PCI && VIDEO_V4L2 + select I2C_ALGOBIT + select VIDEOBUF2_DMA_SG + ---help--- + Support for Techwell tw68xx based frame grabber boards. + + To compile this driver as a module, choose M here: the + module will be called tw68. diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile new file mode 100644 index 000000000000..3d02f28b14fb --- /dev/null +++ b/drivers/media/pci/tw68/Makefile @@ -0,0 +1,3 @@ +tw68-objs := tw68-core.o tw68-video.o tw68-risc.o + +obj-$(CONFIG_VIDEO_TW68) += tw68.o diff --git a/drivers/media/pci/tw68/tw68-cards.c b/drivers/media/pci/tw68/tw68-cards.c deleted file mode 100644 index 62aec4faa0d1..000000000000 --- a/drivers/media/pci/tw68/tw68-cards.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include /* must appear before i2c-algo-bit.h */ -#include - -#include -#include - -#include "tw68.h" -#include "tw68-reg.h" - -/* commly used strings */ -#if 0 -static char name_mute[] = "mute"; -static char name_radio[] = "Radio"; -static char name_tv[] = "Television"; -static char name_tv_mono[] = "TV (mono only)"; -static char name_svideo[] = "S-Video"; -static char name_comp[] = "Composite"; -#endif -static char name_comp1[] = "Composite1"; -static char name_comp2[] = "Composite2"; -static char name_comp3[] = "Composite3"; -static char name_comp4[] = "Composite4"; - -/* ------------------------------------------------------------------ */ -/* board config info */ - -/* If radio_type !=UNSET, radio_addr should be specified - */ - -struct tw68_board tw68_boards[] = { - [TW68_BOARD_UNKNOWN] = { - .name = "GENERIC", - .tuner_type = TUNER_ABSENT, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - - .inputs = { - { - .name = name_comp1, - .vmux = 0, - }, { - .name = name_comp2, - .vmux = 1, - }, { - .name = name_comp3, - .vmux = 2, - }, { - .name = name_comp4, - .vmux = 3, - }, { /* Must have a NULL entry at end of list */ - .name = NULL, - .vmux = 0, - } - }, - }, -}; - -const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards); - -/* - * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps - * the PCI ID database up to date. Note that the entries must be - * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. - */ -struct pci_device_id tw68_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6801, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6804, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - .vendor = PCI_VENDOR_ID_TECHWELL, - .device = PCI_DEVICE_ID_6816_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = TW68_BOARD_UNKNOWN, - }, { - /* end of list */ - } -}; -MODULE_DEVICE_TABLE(pci, tw68_pci_tbl); - -/* ------------------------------------------------------------ */ -/* stuff done before i2c enabled */ -int tw68_board_init1(struct tw68_dev *dev) -{ - /* Clear GPIO outputs */ - tw_writel(TW68_GPOE, 0); - /* Remainder of setup according to board ID */ - switch (dev->board) { - case TW68_BOARD_UNKNOWN: - printk(KERN_INFO "%s: Unable to determine board type, " - "using generic values\n", dev->name); - break; - } - dev->input = dev->hw_input = &card_in(dev,0); - return 0; -} - -int tw68_tuner_setup(struct tw68_dev *dev) -{ - return 0; -} - -/* stuff which needs working i2c */ -int tw68_board_init2(struct tw68_dev *dev) -{ - return 0; -} - - diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 2c5d7a5f3f8e..baf93af1d764 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -9,7 +9,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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 @@ -20,10 +24,6 @@ * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include @@ -44,320 +44,44 @@ #include "tw68-reg.h" MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); -MODULE_AUTHOR("William M. Brack "); +MODULE_AUTHOR("William M. Brack"); +MODULE_AUTHOR("Hans Verkuil "); MODULE_LICENSE("GPL"); -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -static unsigned int gpio_tracking; -module_param(gpio_tracking, int, 0644); -MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); - -static unsigned int alsa = 1; -module_param(alsa, int, 0644); -MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); - static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency, "pci latency timer"); -static unsigned int nocomb; -module_param(nocomb, int, 0644); -MODULE_PARM_DESC(nocomb, "disable comb filter"); - static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; - module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - MODULE_PARM_DESC(video_nr, "video device number"); -MODULE_PARM_DESC(vbi_nr, "vbi device number"); -MODULE_PARM_DESC(radio_nr, "radio device number"); -MODULE_PARM_DESC(tuner, "tuner type"); -MODULE_PARM_DESC(card, "card type"); - -LIST_HEAD(tw68_devlist); -EXPORT_SYMBOL(tw68_devlist); -DEFINE_MUTEX(tw68_devlist_lock); -EXPORT_SYMBOL(tw68_devlist_lock); -static LIST_HEAD(mops_list); -static unsigned int tw68_devcount; /* curr tot num of devices present */ -int (*tw68_dmasound_init)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_init); -int (*tw68_dmasound_exit)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_exit); +static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); -#define dprintk(level, fmt, arg...) if (core_debug & (level)) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +static atomic_t tw68_instance = ATOMIC_INIT(0); /* ------------------------------------------------------------------ */ -void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - BUG_ON(in_interrupt()); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) - videobuf_waiton(&buf->vb, 0, 0); -#else - videobuf_waiton(q, &buf->vb, 0, 0); -#endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) - videobuf_dma_unmap(q, dma); -#else - videobuf_dma_unmap(q->dev, dma); -#endif - videobuf_dma_free(dma); - /* if no risc area allocated, btcx_riscmem_free just returns */ - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -/* ------------------------------------------------------------------ */ -/* ------------- placeholders for later development ----------------- */ - -static int tw68_input_init1(struct tw68_dev *dev) -{ - return 0; -} - -static void tw68_input_fini(struct tw68_dev *dev) -{ - return; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) -{ - return; -} - -static void tw68_ir_stop(struct tw68_dev *dev) -{ - return; -} -#endif - -/* ------------------------------------------------------------------ */ /* - * Buffer handling routines - * - * These routines are "generic", i.e. are intended to be used by more - * than one module, e.g. the video and the transport stream modules. - * To accomplish this generality, callbacks are used whenever some - * module-specific test or action is required. + * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps + * the PCI ID database up to date. Note that the entries must be + * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ - -/* resends a current buffer in queue after resume */ -int tw68_buffer_requeue(struct tw68_dev *dev, - struct tw68_dmaqueue *q) -{ - struct tw68_buf *buf, *prev; - - dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, - buf, buf->vb.i); - q->start_dma(dev, q, buf); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); - /* if nothing precedes this one */ - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); - buf->activate(dev, buf, NULL); - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - - } else if (q->buf_compat(prev, buf) && - (prev->fmt == buf->fmt)) { - list_move_tail(&buf->vb.queue, &q->active); - buf->activate(dev, buf, NULL); - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", - __func__, buf, buf->vb.i); - } else { - dprintk(DBG_BUFF, "%s: no action taken\n", __func__); - return 0; - } - prev = buf; - } -} - -/* nr of (tw68-)pages for the given buffer size */ -static int tw68_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - -/* calc max # of buffers from size (must not exceed the 4MB virtual - * address space per DMA channel) */ -int tw68_buffer_count(unsigned int size, unsigned int count) -{ - unsigned int maxcount; - - maxcount = 1024 / tw68_buffer_pages(size); - if (count > maxcount) - count = maxcount; - return count; -} - -/* - * tw68_wakeup - * - * Called when the driver completes filling a buffer, and tasks waiting - * for the data need to be awakened. - */ -void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) -{ - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (list_empty(&q->active)) { - dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", - __func__); - del_timer(&q->timeout); - return; - } - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - do_gettimeofday(&buf->vb.ts); - buf->vb.field_count = (*fc)++; - dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", - __func__, buf, buf->vb.i, *fc); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); -} - -/* - * tw68_buffer_queue - * - * Add specified buffer to specified queue - */ -void tw68_buffer_queue(struct tw68_dev *dev, - struct tw68_dmaqueue *q, - struct tw68_buf *buf) -{ - struct tw68_buf *prev; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - assert_spin_locked(&dev->slock); - dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); - - /* append a 'JUMP to stopper' to the buffer risc program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - - /* if this buffer is not "compatible" (in dimensions and format) - * with the currently active chain of buffers, we must change - * settings before filling it; if a previous buffer has already - * been determined to require changes, this buffer must follow - * it. To do this, we maintain a "queued" chain. If that - * chain exists, append this buffer to it */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", - __func__, buf, buf->vb.i); - - /* else if the 'active' chain doesn't yet exist we create it now */ - } else if (list_empty(&q->active)) { - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - list_add_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); /* 1st one - start dma */ - /* TODO - why have we removed buf->count and q->count? */ - buf->activate(dev, buf, NULL); - - /* else we would like to put this buffer on the tail of the - * active chain, provided it is "compatible". */ - } else { - /* "compatibility" depends upon the type of buffer */ - prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); - if (q->buf_compat(prev, buf)) { - /* If "compatible", append to active chain */ - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* the param 'prev' is only for debug printing */ - buf->activate(dev, buf, prev); - list_add_tail(&buf->vb.queue, &q->active); - dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", - __func__, buf, buf->vb.i); - } else { - /* If "incompatible", append to queued chain */ - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " - "to queued\n", __func__, buf, buf->vb.i); - } - } -} - -/* - * tw68_buffer_timeout - * - * This routine is set as the video_q.timeout.function - * - * Log the event, try to reset the h/w. - * Flag the current buffer as failed, try to start again with next buff - */ -void tw68_buffer_timeout(unsigned long data) -{ - struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - unsigned long flags; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - spin_lock_irqsave(&dev->slock, flags); - - /* flag all current active buffers as failed */ - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - tw68_buffer_requeue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} +struct pci_device_id tw68_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)}, + {0,} +}; /* ------------------------------------------------------------------ */ -/* early init (no i2c, no irq) */ -/* Called from tw68_hw_init1 and tw68_resume */ -static int tw68_hw_enable1(struct tw68_dev *dev) -{ - return 0; -} /* * The device is given a "soft reset". According to the specifications, @@ -367,7 +91,6 @@ static int tw68_hw_enable1(struct tw68_dev *dev) */ static int tw68_hw_init1(struct tw68_dev *dev) { - dprintk(DBG_FLOW, "%s: called\n", __func__); /* Assure all interrupts are disabled */ tw_writel(TW68_INTMASK, 0); /* 020 */ /* Clear any pending interrupts */ @@ -415,7 +138,7 @@ static int tw68_hw_init1(struct tw68_dev *dev) tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ -// tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ +/* tw_writeb(TW68_SYNCT, 0x38);*/ /* 294 Sync amplitude */ tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ @@ -465,80 +188,9 @@ static int tw68_hw_init1(struct tw68_dev *dev) /* Initialize any subsystems */ tw68_video_init1(dev); - tw68_vbi_init1(dev); - if (card_has_mpeg(dev)) - tw68_ts_init1(dev); - tw68_input_init1(dev); - - /* Do any other h/w early initialisation at this point */ - tw68_hw_enable1(dev); - - return 0; -} - -/* late init (with i2c + irq) */ -static int tw68_hw_enable2(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_I2C_INTS; -#endif - tw_setl(TW68_INTMASK, dev->pci_irqmask); return 0; } -static int tw68_hw_init2(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - tw68_video_init2(dev); /* initialise video function first */ - tw68_tvaudio_init2(dev);/* audio next */ - - /* all other board-related things, incl. enabling interrupts */ - tw68_hw_enable2(dev); - return 0; -} - -/* shutdown */ -static int tw68_hwfini(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (card_has_mpeg(dev)) - tw68_ts_fini(dev); - tw68_input_fini(dev); - tw68_vbi_fini(dev); - tw68_tvaudio_fini(dev); - return 0; -} - -static void __devinit must_configure_manually(void) -{ - unsigned int i, p; - - printk(KERN_WARNING - "tw68: \n" - "tw68: Congratulations! Your TV card vendor saved a few\n" - "tw68: cents for a eeprom, thus your pci board has no\n" - "tw68: subsystem ID and I can't identify it automatically\n" - "tw68: \n" - "tw68: I feel better now. Ok, here is the good news:\n" - "tw68: You can use the card= insmod option to specify\n" - "tw68: which board you have. The list:\n"); - for (i = 0; i < tw68_bcount; i++) { - printk(KERN_WARNING "tw68: card=%d -> %-40.40s", - i, tw68_boards[i].name); - for (p = 0; tw68_pci_tbl[p].driver_data; p++) { - if (tw68_pci_tbl[p].driver_data != i) - continue; - printk(" %04x:%04x", - tw68_pci_tbl[p].subvendor, - tw68_pci_tbl[p].subdevice); - } - printk("\n"); - } -} - - static irqreturn_t tw68_irq(int irq, void *dev_id) { struct tw68_dev *dev = dev_id; @@ -548,126 +200,39 @@ static irqreturn_t tw68_irq(int irq, void *dev_id) status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; /* Check if anything to do */ if (0 == status) - return IRQ_RETVAL(0); /* Nope - return */ + return IRQ_NONE; /* Nope - return */ for (loop = 0; loop < 10; loop++) { if (status & dev->board_virqmask) /* video interrupt */ tw68_irq_video_done(dev, status); -#ifdef TW68_TESTING - if (status & TW68_I2C_INTS) - tw68_irq_i2c(dev, status); -#endif status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; if (0 == status) - goto out; + return IRQ_HANDLED; } - dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" - " (orig 0x%08x, cur 0x%08x)", - dev->name, orig, tw_readl(TW68_INTSTAT)); - dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " - "0x%08x ****\n", dev->name, - dev->pci_irqmask, dev->board_virqmask); + dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)", + dev->name, orig, tw_readl(TW68_INTSTAT)); + dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n", + dev->name, dev->pci_irqmask, dev->board_virqmask); tw_clearl(TW68_INTMASK, dev->pci_irqmask); -out: - return IRQ_RETVAL(1); -} - -int tw68_set_dmabits(struct tw68_dev *dev) -{ - return 0; -} - -static struct video_device *vdev_init(struct tw68_dev *dev, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->parent = &dev->pci->dev; - vfd->release = video_device_release; - /* vfd->debug = tw_video_debug; */ - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, tw68_boards[dev->board].name); - return vfd; + return IRQ_HANDLED; } -static void tw68_unregister_video(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (dev->video_dev) { - if (-1 != dev->video_dev->minor) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } - if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } -} - -static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - int err; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (NULL != dev->mops) - return; - if (tw68_boards[dev->board].mpeg != ops->type) - return; - err = ops->init(dev); - if (0 != err) - return; - dev->mops = ops; -} - -static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - - if (NULL == dev->mops) - return; - if (dev->mops != ops) - return; - dev->mops->fini(dev); - dev->mops = NULL; -} - -static int __devinit tw68_initdev(struct pci_dev *pci_dev, +static int tw68_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct tw68_dev *dev; - struct tw68_mpeg_ops *mops; + int vidnr = -1; int err; - if (tw68_devcount == TW68_MAXBOARDS) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; + dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68", + &tw68_instance); + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); if (err) - goto fail0; + return err; /* pci init */ dev->pci = pci_dev; @@ -676,33 +241,10 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, goto fail1; } - dev->nr = tw68_devcount; - sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); + dev->name = dev->v4l2_dev.name; - /* pci quirks */ - if (pci_pci_problems) { - if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", - dev->name); - if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", - dev->name); - if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", - dev->name); - if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", - dev->name); -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " - "-- latency fixup\n", dev->name); - latency = 0x0A; - } -#endif - } if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", + pr_info("%s: setting pci latency timer to %d\n", dev->name, latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } @@ -710,13 +252,12 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, - (unsigned long long)pci_resource_start(pci_dev, 0)); + pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); + pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail1; } @@ -730,7 +271,7 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->vdecoder = TW6801; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; - case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ + case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */ dev->vdecoder = TW6804; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; @@ -739,35 +280,13 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; } - /* board config */ - dev->board = pci_id->driver_data; - if (card[dev->nr] >= 0 && - card[dev->nr] < tw68_bcount) - dev->board = card[dev->nr]; - if (TW68_BOARD_NOAUTO == dev->board) { - must_configure_manually(); - dev->board = TW68_BOARD_UNKNOWN; - } - dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = tw68_boards[dev->board].tuner_type; - dev->tuner_addr = tw68_boards[dev->board].tuner_addr; - dev->radio_type = tw68_boards[dev->board].radio_type; - dev->radio_addr = tw68_boards[dev->board].radio_addr; - dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; - if (UNSET != tuner[dev->nr]) - dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, pci_dev->subsystem_vendor, - pci_dev->subsystem_device, tw68_boards[dev->board].name, - dev->board, dev->autodetected ? - "autodetected" : "insmod option"); /* get mmio */ if (!request_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0), dev->name)) { err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + pr_err("%s: can't get MMIO memory @ 0x%llx\n", dev->name, (unsigned long long)pci_resource_start(pci_dev, 0)); goto fail1; @@ -777,185 +296,75 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + pr_err("%s: can't ioremap() MMIO memory\n", dev->name); goto fail2; } /* initialize hardware #1 */ - /* First, take care of anything unique to a particular card */ - tw68_board_init1(dev); /* Then do any initialisation wanted before interrupts are on */ tw68_hw_init1(dev); /* get irq */ - err = request_irq(pci_dev->irq, tw68_irq, + err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); goto fail3; } -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_SBDONE; - tw_setl(TW68_INTMASK, dev->pci_irqmask); - printk(KERN_INFO "Calling tw68_i2c_register\n"); - /* Register the i2c bus */ - tw68_i2c_register(dev); -#endif - /* * Now do remainder of initialisation, first for * things unique for this card, then for general board */ - tw68_board_init2(dev); - - tw68_hw_init2(dev); - -#if 0 - /* load i2c helpers */ - if (card_is_empress(dev)) { - struct v4l2_subdev *sd = - v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", - "saa6752hs", 0x20); - - if (sd) - sd->grp_id = GRP_EMPRESS; - } - - request_submodules(dev); -#endif - - v4l2_prio_init(&dev->prio); - - mutex_lock(&tw68_devlist_lock); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_attach(mops, dev); - list_add_tail(&dev->devlist, &tw68_devlist); - mutex_unlock(&tw68_devlist_lock); - - /* check for signal */ - tw68_irq_video_signalchange(dev); - -#if 0 - if (TUNER_ABSENT != dev->tuner_type) - tw_call_all(dev, core, s_standby, 0); -#endif - - dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); - err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, - video_nr[dev->nr]); + if (dev->instance < TW68_MAXBOARDS) + vidnr = video_nr[dev->instance]; + /* initialise video function first */ + err = tw68_video_init2(dev, vidnr); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_err("%s: can't register video device\n", dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->num); - - dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); - - err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register vbi device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device vbi%d\n", - dev->name, dev->vbi_dev->num); - - if (card_has_radio(dev)) { - dev->radio_dev = vdev_init(dev, &tw68_radio_template, - "radio"); - err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->nr]); - if (err < 0) { - /* TODO - need to unregister vbi? */ - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device radio%d\n", - dev->name, dev->radio_dev->num); - } - - /* everything worked */ - tw68_devcount++; + tw_setl(TW68_INTMASK, dev->pci_irqmask); - if (tw68_dmasound_init && !dev->dmasound.priv_data) - tw68_dmasound_init(dev); + pr_info("%s: registered device %s\n", + dev->name, video_device_node_name(&dev->vdev)); return 0; - fail4: - tw68_unregister_video(dev); -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - free_irq(pci_dev->irq, dev); - fail3: - tw68_hwfini(dev); +fail4: + video_unregister_device(&dev->vdev); +fail3: iounmap(dev->lmmio); - fail2: +fail2: release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); - fail1: +fail1: v4l2_device_unregister(&dev->v4l2_dev); - fail0: - kfree(dev); return err; } -static void __devexit tw68_finidev(struct pci_dev *pci_dev) +static void tw68_finidev(struct pci_dev *pci_dev) { struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - struct tw68_mpeg_ops *mops; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - /* Release DMA sound modules if present */ - if (tw68_dmasound_exit && dev->dmasound.priv_data) - tw68_dmasound_exit(dev); /* shutdown subsystems */ - tw68_hwfini(dev); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); tw_writel(TW68_INTMASK, 0); /* unregister */ - mutex_lock(&tw68_devlist_lock); - list_del(&dev->devlist); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_detach(mops, dev); - mutex_unlock(&tw68_devlist_lock); - tw68_devcount--; - -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - tw68_unregister_video(dev); - - - /* the DMA sound modules should be unloaded before reaching - this, but just in case they are still present... */ - if (dev->dmasound.priv_data != NULL) { - free_irq(pci_dev->irq, &dev->dmasound); - dev->dmasound.priv_data = NULL; - } - + video_unregister_device(&dev->vdev); + v4l2_ctrl_handler_free(&dev->hdl); /* release resources */ - free_irq(pci_dev->irq, dev); iounmap(dev->lmmio); release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); v4l2_device_unregister(&dev->v4l2_dev); - - /* free memory */ - kfree(dev); } #ifdef CONFIG_PM @@ -966,28 +375,15 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - dprintk(DBG_FLOW, "%s: called\n", __func__); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask &= ~TW68_VID_INTS; tw_writel(TW68_INTMASK, 0); - dev->insuspend = 1; synchronize_irq(pci_dev->irq); - /* Disable timeout timers - if we have active buffers, we will - fill them on resume*/ - - del_timer(&dev->video_q.timeout); - del_timer(&dev->vbi_q.timeout); - del_timer(&dev->ts_q.timeout); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_stop(dev); -#endif - pci_save_state(pci_dev); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + vb2_discard_done(&dev->vidq); return 0; } @@ -997,54 +393,25 @@ static int tw68_resume(struct pci_dev *pci_dev) struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); + struct tw68_buf *buf; unsigned long flags; - dprintk(DBG_FLOW, "%s: called\n", __func__); pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); /* Do things that are done in tw68_initdev , except of initializing memory structures.*/ - tw68_board_init1(dev); - - /* tw68_hw_init1 */ - if (tw68_boards[dev->board].video_out) - tw68_videoport_init(dev); - if (card_has_mpeg(dev)) - tw68_ts_init_hw(dev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_start(dev, dev->remote); -#endif - tw68_hw_enable1(dev); - msleep(100); - tw68_board_init2(dev); - - /*tw68_hw_init2*/ tw68_set_tvnorm_hw(dev); - tw68_tvaudio_setmute(dev); -/* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ - tw68_tvaudio_init(dev); - tw68_irq_video_signalchange(dev); /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); - tw68_buffer_requeue(dev, &dev->video_q); - tw68_buffer_requeue(dev, &dev->vbi_q); - tw68_buffer_requeue(dev, &dev->ts_q); - - /* FIXME: Disable DMA audio sound - temporary till proper support - is implemented*/ + buf = container_of(dev->active.next, struct tw68_buf, list); - dev->dmasound.dma_running = 0; + tw68_video_start_dma(dev, buf); - /* start DMA now*/ - dev->insuspend = 0; - smp_wmb(); - tw68_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); return 0; @@ -1057,35 +424,11 @@ static struct pci_driver tw68_pci_driver = { .name = "tw68", .id_table = tw68_pci_tbl, .probe = tw68_initdev, - .remove = __devexit_p(tw68_finidev), + .remove = tw68_finidev, #ifdef CONFIG_PM .suspend = tw68_suspend, .resume = tw68_resume #endif }; -static int tw68_init(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - INIT_LIST_HEAD(&tw68_devlist); - printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", - (TW68_VERSION_CODE >> 16) & 0xff, - (TW68_VERSION_CODE >> 8) & 0xff, - TW68_VERSION_CODE & 0xff); -#if 0 - printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&tw68_pci_driver); -} - -static void module_cleanup(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - pci_unregister_driver(&tw68_pci_driver); -} - -module_init(tw68_init); -module_exit(module_cleanup); +module_pci_driver(tw68_pci_driver); diff --git a/drivers/media/pci/tw68/tw68-i2c.c b/drivers/media/pci/tw68/tw68-i2c.c deleted file mode 100644 index 38659d0b1e18..000000000000 --- a/drivers/media/pci/tw68/tw68-i2c.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * tw68 code to handle the i2c interface. - * - * Much of this code is derived from the bt87x driver. The original - * work was by Gerd Knorr; more recently the code was enhanced by Mauro - * Carvalho Chehab. Their work is gratefully acknowledged. Full credit - * goes to them - any problems within this code are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "tw68.h" -#include -#include - -/*----------------------------------------------------------------*/ - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - -#if 0 -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#endif - -#define d1printk if (1 == i2c_debug) printk - -#define I2C_CLOCK 0xa6 /* 99.4 kHz */ - -/*----------------------------------------------------------------------*/ -/* Although the TW68xx i2c controller has a "hardware" mode, where all of - * the low-level i2c/smbbus is handled by the chip, it appears that mode - * is not suitable for linux i2c handling routines because extended "bursts" - * of data (sequences of bytes without intervening START/STOP bits) are - * not possible. Instead, we put the chip into "software" mode, and handle - * the i2c bus at a low level. To accomplish this, we use the routines - * from the i2c modules. - * - * Because the particular boards which I had for testing did not have any - * devices attached to the i2c bus, I have been unable to test these - * routines. - */ - -/*----------------------------------------------------------------------*/ -/* I2C functions - "bit-banging" adapter (software i2c) */ - -/* tw68_bit_setcl - * Handles "toggling" the i2c clock bit - */ -static void tw68_bit_setscl(void *data, int state) -{ - struct tw68_dev *dev = data; - - tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B); -} - -/* tw68_bit_setsda - * Handles "toggling" the i2c data bit - */ -static void tw68_bit_setsda(void *data, int state) -{ - struct tw68_dev *dev = data; - - tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B); -} - -/* tw68_bit_getscl - * - * Returns the current state of the clock bit - */ -static int tw68_bit_getscl(void *data) -{ - struct tw68_dev *dev = data; - - return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0; -} - -/* tw68_bit_getsda - * - * Returns the current state of the data bit - */ -static int tw68_bit_getsda(void *data) -{ - struct tw68_dev *dev = data; - - return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0; -} - -static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = { - .setsda = tw68_bit_setsda, - .setscl = tw68_bit_setscl, - .getsda = tw68_bit_getsda, - .getscl = tw68_bit_getscl, - .udelay = 16, - .timeout = 200, -}; - -static struct i2c_client tw68_client_template = { - .name = "tw68 internal", -}; - -/*----------------------------------------------------------------*/ - -static int attach_inform(struct i2c_client *client) -{ -/* struct tw68_dev *dev = client->adapter->algo_data; */ - - d1printk("%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, client->name); - - switch (client->addr) { - /* No info yet on what addresses to expect */ - } - - return 0; -} - -static struct i2c_adapter tw68_adap_sw_template = { - .owner = THIS_MODULE, - .name = "tw68_sw", - .client_register = attach_inform, -}; - -static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata, - int len) -{ - unsigned char buf; - int i, err; - - dev->i2c_client.addr = 0xa0 >> 1; - buf = 256 - len; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (1 != err) { - printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n", - dev->name, err); - return -1; - } - err = i2c_master_recv(&dev->i2c_client, eedata, len); - if (len != err) { - printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", - dev->name, err); - return -1; - } - - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", - dev->name, i); - printk(KERN_INFO " %02x", eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - return 0; -} - -#if 0 -static char *i2c_devs[128] = { - [0xa0 >> 1] = "eeprom", -}; - -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, 1); - if (rc < 0) - continue; - printk(KERN_INFO "%s: i2c scan: found device " - "@ 0x%x [%s]\n", name, i << 1, - i2c_devs[i] ? i2c_devs[i] : "???"); - } -} -#endif - -int __devinit tw68_i2c_register(struct tw68_dev *dev) -{ - int rc; - -printk(KERN_DEBUG "%s: Registering i2c module\n", __func__); - tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */ - - memcpy(&dev->i2c_client, &tw68_client_template, - sizeof(tw68_client_template)); - - memcpy(&dev->i2c_adap, &tw68_adap_sw_template, - sizeof(tw68_adap_sw_template)); - dev->i2c_adap.algo_data = &dev->i2c_algo; - dev->i2c_adap.dev.parent = &dev->pci->dev; - - memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template, - sizeof(tw68_i2c_algo_bit_template)); - dev->i2c_algo.data = dev; - /* TODO - may want to set better name (see bttv code) */ - - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); - dev->i2c_client.adapter = &dev->i2c_adap; - - /* Assure chip is in "software" mode */ - tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK); - tw68_bit_setscl(dev, 1); - tw68_bit_setsda(dev, 1); - - rc = i2c_bit_add_bus(&dev->i2c_adap); - - tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); -#if 0 - if (i2c_scan) - do_i2c_scan(dev->name, &dev->i2c_client); -#endif - - return rc; -} - -int tw68_i2c_unregister(struct tw68_dev *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h index 314bc43cd9d3..f60b3a896fa7 100644 --- a/drivers/media/pci/tw68/tw68-reg.h +++ b/drivers/media/pci/tw68/tw68-reg.h @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) William M. Brack + * Copyright (C) William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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 @@ -19,10 +23,6 @@ * 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 _TW68_REG_H_ diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c index 66273bbd51c5..7439db212a69 100644 --- a/drivers/media/pci/tw68/tw68-risc.c +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -9,7 +9,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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 @@ -20,16 +24,10 @@ * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "tw68.h" -#define NO_SYNC_LINE (-1U) - /** * @rp pointer to current risc program position * @sglist pointer to "scatter-gather list" of buffer pointers @@ -38,32 +36,35 @@ * @bpl number of bytes per scan line * @padding number of bytes of padding to add * @lines number of lines in field - * @lpi lines per IRQ, or 0 to not generate irqs - * Note: IRQ to be generated _after_ lpi lines are transferred + * @jump insert a jump at the start */ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) + unsigned int lines, bool jump) { struct scatterlist *sg; unsigned int line, todo, done; - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) { - if (sync_line == 1) - *(rp++) = cpu_to_le32(RISC_SYNCO); - else - *(rp++) = cpu_to_le32(RISC_SYNCE); + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); *(rp++) = 0; } + + /* sync instruction */ + if (sync_line == 1) + *(rp++) = cpu_to_le32(RISC_SYNCO); + else + *(rp++) = cpu_to_le32(RISC_SYNCE); + *(rp++) = 0; + /* scan lines */ sg = sglist; for (line = 0; line < lines; line++) { /* calculate next starting position */ while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); } if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ @@ -86,7 +87,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, done); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); todo -= done; - sg++; + sg = sg_next(sg); /* succeeding fragments have no offset */ while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_INLINE | @@ -94,7 +95,7 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); todo -= sg_dma_len(sg); - sg++; + sg = sg_next(sg); done += sg_dma_len(sg); } if (todo) { @@ -107,9 +108,6 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, offset = todo; } offset += padding; - /* If this line needs an interrupt, put it in */ - if (lpi && line > 0 && !(line % lpi)) - *(rp-2) |= RISC_INT_BIT; } return rp; @@ -118,25 +116,25 @@ static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist, /** * tw68_risc_buffer * - * This routine is called by tw68-video. It allocates - * memory for the dma controller "program" and then fills in that - * memory with the appropriate "instructions". + * This routine is called by tw68-video. It allocates + * memory for the dma controller "program" and then fills in that + * memory with the appropriate "instructions". * - * @pci_dev structure with info about the pci - * slot which our device is in. - * @risc structure with info about the memory - * used for our controller program. - * @sglist scatter-gather list entry - * @top_offset offset within the risc program area for the - * first odd frame line - * @bottom_offset offset within the risc program area for the - * first even frame line - * @bpl number of data bytes per scan line - * @padding number of extra bytes to add at end of line - * @lines number of scan lines + * @pci_dev structure with info about the pci + * slot which our device is in. + * @risc structure with info about the memory + * used for our controller program. + * @sglist scatter-gather list entry + * @top_offset offset within the risc program area for the + * first odd frame line + * @bottom_offset offset within the risc program area for the + * first even frame line + * @bpl number of data bytes per scan line + * @padding number of extra bytes to add at end of line + * @lines number of scan lines */ int tw68_risc_buffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct tw68_buf *buf, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, @@ -146,7 +144,6 @@ int tw68_risc_buffer(struct pci_dev *pci, { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -155,29 +152,31 @@ int tw68_risc_buffer(struct pci_dev *pci, fields++; /* * estimate risc mem: worst case is one write per page border + - * one write per scan line + syncs + jump (all 2 dwords). + * one write per scan line + syncs + 2 jumps (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 = fields * (1 + (((bpl + padding) * lines) / - PAGE_SIZE) + lines) + 2; - rc = btcx_riscmem_alloc(pci, risc, instructions * 8); - if (rc < 0) - return rc; + PAGE_SIZE) + lines) + 4; + buf->size = instructions * 8; + buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma); + if (buf->cpu == NULL) + return -ENOMEM; /* write risc instructions */ - rp = risc->cpu; + rp = buf->cpu; if (UNSET != top_offset) /* generates SYNCO */ rp = tw68_risc_field(rp, sglist, top_offset, 1, - bpl, padding, lines, 0); + bpl, padding, lines, true); if (UNSET != bottom_offset) /* generates SYNCE */ rp = tw68_risc_field(rp, sglist, bottom_offset, 2, - bpl, padding, lines, 0); + bpl, padding, lines, top_offset == UNSET); /* save pointer to jmp instruction address */ - risc->jmp = rp; + buf->jmp = rp; + buf->cpu[1] = cpu_to_le32(buf->dma + 8); /* assure risc buffer hasn't overflowed */ - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); + BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size); return 0; } @@ -204,65 +203,28 @@ static void tw68_risc_decode(u32 risc, u32 addr) p = RISC_OP(risc); if (!(risc & 0x80000000) || !instr[p].name) { - printk(KERN_DEBUG "0x%08x [ INVALID ]\n", risc); + pr_debug("0x%08x [ INVALID ]\n", risc); return; } - printk(KERN_DEBUG "0x%08x %-9s IRQ=%d", + pr_debug("0x%08x %-9s IRQ=%d", risc, instr[p].name, (risc >> 27) & 1); if (instr[p].has_data_type) - printk(KERN_DEBUG " Type=%d", (risc >> 24) & 7); + pr_debug(" Type=%d", (risc >> 24) & 7); if (instr[p].has_byte_info) - printk(KERN_DEBUG " Start=0x%03x Count=%03u", + pr_debug(" Start=0x%03x Count=%03u", (risc >> 12) & 0xfff, risc & 0xfff); if (instr[p].has_addr) - printk(KERN_DEBUG " StartAddr=0x%08x", addr); - printk(KERN_DEBUG "\n"); + pr_debug(" StartAddr=0x%08x", addr); + pr_debug("\n"); } -void tw68_risc_program_dump(struct tw68_core *core, - struct btcx_riscmem *risc) +void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf) { - __le32 *addr; + const __le32 *addr; - printk(KERN_DEBUG "%s: risc_program_dump: risc=%p, " - "risc->cpu=0x%p, risc->jmp=0x%p\n", - core->name, risc, risc->cpu, risc->jmp); - for (addr = risc->cpu; addr <= risc->jmp; addr += 2) + pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n", + core->name, buf, buf->cpu, buf->jmp); + for (addr = buf->cpu; addr <= buf->jmp; addr += 2) tw68_risc_decode(*addr, *(addr+1)); } -EXPORT_SYMBOL_GPL(tw68_risc_program_dump); #endif - -/* - * tw68_risc_stopper - * Normally, the risc code generated for a buffer ends with a - * JUMP instruction to direct the DMAP processor to the code for - * the next buffer. However, when there is no additional buffer - * currently available, the code instead jumps to this routine. - * - * My first try for a "stopper" program was just a simple - * "jump to self" instruction. Unfortunately, this caused the - * video FIFO to overflow. My next attempt was to just disable - * the DMAP processor. Unfortunately, this caused the video - * decoder to lose its synchronization. The solution to this was to - * add a "Sync-Odd" instruction, which "eats" all the video data - * until the start of the next odd field. - */ -int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 8*4); - if (rc < 0) - return rc; - - /* write risc inststructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_SYNCO); - *(rp++) = 0; - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - risc->jmp = risc->cpu; - return 0; -} diff --git a/drivers/media/pci/tw68/tw68-ts.c b/drivers/media/pci/tw68/tw68-ts.c deleted file mode 100644 index dacd6e621bae..000000000000 --- a/drivers/media/pci/tw68/tw68-ts.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * tw68_ts.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tw68.h" - -int tw68_ts_init1(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_ts_ini(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_ts_fini(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status) -{ - return; -} - -int tw68_ts_register(struct tw68_mpeg_ops *ops) -{ - return 0; -} - -void tw68_ts_unregister(struct tw68_mpeg_ops *ops) -{ - return; -} - -int tw68_ts_init_hw(struct tw68_dev *dev) -{ - return 0; -} - - diff --git a/drivers/media/pci/tw68/tw68-tvaudio.c b/drivers/media/pci/tw68/tw68-tvaudio.c deleted file mode 100644 index 656d462196f4..000000000000 --- a/drivers/media/pci/tw68/tw68-tvaudio.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * tw68_controls.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tw68.h" - -int tw68_tvaudio_rx2mode(u32 rx) -{ - return 0; -} - -void tw68_tvaudio_setmute(struct tw68_dev *dev) -{ - return; -} - -void tw68_tvaudio_setinput(struct tw68_dev *dev, struct tw68_input *in) -{ - return; -} - -void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level) -{ - return; -} - -int tw68_tvaudio_getstereo(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_tvaudio_init(struct tw68_dev *dev) -{ - return; -} - -int tw68_tvaudio_init2(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_tvaudio_fini(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_tvaudio_do_scan(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_enable_i2s(struct tw68_dev *dev) -{ - return; -} - diff --git a/drivers/media/pci/tw68/tw68-vbi.c b/drivers/media/pci/tw68/tw68-vbi.c deleted file mode 100644 index fbad3b998848..000000000000 --- a/drivers/media/pci/tw68/tw68-vbi.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * tw68_controls.c - * Part of the device driver for Techwell 68xx based cards - * - * Much of this code is derived from the cx88 and sa7134 drivers, which - * were in turn derived from the bt87x driver. The original work was by - * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab, - * Hans Verkuil, Andy Walls and many others. Their work is gratefully - * acknowledged. Full credit goes to them - any problems within this code - * are mine. - * - * Copyright (C) 2009 William M. Brack - * - * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "tw68.h" - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) { - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); - return 0; -} -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); - return 0; -} -static void buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); -} -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - printk(KERN_INFO "%s: shouldn't be here!\n", __func__); -} -struct videobuf_queue_ops tw68_vbi_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ - -int tw68_vbi_init1(struct tw68_dev *dev) -{ - return 0; -} - -int tw68_vbi_fini(struct tw68_dev *dev) -{ - return 0; -} - -void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status) -{ - return; -} - diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index ca08ca38d3bd..66fae2345fdd 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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 @@ -19,39 +23,16 @@ * 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., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include -#include +#include +#include #include "tw68.h" #include "tw68-reg.h" -unsigned int video_debug; - -static unsigned int gbuffers = 8; -static unsigned int noninterlaced; /* 0 */ -static unsigned int gbufsz = 768*576*4; -static unsigned int gbufsz_max = 768*576*4; -static char secam[] = "--"; - -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers, "number of capture buffers, range 2-32"); -module_param(noninterlaced, int, 0644); -MODULE_PARM_DESC(noninterlaced, "capture non interlaced video"); -module_param_string(secam, secam, sizeof(secam), 0644); -MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); - -#define dprintk(level, fmt, arg...) if (video_debug & (level)) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) - /* ------------------------------------------------------------------ */ /* data structs for video */ /* @@ -60,7 +41,7 @@ MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); * as "planar". These affect overlay mode, and are flagged with a field * ".planar" in the format. Do we need to implement this in this driver? */ -static struct tw68_format formats[] = { +static const struct tw68_format formats[] = { { .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, @@ -145,47 +126,8 @@ static struct tw68_format formats[] = { * match, then for an entry which contains the desired id. The table * entries should therefore be ordered in ascending order of specificity. */ -static struct tw68_tvnorm tvnorms[] = { +static const struct tw68_tvnorm tvnorms[] = { { - .name = "PAL-BG", - .id = V4L2_STD_PAL_BG, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { - .name = "PAL-I", - .id = V4L2_STD_PAL_I, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { - .name = "PAL-DK", - .id = V4L2_STD_PAL_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, - - }, { .name = "PAL", /* autodetect */ .id = V4L2_STD_PAL, NORM_625_50, @@ -197,7 +139,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPALBDGHI, - }, { .name = "NTSC", .id = V4L2_STD_NTSC, @@ -210,46 +151,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x0e, .vgate_misc = 0x18, .format = VideoFormatNTSC, - - }, { - .name = "SECAM-DK", - .id = V4L2_STD_SECAM_DK, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - - }, { - .name = "SECAM-L", - .id = V4L2_STD_SECAM_L, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - - }, { - .name = "SECAM-LC", - .id = V4L2_STD_SECAM_LC, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x1b, - .chroma_ctrl1 = 0xd1, - .chroma_gain = 0x80, - .chroma_ctrl2 = 0x00, - .vgate_misc = 0x1c, - .format = VideoFormatSECAM, - }, { .name = "SECAM", .id = V4L2_STD_SECAM, @@ -262,7 +163,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x00, .vgate_misc = 0x1c, .format = VideoFormatSECAM, - }, { .name = "PAL-M", .id = V4L2_STD_PAL_M, @@ -275,7 +175,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x0e, .vgate_misc = 0x18, .format = VideoFormatPALM, - }, { .name = "PAL-Nc", .id = V4L2_STD_PAL_Nc, @@ -288,7 +187,6 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPALNC, - }, { .name = "PAL-60", .id = V4L2_STD_PAL_60, @@ -309,127 +207,11 @@ static struct tw68_tvnorm tvnorms[] = { .chroma_ctrl2 = 0x06, .vgate_misc = 0x1c, .format = VideoFormatPAL60, - - }, { -/* - * FIXME: The following are meant to be "catch-all", and need - * to be further thought out! - */ - .name = "STD-525-60", - .id = V4L2_STD_525_60, - NORM_525_60, - - .sync_control = 0x59, - .luma_control = 0x40, - .chroma_ctrl1 = 0x89, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x0e, - .vgate_misc = 0x18, - .format = VideoFormatNTSC, - - }, { - .name = "STD-625-50", - .id = V4L2_STD_625_50, - NORM_625_50, - - .sync_control = 0x18, - .luma_control = 0x40, - .chroma_ctrl1 = 0x81, - .chroma_gain = 0x2a, - .chroma_ctrl2 = 0x06, - .vgate_misc = 0x1c, - .format = VideoFormatPALBDGHI, } }; #define TVNORMS ARRAY_SIZE(tvnorms) -static const struct v4l2_queryctrl no_ctrl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl video_ctrls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 20, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 100, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_COLOR_KILLER, - .name = "Color Killer", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_CHROMA_AGC, - .name = "Chroma AGC", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = -15, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; -static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); - -/* - * Routine to lookup a control by its ID, and return a pointer - * to the entry in the video_ctrls array for that control. - */ -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) -{ - unsigned int i; - - for (i = 0; i < CTRLS; i++) - if (video_ctrls[i].id == id) - return video_ctrls+i; - return NULL; -} - -static struct tw68_format *format_by_fourcc(unsigned int fourcc) +static const struct tw68_format *format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -439,99 +221,22 @@ static struct tw68_format *format_by_fourcc(unsigned int fourcc) return NULL; } -/* ----------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct tw68_fh *fh, unsigned int bit) -{ - struct tw68_dev *dev = fh->dev; - - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&fh->dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(DBG_FLOW, "%s: %d\n", __func__, bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct tw68_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct tw68_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct tw68_fh *fh, - unsigned int bits) -{ - struct tw68_dev *dev = fh->dev; - - BUG_ON((fh->resources & bits) != bits); - - mutex_lock(&fh->dev->lock); - fh->resources &= ~bits; - fh->dev->resources &= ~bits; - dprintk(DBG_FLOW, "%s: %d\n", __func__, bits); - mutex_unlock(&fh->dev->lock); -} /* ------------------------------------------------------------------ */ /* * Note that the cropping rectangles are described in terms of a single * frame, i.e. line positions are only 1/2 the interlaced equivalent */ -static void set_tvnorm(struct tw68_dev *dev, struct tw68_tvnorm *norm) +static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm) { - dprintk(DBG_FLOW, "%s: %s\n", __func__, norm->name); - dev->tvnorm = norm; - - /* setup cropping */ - dev->crop_bounds.left = norm->h_start; - dev->crop_defrect.left = norm->h_start; - dev->crop_bounds.width = norm->h_stop - norm->h_start + 1; - dev->crop_defrect.width = norm->h_stop - norm->h_start + 1; - - dev->crop_bounds.top = norm->video_v_start; - dev->crop_defrect.top = norm->video_v_start; - dev->crop_bounds.height = (((norm->id & V4L2_STD_525_60) ? - 524 : 624)) / 2 - dev->crop_bounds.top; - dev->crop_defrect.height = (norm->video_v_stop - - norm->video_v_start + 1); - - dev->crop_current = dev->crop_defrect; - if (norm != dev->tvnorm) { + dev->width = 720; + dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576; dev->tvnorm = norm; tw68_set_tvnorm_hw(dev); } } -static void video_mux(struct tw68_dev *dev, int input) -{ - dprintk(DBG_FLOW, "%s: input = %d [%s]\n", __func__, input, - card_in(dev, input).name); - /* - * dev->input shows current application request, - * dev->hw_input shows current hardware setting - */ - dev->input = &card_in(dev, input); - tw68_tvaudio_setinput(dev, &card_in(dev, input)); -} - /* * tw68_set_scale * @@ -544,7 +249,7 @@ static void video_mux(struct tw68_dev *dev, int input) * before scaling. HDELAY represents the number of pixels skipped * between the start of the horizontal sync and the start of the image. * HSCALE is calculated using the formula - * HSCALE = (HACTIVE / (#pixels desired)) * 256 + * HSCALE = (HACTIVE / (#pixels desired)) * 256 * * The vertical registers are similar, except based upon the total number * of lines in the image, and the first line of the image (i.e. ignoring @@ -555,16 +260,16 @@ static void video_mux(struct tw68_dev *dev, int input) * these values, especially HSCALE. * * Parameters: - * @dev pointer to the device structure, needed for - * getting current norm (as well as debug print) - * @width actual image width (from user buffer) - * @height actual image height - * @field indicates Top, Bottom or Interlaced + * @dev pointer to the device structure, needed for + * getting current norm (as well as debug print) + * @width actual image width (from user buffer) + * @height actual image height + * @field indicates Top, Bottom or Interlaced */ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, unsigned int height, enum v4l2_field field) { - + const struct tw68_tvnorm *norm = dev->tvnorm; /* set individually for debugging clarity */ int hactive, hdelay, hscale; int vactive, vdelay, vscale; @@ -573,41 +278,38 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */ height /= 2; /* we must set for 1-frame */ - dprintk(DBG_FLOW, "%s: width=%d, height=%d, both=%d\n Crop rect: " - "top=%d, left=%d, width=%d height=%d\n" - " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " - "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, + pr_debug("%s: width=%d, height=%d, both=%d\n" + " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " + "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, width, height, V4L2_FIELD_HAS_BOTH(field), - dev->crop_bounds.top, dev->crop_bounds.left, - dev->crop_bounds.width, dev->crop_bounds.height, - dev->tvnorm->h_delay, dev->tvnorm->h_start, dev->tvnorm->h_stop, - dev->tvnorm->v_delay, dev->tvnorm->video_v_start, - dev->tvnorm->video_v_stop); + norm->h_delay, norm->h_start, norm->h_stop, + norm->v_delay, norm->video_v_start, + norm->video_v_stop); switch (dev->vdecoder) { case TW6800: - hdelay = dev->tvnorm->h_delay0; + hdelay = norm->h_delay0; break; default: - hdelay = dev->tvnorm->h_delay; + hdelay = norm->h_delay; break; } - hdelay += dev->crop_bounds.left; - hactive = dev->crop_bounds.width; + + hdelay += norm->h_start; + hactive = norm->h_stop - norm->h_start + 1; hscale = (hactive * 256) / (width); - vdelay = dev->tvnorm->v_delay + dev->crop_bounds.top - - dev->crop_defrect.top; - vactive = dev->crop_bounds.height; + vdelay = norm->v_delay; + vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start; vscale = (vactive * 256) / height; - dprintk(DBG_FLOW, "%s: %dx%d [%s%s,%s]\n", __func__, + pr_debug("%s: %dx%d [%s%s,%s]\n", __func__, width, height, V4L2_FIELD_HAS_TOP(field) ? "T" : "", V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", v4l2_norm_to_name(dev->tvnorm->id)); - dprintk(DBG_FLOW, "%s: hactive=%d, hdelay=%d, hscale=%d; " + pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; " "vactive=%d, vdelay=%d, vscale=%d\n", __func__, hactive, hdelay, hscale, vactive, vdelay, vscale); @@ -615,7 +317,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, ((vactive & 0x300) >> 4) | ((hdelay & 0x300) >> 6) | ((hactive & 0x300) >> 8); - dprintk(DBG_FLOW, "%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " + pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", __func__, comb, vdelay, vactive, hdelay, hactive); tw_writeb(TW68_CROP_HI, comb); @@ -625,7 +327,7 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); - dprintk(DBG_FLOW, "%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " + pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); tw_writeb(TW68_SCALE_HI, comb); tw_writeb(TW68_VSCALE_LO, vscale); @@ -636,28 +338,21 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, /* ------------------------------------------------------------------ */ -static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, - struct tw68_buf *buf) { - - dprintk(DBG_FLOW, "%s: Starting risc program\n", __func__); - /* Assure correct input */ - if (dev->hw_input != dev->input) { - dev->hw_input = dev->input; - tw_andorb(TW68_INFORM, 0x03 << 2, dev->input->vmux << 2); - } +int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) +{ /* Set cropping and scaling */ - tw68_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + tw68_set_scale(dev, dev->width, dev->height, dev->field); /* * Set start address for RISC program. Note that if the DMAP * processor is currently running, it must be stopped before * a new address can be set. */ tw_clearl(TW68_DMAC, TW68_DMAP_EN); - tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->risc.dma)); + tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->dma)); /* Clear any pending interrupts */ tw_writel(TW68_INTSTAT, dev->board_virqmask); /* Enable the risc engine and the fifo */ - tw_andorl(TW68_DMAC, 0xff, buf->fmt->twformat | + tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat | ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask |= dev->board_virqmask; tw_setl(TW68_INTMASK, dev->pci_irqmask); @@ -665,693 +360,295 @@ static int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_dmaqueue *q, } /* ------------------------------------------------------------------ */ -/* videobuf queue operations */ -/* - * check_buf_fmt - * - * callback from tw68-core buffer_queue to determine whether the - * current buffer and the previous one are "compatible" (i.e. the - * risc programs can be chained without requiring a format change) - */ -static int tw68_check_video_fmt(struct tw68_buf *prev, struct tw68_buf *buf) +/* nr of (tw68-)pages for the given buffer size */ +static int tw68_buffer_pages(int size) { - return (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt); + size = PAGE_ALIGN(size); + size += PAGE_SIZE; /* for non-page-aligned buffers */ + size /= 4096; + return size; } -/* - * buffer_setup - * - * Calculate required size of buffer and maximum number allowed - */ -static int -buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +/* calc max # of buffers from size (must not exceed the 4MB virtual + * address space per DMA channel) */ +static int tw68_buffer_count(unsigned int size, unsigned int count) { - struct tw68_fh *fh = q->priv_data; + unsigned int maxcount; - *size = fh->fmt->depth * fh->width * fh->height >> 3; - if (0 == *count) - *count = gbuffers; - *count = tw68_buffer_count(*size, *count); - return 0; + maxcount = 1024 / tw68_buffer_pages(size); + if (count > maxcount) + count = maxcount; + return count; } -static int buffer_activate(struct tw68_dev *dev, struct tw68_buf *buf, - struct tw68_buf *next) -{ - dprintk(DBG_BUFF, "%s: dev=%p, buf=%p, next=%p\n", - __func__, dev, buf, next); - if (dev->hw_input != dev->input) { - dev->hw_input = dev->input; - tw_andorb(TW68_INFORM, 0x03 << 2, - dev->hw_input->vmux << 2); - } - buf->vb.state = VIDEOBUF_ACTIVE; - /* TODO - need to assure scaling/cropping are set correctly */ - mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} +/* ------------------------------------------------------------- */ +/* vb2 queue operations */ -/* -* buffer_prepare -* -* Set the ancilliary information into the buffer structure. This -* includes generating the necessary risc program if it hasn't already -* been done for the current buffer format. -* The structure fh contains the details of the format requested by the -* user - type, width, height and #fields. This is compared with the -* last format set for the current buffer. If they differ, the risc -* code (which controls the filling of the buffer) is (re-)generated. -*/ -static int -buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct tw68_fh *fh = q->priv_data; - struct tw68_dev *dev = fh->dev; - struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - int rc, init_buffer = 0; - unsigned int maxw, maxh; - - BUG_ON(NULL == fh->fmt); - maxw = dev->tvnorm->h_stop - dev->tvnorm->h_start + 1; - maxh = 2*(dev->tvnorm->video_v_stop - dev->tvnorm->video_v_start + 1); - if (fh->width < 48 || fh->width > maxw || fh->height > maxh - || fh->height < 16) { - dprintk(DBG_UNEXPECTED, "%s: invalid dimensions - " - "fh->width=%d, fh->height=%d, maxw=%d, maxh=%d\n", - __func__, fh->width, fh->height, maxw, maxh); - return -EINVAL; - } - buf->vb.size = (fh->width * fh->height * (fh->fmt->depth)) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - dprintk(DBG_BUFF, "%s: buf - fmt=%p, width=%3d, height=%3d, " - "field=%d\n%s: fh - fmt=%p, width=%3d, height=%3d, " - "field=%d\n", __func__, buf->fmt, buf->vb.width, - buf->vb.height, buf->vb.field, __func__, fh->fmt, - fh->width, fh->height, field); - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; /* force risc code re-generation */ - } - buf->input = dev->input; + struct tw68_dev *dev = vb2_get_drv_priv(q); + unsigned tot_bufs = q->num_buffers + *num_buffers; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - init_buffer = 1; /* force risc code re-generation */ - } - dprintk(DBG_BUFF, "%s: q=%p, vb=%p, init_buffer=%d\n", - __func__, q, vb, init_buffer); - - if (init_buffer) { - buf->bpl = buf->vb.width * (buf->fmt->depth) >> 3; - dprintk(DBG_TESTING, "%s: Generating new risc code " - "[%dx%dx%d](%d)\n", __func__, buf->vb.width, - buf->vb.height, buf->fmt->depth, buf->bpl); - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, UNSET, - buf->bpl, 0, - buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - UNSET, 0, - buf->bpl, 0, - buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - tw68_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); - } - } - dprintk(DBG_BUFF, "%s: [%p/%d] - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - __func__, buf, buf->vb.i, fh->width, fh->height, - fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; + /* + * We allow create_bufs, but only if the sizeimage is the same as the + * current sizeimage. The tw68_buffer_count calculation becomes quite + * difficult otherwise. + */ + if (fmt && fmt->fmt.pix.sizeimage < sizes[0]) + return -EINVAL; + *num_planes = 1; + if (tot_bufs < 2) + tot_bufs = 2; + tot_bufs = tw68_buffer_count(sizes[0], tot_bufs); + *num_buffers = tot_bufs - q->num_buffers; - buf->vb.state = VIDEOBUF_PREPARED; - buf->activate = buffer_activate; return 0; - - fail: - tw68_dma_free(q, buf); - return rc; } /* - * buffer_queue + * The risc program for each buffers works as follows: it starts with a simple + * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the + * buffer follows and at the end we have a JUMP back to the start + 8 (skipping + * the initial JUMP). + * + * This is the program of the first buffer to be queued if the active list is + * empty and it just keeps DMAing this buffer without generating any interrupts. + * + * If a new buffer is added then the initial JUMP in the program generates an + * interrupt as well which signals that the previous buffer has been DMAed + * successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. * - * Callback whenever a buffer has been requested (by read() or QBUF) + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. */ -static void -buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void tw68_buf_queue(struct vb2_buffer *vb) { - struct tw68_fh *fh = q->priv_data; - struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct tw68_buf *prev; + unsigned long flags; + + spin_lock_irqsave(&dev->slock, flags); - tw68_buffer_queue(fh->dev, &fh->dev->video_q, buf); + /* append a 'JUMP to start of buffer' to the buffer risc program */ + buf->jmp[0] = cpu_to_le32(RISC_JUMP); + buf->jmp[1] = cpu_to_le32(buf->dma + 8); + + if (!list_empty(&dev->active)) { + prev = list_entry(dev->active.prev, struct tw68_buf, list); + buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT); + prev->jmp[1] = cpu_to_le32(buf->dma); + } + list_add_tail(&buf->list, &dev->active); + spin_unlock_irqrestore(&dev->slock, flags); } /* - * buffer_release + * buffer_prepare * - * Free a buffer previously allocated. + * Set the ancilliary information into the buffer structure. This + * includes generating the necessary risc program if it hasn't already + * been done for the current buffer format. + * The structure fh contains the details of the format requested by the + * user - type, width, height and #fields. This is compared with the + * last format set for the current buffer. If they differ, the risc + * code (which controls the filling of the buffer) is (re-)generated. */ -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static int tw68_buf_prepare(struct vb2_buffer *vb) { + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); + unsigned size, bpl; + int rc; - tw68_dma_free(q, buf); -} - -static struct videobuf_queue_ops video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/* ------------------------------------------------------------------ */ + size = (dev->width * dev->height * dev->fmt->depth) >> 3; + if (vb2_plane_size(vb, 0) < size) + return -EINVAL; + vb2_set_plane_payload(vb, 0, size); -static int tw68_g_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, - struct v4l2_control *c) -{ - const struct v4l2_queryctrl *ctrl; + rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); + if (!rc) + return -EIO; - dprintk(DBG_FLOW, "%s\n", __func__); - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = (char)tw_readb(TW68_BRIGHT); - break; - case V4L2_CID_HUE: - c->value = (char)tw_readb(TW68_HUE); - break; - case V4L2_CID_CONTRAST: - c->value = tw_readb(TW68_CONTRAST); - break; - case V4L2_CID_SATURATION: - c->value = tw_readb(TW68_SAT_U); - break; - case V4L2_CID_COLOR_KILLER: - c->value = 0 != (tw_readb(TW68_MISC2) & 0xe0); + bpl = (dev->width * dev->fmt->depth) >> 3; + switch (dev->field) { + case V4L2_FIELD_TOP: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, UNSET, bpl, 0, dev->height); break; - case V4L2_CID_CHROMA_AGC: - c->value = 0 != (tw_readb(TW68_LOOP) & 0x30); + case V4L2_FIELD_BOTTOM: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + UNSET, 0, bpl, 0, dev->height); break; - case V4L2_CID_AUDIO_MUTE: - /*hack to suppresss tvtime complaint */ - c->value = 0; + case V4L2_FIELD_SEQ_TB: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, bpl * (dev->height >> 1), + bpl, 0, dev->height >> 1); break; -#if 0 - case V4L2_CID_AUDIO_VOLUME: - c->value = dev->ctl_volume; + case V4L2_FIELD_SEQ_BT: + tw68_risc_buffer(dev->pci, buf, dma->sgl, + bpl * (dev->height >> 1), 0, + bpl, 0, dev->height >> 1); break; -#endif + case V4L2_FIELD_INTERLACED: default: - return -EINVAL; + tw68_risc_buffer(dev->pci, buf, dma->sgl, + 0, bpl, bpl, bpl, dev->height >> 1); + break; } return 0; } -static int tw68_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +static void tw68_buf_finish(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tw68_dev *dev = vb2_get_drv_priv(vq); + struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0); + struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb); + + dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE); + + pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma); +} + +static int tw68_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct tw68_dev *dev = vb2_get_drv_priv(q); + struct tw68_buf *buf = + container_of(dev->active.next, struct tw68_buf, list); + + dev->seqnr = 0; + tw68_video_start_dma(dev, buf); + return 0; +} + +static void tw68_stop_streaming(struct vb2_queue *q) { - struct tw68_fh *fh = priv; + struct tw68_dev *dev = vb2_get_drv_priv(q); + + /* Stop risc & fifo */ + tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); + while (!list_empty(&dev->active)) { + struct tw68_buf *buf = + container_of(dev->active.next, struct tw68_buf, list); - return tw68_g_ctrl_internal(fh->dev, fh, c); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } } -static int tw68_s_ctrl_value(struct tw68_dev *dev, __u32 id, int val) +static struct vb2_ops tw68_video_qops = { + .queue_setup = tw68_queue_setup, + .buf_queue = tw68_buf_queue, + .buf_prepare = tw68_buf_prepare, + .buf_finish = tw68_buf_finish, + .start_streaming = tw68_start_streaming, + .stop_streaming = tw68_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* ------------------------------------------------------------------ */ + +static int tw68_s_ctrl(struct v4l2_ctrl *ctrl) { - int err = 0; + struct tw68_dev *dev = + container_of(ctrl->handler, struct tw68_dev, hdl); - dprintk(DBG_FLOW, "%s\n", __func__); - switch (id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - tw_writeb(TW68_BRIGHT, val); + tw_writeb(TW68_BRIGHT, ctrl->val); break; case V4L2_CID_HUE: - tw_writeb(TW68_HUE, val); + tw_writeb(TW68_HUE, ctrl->val); break; case V4L2_CID_CONTRAST: - tw_writeb(TW68_CONTRAST, val); + tw_writeb(TW68_CONTRAST, ctrl->val); break; case V4L2_CID_SATURATION: - tw_writeb(TW68_SAT_U, val); - tw_writeb(TW68_SAT_V, val); + tw_writeb(TW68_SAT_U, ctrl->val); + tw_writeb(TW68_SAT_V, ctrl->val); break; case V4L2_CID_COLOR_KILLER: - if (val) + if (ctrl->val) tw_andorb(TW68_MISC2, 0xe0, 0xe0); else tw_andorb(TW68_MISC2, 0xe0, 0x00); break; case V4L2_CID_CHROMA_AGC: - if (val) + if (ctrl->val) tw_andorb(TW68_LOOP, 0x30, 0x20); else tw_andorb(TW68_LOOP, 0x30, 0x00); break; - case V4L2_CID_AUDIO_MUTE: - /* hack to suppress tvtime complaint */ - break; -#if 0 - case V4L2_CID_AUDIO_VOLUME: - dev->ctl_volume = val; - tw68_tvaudio_setvolume(dev, dev->ctl_volume); - break; - case V4L2_CID_HFLIP: - dev->ctl_mirror = val; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->ctl_automute = val; - if (dev->tda9887_conf) { - if (dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - else - dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - - tw_call_all(dev, tuner, s_config, &tda9887_cfg); - } - break; - } -#endif - default: - err = -EINVAL; } - return err; + return 0; } -static int tw68_s_ctrl_internal(struct tw68_dev *dev, struct tw68_fh *fh, - struct v4l2_control *c) -{ - const struct v4l2_queryctrl *ctrl; - int err; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (fh) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - return err; - } +/* ------------------------------------------------------------------ */ - mutex_lock(&dev->lock); +/* + * Note that this routine returns what is stored in the fh structure, and + * does not interrogate any of the device registers. + */ +static int tw68_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tw68_dev *dev = video_drvdata(file); - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) { - err = -EINVAL; - goto error; - } - - dprintk(DBG_BUFF, "%s: name=%s val=%d\n", __func__, - ctrl->name, c->value); - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (c->value < ctrl->minimum) - c->value = ctrl->minimum; - if (c->value > ctrl->maximum) - c->value = ctrl->maximum; - break; - default: - /* nothing */; - }; - err = tw68_s_ctrl_value(dev, c->id, c->value); - -error: - mutex_unlock(&dev->lock); - return err; -} - -static int tw68_s_ctrl(struct file *file, void *f, struct v4l2_control *c) -{ - struct tw68_fh *fh = f; - - return tw68_s_ctrl_internal(fh->dev, fh, c); -} - -/* ------------------------------------------------------------------ */ - -/* - * Returns a pointer to the currently used queue (e.g. video, vbi, etc.) - */ -static struct videobuf_queue *tw68_queue(struct tw68_fh *fh) -{ - struct videobuf_queue *q = NULL; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &fh->cap; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - q = &fh->vbi; - break; - default: - BUG(); - } - return q; -} - -static int tw68_resource(struct tw68_fh *fh) -{ - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return RESOURCE_VIDEO; - - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - return RESOURCE_VBI; - - BUG(); - return 0; -} - -static int video_open(struct file *file) -{ - int minor = video_devdata(file)->minor; - struct tw68_dev *dev; - struct tw68_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - int radio = 0; - - mutex_lock(&tw68_devlist_lock); - list_for_each_entry(dev, &tw68_devlist, devlist) { - if (dev->video_dev && (dev->video_dev->minor == minor)) - goto found; - if (dev->radio_dev && (dev->radio_dev->minor == minor)) { - radio = 1; - goto found; - } - if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - goto found; - } - } - mutex_unlock(&tw68_devlist_lock); - return -ENODEV; - -found: - mutex_unlock(&tw68_devlist_lock); - - dprintk(DBG_FLOW, "%s: minor=%d radio=%d type=%s\n", __func__, minor, - radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - fh->width = 720; - fh->height = 576; - v4l2_prio_open(&dev->prio, &fh->prio); - - videobuf_queue_sg_init(&fh->cap, &video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct tw68_buf), -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - fh -#else - fh, &dev->lock -#endif - ); - videobuf_queue_sg_init(&fh->vbi, &tw68_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct tw68_buf), -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,37) - fh -#else - fh, &dev->lock -#endif - ); - if (fh->radio) { - /* switch to radio mode */ - tw68_tvaudio_setinput(dev, &card(dev).radio); - tw_call_all(dev, tuner, s_radio); - } else { - /* switch to video/vbi mode */ - tw68_tvaudio_setinput(dev, dev->input); - } - return 0; -} - -static ssize_t -video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) -{ - struct tw68_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(tw68_queue(fh), - data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(tw68_queue(fh), - data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - break; - default: - BUG(); - return 0; - } -} - -static unsigned int -video_poll(struct file *file, struct poll_table_struct *wait) -{ - struct tw68_fh *fh = file->private_data; - struct videobuf_buffer *buf = NULL; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) - return videobuf_poll_stream(file, &fh->vbi, wait); - - if (res_check(fh, RESOURCE_VIDEO)) { - if (!list_empty(&fh->cap.stream)) - buf = list_entry(fh->cap.stream.next, - struct videobuf_buffer, stream); - } else { - mutex_lock(&fh->cap.vb_lock); - if (UNSET == fh->cap.read_off) { - /* need to capture a new frame */ - if (res_locked(fh->dev, RESOURCE_VIDEO)) - goto err; - if (0 != fh->cap.ops->buf_prepare(&fh->cap, - fh->cap.read_buf, fh->cap.field)) - goto err; - fh->cap.ops->buf_queue(&fh->cap, fh->cap.read_buf); - fh->cap.read_off = 0; - } - mutex_unlock(&fh->cap.vb_lock); - buf = fh->cap.read_buf; - } - - if (!buf) - return POLLERR; - - poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) - return POLLIN | POLLRDNORM; - return 0; - -err: - mutex_unlock(&fh->cap.vb_lock); - return POLLERR; -} - -static int video_release(struct file *file) -{ - struct tw68_fh *fh = file->private_data; - struct tw68_dev *dev = fh->dev; - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_streamoff(&fh->cap); - res_free(fh , RESOURCE_VIDEO); - } - if (fh->cap.read_buf) { - buffer_release(&fh->cap, fh->cap.read_buf); - kfree(fh->cap.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - videobuf_stop(&fh->vbi); - res_free(fh, RESOURCE_VBI); - } - -#if 0 - tw_call_all(dev, core, s_standby, 0); -#endif - - /* free stuff */ - videobuf_mmap_free(&fh->cap); - videobuf_mmap_free(&fh->vbi); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - v4l2_prio_close(&dev->prio, &fh->prio); -#else - v4l2_prio_close(&dev->prio, fh->prio); -#endif - file->private_data = NULL; - kfree(fh); - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct tw68_fh *fh = file->private_data; - - return videobuf_mmap_mapper(tw68_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ - -#if 0 -static int tw68_try_get_set_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - struct tw68_tvnorm *norm = dev->tvnorm; - - f->fmt.vbi.sampling_rate = 6750000 * 4; - f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 64 * 4; - f->fmt.vbi.start[0] = norm->vbi_v_start_0; - f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 + 1; - f->fmt.vbi.start[1] = norm->vbi_v_start_1; - f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; - f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ - -#if 0 - if (V4L2_STD_PAL == norm->id) { - /* FIXME */ - f->fmt.vbi.start[0] += 3; - f->fmt.vbi.start[1] += 3*2; - } -#endif - return 0; -} -#endif - -/* - * Note that this routine returns what is stored in the fh structure, and - * does not interrogate any of the device registers. - */ -static int tw68_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = dev->field; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * (fh->fmt->depth)) >> 3; + (f->fmt.pix.width * (dev->fmt->depth)) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; return 0; } static int tw68_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - struct tw68_format *fmt; + struct tw68_dev *dev = video_drvdata(file); + const struct tw68_format *fmt; enum v4l2_field field; - unsigned int maxw, maxh; + unsigned int maxh; - dprintk(DBG_FLOW, "%s\n", __func__); fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576; - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: break; case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_SEQ_TB: maxh = maxh * 2; break; default: - return -EINVAL; + field = (f->fmt.pix.height > maxh / 2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + break; } f->fmt.pix.field = field; @@ -1359,8 +656,8 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = 48; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; + if (f->fmt.pix.width > 720) + f->fmt.pix.width = 720; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; f->fmt.pix.width &= ~0x03; @@ -1368,7 +665,7 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * (fmt->depth)) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -1381,76 +678,35 @@ static int tw68_try_fmt_vid_cap(struct file *file, void *priv, static int tw68_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); int err; - dprintk(DBG_FLOW, "%s\n", __func__); err = tw68_try_fmt_vid_cap(file, priv, f); if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - /* - * The following lines are to make v4l2-test program happy. - * The docs should be checked to assure they make sense. - */ - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; - return 0; -} - -static int tw68_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) -#if 0 - && (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1) -#endif - ) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - if (NULL == ctrl) - return -EINVAL; - *c = *ctrl; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->field = f->fmt.pix.field; return 0; } static int tw68_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); unsigned int n; n = i->index; - dprintk(DBG_FLOW, "%s: index is %d\n", __func__, n); - if (n >= TW68_INPUT_MAX) { - dprintk(DBG_FLOW, "%s: INPUT_MAX reached\n", __func__); + if (n >= TW68_INPUT_MAX) return -EINVAL; - } - if (NULL == card_in(dev, n).name) { - dprintk(DBG_FLOW, "%s: End of list\n", __func__); - return -EINVAL; - } - memset(i, 0, sizeof(*i)); i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, card_in(dev, n).name); - if (card_in(dev, n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; + i->type = V4L2_INPUT_TYPE_CAMERA; + snprintf(i->name, sizeof(i->name), "Composite %d", n); + /* If the query is for the current input, get live data */ - if (n == dev->hw_input->vmux) { + if (n == dev->input) { int v1 = tw_readb(TW68_STATUS1); int v2 = tw_readb(TW68_MVSN); @@ -1465,305 +721,86 @@ static int tw68_enum_input(struct file *file, void *priv, if (0 != (v2 & (1 << 2))) i->status |= V4L2_IN_ST_MACROVISION; } - i->std = TW68_NORMS; + i->std = video_devdata(file)->tvnorms; return 0; } static int tw68_g_input(struct file *file, void *priv, unsigned int *i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); - *i = dev->input->vmux; + *i = dev->input; return 0; } static int tw68_s_input(struct file *file, void *priv, unsigned int i) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - - if (i < 0 || i >= TW68_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i).name) + if (i >= TW68_INPUT_MAX) return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); + dev->input = i; + tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2); return 0; } static int tw68_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - unsigned int tuner_type = dev->tuner_type; - - dprintk(DBG_FLOW, "%s\n", __func__); strcpy(cap->driver, "tw68"); - strlcpy(cap->card, tw68_boards[dev->board].name, + strlcpy(cap->card, "Techwell Capture Card", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = TW68_VERSION_CODE; - cap->capabilities = + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; + V4L2_CAP_STREAMING; - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -static int tw68_s_std_internal(struct tw68_dev *dev, struct tw68_fh *fh, - v4l2_std_id *id) +static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id) { -/* unsigned long flags; */ + struct tw68_dev *dev = video_drvdata(file); unsigned int i; - v4l2_std_id fixup; - int err; - dprintk(DBG_FLOW, "%s\n", __func__); - if (fh) { -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - } + if (vb2_is_busy(&dev->vidq)) + return -EBUSY; /* Look for match on complete norm id (may have mult bits) */ for (i = 0; i < TVNORMS; i++) { - if (*id == tvnorms[i].id) + if (id == tvnorms[i].id) break; } /* If no exact match, look for norm which contains this one */ - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) { - if (*id & tvnorms[i].id) + if (i == TVNORMS) { + for (i = 0; i < TVNORMS; i++) + if (id & tvnorms[i].id) break; - } + } /* If still not matched, give up */ if (i == TVNORMS) return -EINVAL; - /* TODO - verify this additional work with SECAM applies to TW */ - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { - if (secam[0] == 'L' || secam[0] == 'l') { - if (secam[1] == 'C' || secam[1] == 'c') - fixup = V4L2_STD_SECAM_LC; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; - } - for (i = 0; i < TVNORMS; i++) - if (fixup == tvnorms[i].id) - break; - } - - *id = tvnorms[i].id; - mutex_lock(&dev->lock); set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */ - tw68_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); return 0; } -static int tw68_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - return tw68_s_std_internal(fh->dev, fh, id); -} - static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); *id = dev->tvnorm->id; return 0; } -static int tw68_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int n; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - for (n = 0; n < TW68_INPUT_MAX; n++) - if (card_in(dev, n).tv) - break; - if (n == TW68_INPUT_MAX) - return -EINVAL; -#if 0 - if (NULL != card_in(dev, n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = tw68_tvaudio_getstereo(dev); - t->audmode = tw68_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(TW68_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; -#endif - return 0; -} - -static int tw68_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; -#if 0 - int rx, mode -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - -#if 0 - mode = dev->thread.mode; - if (UNSET == mode) { - rx = tw68_tvaudio_getstereo(dev); - mode = tw68_tvaudio_rx2mode(t->rxsubchans); - } - if (mode != t->audmode) - dev->thread.mode = t->audmode; -#endif - return 0; -} - -static int tw68_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - if (unlikely(dev->tuner_type)) - return -EINVAL; - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; -/* f->frequency = dev->ctl_freq; */ - - return 0; -} - -static int tw68_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int err; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,34) - err = v4l2_prio_check(&dev->prio, &fh->prio); -#else - err = v4l2_prio_check(&dev->prio, fh->prio); -#endif - if (0 != err) - if (0 != err) - return err; - - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); -/* dev->ctl_freq = f->frequency; */ - - tw_call_all(dev, tuner, s_frequency, f); - - tw68_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} - -static int tw68_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - strcpy(a->name, "audio"); - return 0; -} - -static int tw68_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return 0; -} - -static int tw68_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - *p = v4l2_prio_max(&dev->prio); - return 0; -} - -static int tw68_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - return v4l2_prio_change(&dev->prio, &fh->prio, prio); -} - static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); if (f->index >= FORMATS) return -EINVAL; @@ -1775,149 +812,6 @@ static int tw68_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int tw68_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; - } - return 0; -} - -static int tw68_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - crop->c = dev->crop_current; - return 0; -} - -static int tw68_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct tw68_fh *fh = f; - struct tw68_dev *dev = fh->dev; - struct v4l2_rect *b = &dev->crop_bounds; - - dprintk(DBG_FLOW, "%s\n", __func__); - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - - if ((crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (crop->c.height < 0) || (crop->c.width < 0)) { - dprintk(DBG_UNEXPECTED, "%s: invalid request\n", __func__); - return -EINVAL; - } - - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dprintk(DBG_FLOW, "%s: setting cropping rectangle: top=%d, left=%d, " - "width=%d, height=%d\n", __func__, crop->c.top, - crop->c.left, crop->c.width, crop->c.height); - dev->crop_current = crop->c; - return 0; -} - -/* - * Wrappers for the v4l2_ioctl_ops functions - */ -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) -{ - struct tw68_fh *fh = file->private_data; - return videobuf_cgmbuf(tw68_queue(fh), mbuf, 8); -} -#endif - -static int tw68_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct tw68_fh *fh = priv; - return videobuf_reqbufs(tw68_queue(fh), p); -} - -static int tw68_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_querybuf(tw68_queue(fh), b); -} - -static int tw68_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_qbuf(tw68_queue(fh), b); -} - -static int tw68_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct tw68_fh *fh = priv; - return videobuf_dqbuf(tw68_queue(fh), b, - file->f_flags & O_NONBLOCK); -} - -static int tw68_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int res = tw68_resource(fh); - - dprintk(DBG_FLOW, "%s\n", __func__); - if (!res_get(fh, res)) - return -EBUSY; - - tw68_buffer_requeue(dev, &dev->video_q); - return videobuf_streamon(tw68_queue(fh)); -} - -static int tw68_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int err; - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; - int res = tw68_resource(fh); - - dprintk(DBG_FLOW, "%s\n", __func__); - err = videobuf_streamoff(tw68_queue(fh)); - if (err < 0) - return err; - res_free(fh, res); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG /* * Used strictly for internal development and debugging, this routine * prints out the current register contents for the tw68xx device. @@ -1928,7 +822,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) int i, j, k; unsigned char *cptr; - printk(KERN_DEBUG "Full dump of TW68 registers:\n"); + pr_info("Full dump of TW68 registers:\n"); /* First we do the PCI regs, 8 4-byte regs per line */ for (i = 0; i < 0x100; i += 32) { cptr = line; @@ -1941,7 +835,7 @@ static void tw68_dump_regs(struct tw68_dev *dev) cptr += sprintf(cptr, "%08x ", tw_readl(j)); *cptr++ = '\n'; *cptr = 0; - printk(KERN_DEBUG "%s", line); + pr_info("%s", line); } /* Next the control regs, which are single-byte, address mod 4 */ while (i < 0x400) { @@ -1958,29 +852,24 @@ static void tw68_dump_regs(struct tw68_dev *dev) } *cptr++ = '\n'; *cptr = 0; - printk(KERN_DEBUG "%s", line); + pr_info("%s", line); } } static int vidioc_log_status(struct file *file, void *priv) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; + struct tw68_dev *dev = video_drvdata(file); tw68_dump_regs(dev); - return 0; + return v4l2_ctrl_log_status(file, priv); } +#ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; /* needed for tw_readb */ + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s\n", __func__); - if (!v4l2_chip_match_host(®->match)) - dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); - return -EINVAL; if (reg->size == 1) reg->val = tw_readb(reg->reg); else @@ -1989,17 +878,10 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { - struct tw68_fh *fh = priv; - struct tw68_dev *dev = fh->dev; /* needed for tw_writeb */ + struct tw68_dev *dev = video_drvdata(file); - dprintk(DBG_FLOW, "%s: request to set reg 0x%04x to 0x%02x\n", - __func__, (unsigned int)reg->reg, (unsigned int)reg->val); - if (!v4l2_chip_match_host(®->match)) { - dprintk(DBG_UNEXPECTED, "%s: match failed\n", __func__); - return -EINVAL; - } if (reg->size == 1) tw_writeb(reg->reg, reg->val); else @@ -2008,151 +890,120 @@ static int vidioc_s_register(struct file *file, void *priv, } #endif +static const struct v4l2_ctrl_ops tw68_ctrl_ops = { + .s_ctrl = tw68_s_ctrl, +}; + static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = tw68_querycap, .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap, - .vidioc_reqbufs = tw68_reqbufs, - .vidioc_querybuf = tw68_querybuf, - .vidioc_qbuf = tw68_qbuf, - .vidioc_dqbuf = tw68_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_s_std = tw68_s_std, .vidioc_g_std = tw68_g_std, .vidioc_enum_input = tw68_enum_input, .vidioc_g_input = tw68_g_input, .vidioc_s_input = tw68_s_input, - .vidioc_queryctrl = tw68_queryctrl, - .vidioc_g_ctrl = tw68_g_ctrl, - .vidioc_s_ctrl = tw68_s_ctrl, - .vidioc_streamon = tw68_streamon, - .vidioc_streamoff = tw68_streamoff, - .vidioc_g_priority = tw68_g_priority, - .vidioc_s_priority = tw68_s_priority, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap, - .vidioc_cropcap = tw68_cropcap, - .vidioc_g_crop = tw68_g_crop, - .vidioc_s_crop = tw68_s_crop, -/* - * Functions not yet implemented / not yet passing tests. - */ - -#if 0 - .vidioc_g_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = tw68_try_get_set_fmt_vbi_cap, -#endif - .vidioc_g_audio = tw68_g_audio, - .vidioc_s_audio = tw68_s_audio, - .vidioc_g_tuner = tw68_g_tuner, - .vidioc_s_tuner = tw68_s_tuner, - .vidioc_g_frequency = tw68_g_frequency, - .vidioc_s_frequency = tw68_s_frequency, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif -#ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_log_status = vidioc_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +#ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif }; -/* ------------------------------------------------------------------ */ -/* exported stuff */ -struct video_device tw68_video_template = { +static struct video_device tw68_video_template = { .name = "tw68_video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, - .minor = -1, + .release = video_device_release_empty, .tvnorms = TW68_NORMS, - .current_norm = V4L2_STD_PAL, -}; - -struct video_device tw68_radio_template = { - .name = "tw68_radio", }; -int tw68_videoport_init(struct tw68_dev *dev) -{ - return 0; -} - +/* ------------------------------------------------------------------ */ +/* exported stuff */ void tw68_set_tvnorm_hw(struct tw68_dev *dev) { tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format); - return; } int tw68_video_init1(struct tw68_dev *dev) { - int i; - - dprintk(DBG_FLOW, "%s\n", __func__); - /* sanitycheck insmod options */ - if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) - gbuffers = 2; - if (gbufsz < 0 || gbufsz > gbufsz_max) - gbufsz = gbufsz_max; - gbufsz = (gbufsz + PAGE_SIZE - 1) & PAGE_MASK; - - /* put some sensible defaults into the data structures ... */ - for (i = 0; i < CTRLS; i++) - tw68_s_ctrl_value(dev, video_ctrls[i].id, - video_ctrls[i].default_value); -#if 0 - if (dev->tda9887_conf && dev->ctl_automute) - dev->tda9887_conf |= TDA9887_AUTOMUTE; - dev->automute = 0; -#endif - INIT_LIST_HEAD(&dev->video_q.queued); - INIT_LIST_HEAD(&dev->video_q.active); - init_timer(&dev->video_q.timeout); - dev->video_q.timeout.function = tw68_buffer_timeout; - dev->video_q.timeout.data = (unsigned long)(&dev->video_q); - dev->video_q.dev = dev; - dev->video_q.buf_compat = tw68_check_video_fmt; - dev->video_q.start_dma = tw68_video_start_dma; - tw68_risc_stopper(dev->pci, &dev->video_q.stopper); - - if (tw68_boards[dev->board].video_out) - tw68_videoport_init(dev); - + struct v4l2_ctrl_handler *hdl = &dev->hdl; + + v4l2_ctrl_handler_init(hdl, 6); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 20); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 100); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + /* NTSC only */ + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops, + V4L2_CID_CHROMA_AGC, 0, 1, 1, 1); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; + } + dev->v4l2_dev.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); return 0; } -int tw68_video_init2(struct tw68_dev *dev) +int tw68_video_init2(struct tw68_dev *dev, int video_nr) { - dprintk(DBG_FLOW, "%s\n", __func__); + int ret; + set_tvnorm(dev, &tvnorms[0]); - video_mux(dev, 0); -/* - tw68_tvaudio_setmut(dev); - tw68_tvaudio_setvolume(dev, dev->ctl_volume); -*/ - return 0; -} -/* - * tw68_irq_video_signalchange - * - * TODO: - * Check for presence of video signal. If not present, mute audio. - * If present, log type of signal present. - */ -void tw68_irq_video_signalchange(struct tw68_dev *dev) -{ - return; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + dev->width = 720; + dev->height = 576; + dev->field = V4L2_FIELD_INTERLACED; + + INIT_LIST_HEAD(&dev->active); + dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; + dev->vidq.ops = &tw68_video_qops; + dev->vidq.mem_ops = &vb2_dma_sg_memops; + dev->vidq.drv_priv = dev; + dev->vidq.gfp_flags = __GFP_DMA32; + dev->vidq.buf_struct_size = sizeof(struct tw68_buf); + dev->vidq.lock = &dev->lock; + dev->vidq.min_buffers_needed = 2; + ret = vb2_queue_init(&dev->vidq); + if (ret) + return ret; + dev->vdev = tw68_video_template; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->lock; + dev->vdev.queue = &dev->vidq; + video_set_drvdata(&dev->vdev, dev); + return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); } /* @@ -2171,60 +1022,39 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) * for the current buffer. */ if (status & TW68_DMAPI) { - struct tw68_dmaqueue *q = &dev->video_q; - dprintk(DBG_FLOW | DBG_TESTING, "DMAPI interrupt\n"); + struct tw68_buf *buf; + spin_lock(&dev->slock); - /* - * tw68_wakeup will take care of the buffer handling, - * plus any non-video requirements. - */ - tw68_wakeup(q, &dev->video_fieldcount); + buf = list_entry(dev->active.next, struct tw68_buf, list); + list_del(&buf->list); spin_unlock(&dev->slock); - /* Check whether we have gotten into 'stopper' code */ - reg = tw_readl(TW68_DMAP_PP); - if ((reg >= q->stopper.dma) && - (reg < q->stopper.dma + q->stopper.size)) { - /* Yes - log the information */ - dprintk(DBG_FLOW | DBG_TESTING, - "%s: stopper risc code entered\n", __func__); - } + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.field = dev->field; + buf->vb.v4l2_buf.sequence = dev->seqnr++; + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); status &= ~(TW68_DMAPI); if (0 == status) return; } - if (status & (TW68_VLOCK | TW68_HLOCK)) { /* lost sync */ - dprintk(DBG_UNUSUAL, "Lost sync\n"); - } - if (status & TW68_PABORT) { /* TODO - what should we do? */ - dprintk(DBG_UNEXPECTED, "PABORT interrupt\n"); - } - if (status & TW68_DMAPERR) { - dprintk(DBG_UNEXPECTED, "DMAPERR interrupt\n"); -#if 0 - /* Stop risc & fifo */ - tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); - tw_clearl(TW68_INTMASK, dev->board_virqmask); - dev->pci_irqmask &= ~dev->board_virqmask; -#endif - } + if (status & (TW68_VLOCK | TW68_HLOCK)) + dev_dbg(&dev->pci->dev, "Lost sync\n"); + if (status & TW68_PABORT) + dev_err(&dev->pci->dev, "PABORT interrupt\n"); + if (status & TW68_DMAPERR) + dev_err(&dev->pci->dev, "DMAPERR interrupt\n"); /* * On TW6800, FDMIS is apparently generated if video input is switched * during operation. Therefore, it is not enabled for that chip. */ - if (status & TW68_FDMIS) { /* logic error somewhere */ - dprintk(DBG_UNEXPECTED, "FDMIS interrupt\n"); - /* Stop risc & fifo */ -// tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); -// tw_clearl(TW68_INTMASK, dev->board_virqmask); -// dev->pci_irqmask &= ~dev->board_virqmask; - } - if (status & TW68_FFOF) { /* probably a logic error */ + if (status & TW68_FDMIS) + dev_dbg(&dev->pci->dev, "FDMIS interrupt\n"); + if (status & TW68_FFOF) { + /* probably a logic error */ reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN; tw_clearl(TW68_DMAC, TW68_FIFO_EN); - dprintk(DBG_UNUSUAL, "FFOF interrupt\n"); + dev_dbg(&dev->pci->dev, "FFOF interrupt\n"); tw_setl(TW68_DMAC, reg); } if (status & TW68_FFERR) - dprintk(DBG_UNEXPECTED, "FFERR interrupt\n"); - return; + dev_dbg(&dev->pci->dev, "FFERR interrupt\n"); } diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index e723efb5e623..2c8abe26b13b 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -8,7 +8,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil * * 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 @@ -19,54 +23,26 @@ * 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 */ #include -#define TW68_VERSION_CODE KERNEL_VERSION(0, 0, 8) - #include -#include -#include #include -#include -#include #include #include #include - -#include +#include #include #include +#include #include +#include -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -# include -#endif -#include -#include - -#include "btcx-risc.h" #include "tw68-reg.h" #define UNSET (-1U) -/* - * dprintk statement within the code use a 'level' argument. For - * our purposes, we use the following levels: - */ -#define DBG_UNEXPECTED (1 << 0) -#define DBG_UNUSUAL (1 << 1) -#define DBG_TESTING (1 << 2) -#define DBG_BUFF (1 << 3) -#define DBG_FLOW (1 << 15) - /* system vendor and device ID's */ #define PCI_VENDOR_ID_TECHWELL 0x1797 #define PCI_DEVICE_ID_6800 0x6800 @@ -83,15 +59,9 @@ #define PCI_DEVICE_ID_6816_3 0x6812 #define PCI_DEVICE_ID_6816_4 0x6813 -/* subsystem vendor ID's */ -#define TW68_PCI_ID_TECHWELL 0x1797 - -#define TW68_NORMS (\ - V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60 | \ - V4L2_STD_525_60 | V4L2_STD_625_50 | \ - V4L2_STD_SECAM_L| V4L2_STD_SECAM_LC | V4L2_STD_SECAM_DK) +#define TW68_NORMS ( \ + V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60) #define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \ TW68_FFOF | TW68_DMAPI) @@ -101,12 +71,13 @@ #define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \ TW68_SBDONE2) -typedef enum { +enum tw68_decoder_type { TW6800, TW6801, TW6804, TWXXXX, -} TW68_DECODER_TYPE; +}; + /* ----------------------------------------------------------- */ /* static data */ @@ -153,164 +124,24 @@ struct tw68_format { #define TW68_BOARD_GENERIC_6802 1 #define TW68_MAXBOARDS 16 -#define TW68_INPUT_MAX 8 - -/* ----------------------------------------------------------- */ -/* enums */ - -enum tw68_mpeg_type { - TW68_MPEG_UNUSED, - TW68_MPEG_EMPRESS, - TW68_MPEG_DVB, -}; - -enum tw68_audio_in { - TV = 1, - LINE1 = 2, - LINE2 = 3, - LINE2_LEFT, -}; - -enum tw68_video_out { - CCIR656 = 1, -}; - -/* Structs for card definition */ -struct tw68_input { - char *name; /* text description */ - unsigned int vmux; /* mux value */ - enum tw68_audio_in mux; - unsigned int gpio; - unsigned int tv:1; -}; - -struct tw68_board { - char *name; - unsigned int audio_clock; - - /* input switching */ - unsigned int gpiomask; - struct tw68_input inputs[TW68_INPUT_MAX]; - struct tw68_input radio; - struct tw68_input mute; - - /* i2c chip info */ - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - unsigned int tda9887_conf; - unsigned int tuner_config; - - enum tw68_video_out video_out; - enum tw68_mpeg_type mpeg; - unsigned int vid_port_opts; -}; - -#define card_has_radio(dev) (NULL != tw68_boards[dev->board].radio.name) -#define card_has_mpeg(dev) (TW68_MPEG_UNUSED != \ - tw68_boards[dev->board].mpeg) -#define card_in(dev, n) (tw68_boards[dev->board].inputs[n]) -#define card(dev) (tw68_boards[dev->board]) +#define TW68_INPUT_MAX 4 /* ----------------------------------------------------------- */ /* device / file handle status */ -#define RESOURCE_VIDEO 1 -#define RESOURCE_VBI 2 - -#define INTERLACE_AUTO 0 -#define INTERLACE_ON 1 -#define INTERLACE_OFF 2 - #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ struct tw68_dev; /* forward delclaration */ -/* tvaudio thread status */ -struct tw68_thread { - struct task_struct *thread; - unsigned int scan1; - unsigned int scan2; - unsigned int mode; - unsigned int stopped; -}; - /* buffer for one video/vbi/ts frame */ struct tw68_buf { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* tw68 specific */ - struct tw68_format *fmt; - struct tw68_input *input; - unsigned int top_seen; - int (*activate)(struct tw68_dev *dev, - struct tw68_buf *buf, - struct tw68_buf *next); - struct btcx_riscmem risc; - unsigned int bpl; -}; + struct vb2_buffer vb; + struct list_head list; -struct tw68_dmaqueue { - struct tw68_dev *dev; - struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; - int (*buf_compat)(struct tw68_buf *prev, - struct tw68_buf *buf); - int (*start_dma)(struct tw68_dev *dev, - struct tw68_dmaqueue *q, - struct tw68_buf *buf); -}; - -/* video filehandle status */ -struct tw68_fh { - struct tw68_dev *dev; - unsigned int radio; - enum v4l2_buf_type type; - unsigned int resources; - enum v4l2_priority prio; - - /* video capture */ - struct tw68_format *fmt; - unsigned int width, height; - struct videobuf_queue cap; /* also used for overlay */ - - /* vbi capture */ - struct videobuf_queue vbi; -}; - -/* dmasound dsp status */ -struct tw68_dmasound { - struct mutex lock; - int minor_mixer; - int minor_dsp; - unsigned int users_dsp; - - /* mixer */ - enum tw68_audio_in input; - unsigned int count; - unsigned int line1; - unsigned int line2; - - /* dsp */ - unsigned int afmt; - unsigned int rate; - unsigned int channels; - unsigned int recording_on; - unsigned int dma_running; - unsigned int blocks; - unsigned int blksize; - unsigned int bufsize; - struct videobuf_dmabuf dma; - unsigned int dma_blk; - unsigned int read_offset; - unsigned int read_count; - void *priv_data; - struct snd_pcm_substream *substream; + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; }; struct tw68_fmt { @@ -321,58 +152,20 @@ struct tw68_fmt { u32 twformat; }; -/* ts/mpeg status */ -struct tw68_ts { - /* TS capture */ - int nr_packets; - int nr_bufs; -}; - -/* ts/mpeg ops */ -struct tw68_mpeg_ops { - enum tw68_mpeg_type type; - struct list_head next; - int (*init)(struct tw68_dev *dev); - int (*fini)(struct tw68_dev *dev); - void (*signal_change)(struct tw68_dev *dev); -}; - -enum tw68_ts_status { - TW68_TS_STOPPED, - TW68_TS_BUFF_DONE, - TW68_TS_STARTED, -}; - /* global device status */ struct tw68_dev { - struct list_head devlist; struct mutex lock; spinlock_t slock; - struct v4l2_prio_state prio; + u16 instance; struct v4l2_device v4l2_dev; - /* workstruct for loading modules */ - struct work_struct request_module_wk; - - /* insmod option/autodetected */ - int autodetected; /* various device info */ - TW68_DECODER_TYPE vdecoder; - unsigned int resources; - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; - struct tw68_dmasound dmasound; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - /* infrared remote */ - int has_remote; - struct card_ir *remote; -#endif + enum tw68_decoder_type vdecoder; + struct video_device vdev; + struct v4l2_ctrl_handler hdl; /* pci i/o */ - char name[32]; - int nr; + char *name; struct pci_dev *pci; unsigned char pci_rev, pci_lat; u32 __iomem *lmmio; @@ -381,75 +174,18 @@ struct tw68_dev { /* The irq mask to be used will depend upon the chip type */ u32 board_virqmask; - /* config info */ - unsigned int board; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - unsigned int tda9887_conf; - unsigned int gpio_value; - - /* i2c i/o */ - struct i2c_algo_bit_data i2c_algo; - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - u32 i2c_state; - u32 i2c_done; - wait_queue_head_t i2c_queue; - int i2c_rc; - unsigned char eedata[256]; - - /* video+ts+vbi capture */ - struct tw68_dmaqueue video_q; - struct tw68_dmaqueue vbi_q; - unsigned int video_fieldcount; - unsigned int vbi_fieldcount; + /* video capture */ + const struct tw68_format *fmt; + unsigned width, height; + unsigned seqnr; + unsigned field; + struct vb2_queue vidq; + struct list_head active; /* various v4l controls */ - struct tw68_tvnorm *tvnorm; /* video */ - struct tw68_tvaudio *tvaudio; -#if 0 - unsigned int ctl_input; - int ctl_bright; - int ctl_contrast; - int ctl_hue; - int ctl_saturation; - int ctl_freq; - int ctl_mute; /* audio */ - int ctl_volume; - int ctl_invert; /* private */ - int ctl_mirror; - int ctl_y_odd; - int ctl_y_even; - int ctl_automute; -#endif - - /* crop */ - struct v4l2_rect crop_bounds; - struct v4l2_rect crop_defrect; - struct v4l2_rect crop_current; - - /* other global state info */ - unsigned int automute; - struct tw68_thread thread; - /* input is latest requested by app, hw_input is current hw setting */ - struct tw68_input *input; - struct tw68_input *hw_input; - unsigned int hw_mute; - int last_carrier; - int nosignal; - unsigned int insuspend; - - /* TW68_MPEG_* */ - struct tw68_ts ts; - struct tw68_dmaqueue ts_q; - enum tw68_ts_status ts_state; - unsigned int buff_cnt; - struct tw68_mpeg_ops *mops; - - void (*gate_ctrl)(struct tw68_dev *dev, int open); + const struct tw68_tvnorm *tvnorm; /* video */ + + int input; }; /* ----------------------------------------------------------- */ @@ -473,116 +209,23 @@ struct tw68_dev { #define tw_clearb(reg, bit) \ writeb((readb(dev->bmmio+(reg)) & ~(bit)), \ dev->bmmio + (reg)) -#define tw_call_all(dev, o, f, args...) do { \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 1); \ - v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \ - if (dev->gate_ctrl) \ - dev->gate_ctrl(dev, 0); \ -} while (0) #define tw_wait(us) { udelay(us); } -static inline struct tw68_dev *to_tw68_dev(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct tw68_dev, v4l2_dev); -} - -/* ----------------------------------------------------------- */ -/* tw68-core.c */ - -extern struct list_head tw68_devlist; -extern struct mutex tw68_devlist_lock; -extern unsigned int irq_debug; - -int tw68_buffer_count(unsigned int size, unsigned int count); -void tw68_buffer_queue(struct tw68_dev *dev, struct tw68_dmaqueue *q, - struct tw68_buf *buf); -void tw68_buffer_timeout(unsigned long data); -int tw68_set_dmabits(struct tw68_dev *dev); -void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf); -void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *field_count); -int tw68_buffer_requeue(struct tw68_dev *dev, struct tw68_dmaqueue *q); - -/* ----------------------------------------------------------- */ -/* tw68-cards.c */ - -extern struct tw68_board tw68_boards[]; -extern const unsigned int tw68_bcount; -extern struct pci_device_id __devinitdata tw68_pci_tbl[]; - -int tw68_board_init1(struct tw68_dev *dev); -int tw68_board_init2(struct tw68_dev *dev); -int tw68_tuner_callback(void *priv, int component, int command, int arg); - -/* ----------------------------------------------------------- */ -/* tw68-i2c.c */ - -int tw68_i2c_register(struct tw68_dev *dev); -int tw68_i2c_unregister(struct tw68_dev *dev); -void tw68_irq_i2c(struct tw68_dev *dev, int status); - /* ----------------------------------------------------------- */ /* tw68-video.c */ -extern unsigned int video_debug; -extern struct video_device tw68_video_template; -extern struct video_device tw68_radio_template; - -int tw68_videoport_init(struct tw68_dev *dev); void tw68_set_tvnorm_hw(struct tw68_dev *dev); int tw68_video_init1(struct tw68_dev *dev); -int tw68_video_init2(struct tw68_dev *dev); -void tw68_irq_video_signalchange(struct tw68_dev *dev); +int tw68_video_init2(struct tw68_dev *dev, int video_nr); void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status); - -/* ----------------------------------------------------------- */ -/* tw68-ts.c */ - -int tw68_ts_init1(struct tw68_dev *dev); -int tw68_ts_fini(struct tw68_dev *dev); -void tw68_irq_ts_done(struct tw68_dev *dev, unsigned long status); - -int tw68_ts_register(struct tw68_mpeg_ops *ops); -void tw68_ts_unregister(struct tw68_mpeg_ops *ops); - -int tw68_ts_init_hw(struct tw68_dev *dev); - -/* ----------------------------------------------------------- */ -/* tw68-vbi.c */ - -extern struct videobuf_queue_ops tw68_vbi_qops; -extern struct video_device tw68_vbi_template; - -int tw68_vbi_init1(struct tw68_dev *dev); -int tw68_vbi_fini(struct tw68_dev *dev); -void tw68_irq_vbi_done(struct tw68_dev *dev, unsigned long status); - -/* ----------------------------------------------------------- */ -/* tw68-tvaudio.c */ - -int tw68_tvaudio_rx2mode(u32 rx); - -void tw68_tvaudio_setmute(struct tw68_dev *dev); -void tw68_tvaudio_setinput(struct tw68_dev *dev, - struct tw68_input *in); -void tw68_tvaudio_setvolume(struct tw68_dev *dev, int level); -int tw68_tvaudio_getstereo(struct tw68_dev *dev); -void tw68_tvaudio_init(struct tw68_dev *dev); -int tw68_tvaudio_init2(struct tw68_dev *dev); -int tw68_tvaudio_fini(struct tw68_dev *dev); -int tw68_tvaudio_do_scan(struct tw68_dev *dev); -int tw_dsp_writel(struct tw68_dev *dev, int reg, u32 value); -void tw68_enable_i2s(struct tw68_dev *dev); +int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf); /* ----------------------------------------------------------- */ /* tw68-risc.c */ -int tw68_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); -int tw68_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc); -int tw68_risc_overlay(struct tw68_fh *fh, struct btcx_riscmem *risc, - int field_type); -- cgit v1.2.3 From ce9e1ac1b9becb9481f8492d9ccf713398a07ef8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 4 Sep 2014 11:31:58 -0300 Subject: [media] tw68: make tw68_pci_tbl static and constify drivers/media/pci/tw68/tw68-core.c:72:22: warning: symbol 'tw68_pci_tbl' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index baf93af1d764..a6fb48cf7aae 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -69,7 +69,7 @@ static atomic_t tw68_instance = ATOMIC_INIT(0); * the PCI ID database up to date. Note that the entries must be * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ -struct pci_device_id tw68_pci_tbl[] = { +static const struct pci_device_id tw68_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, -- cgit v1.2.3 From 04da2daee383391954b34e7d0fe0281d75447d61 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 3 Sep 2014 20:44:04 -0300 Subject: [media] ngene: properly handle __user ptr Sparse is complaining about ngene's bad usage of a __user ptr: >> drivers/media/pci/ngene/ngene-dvb.c:62:48: sparse: incorrect type in argument 2 (different address spaces) drivers/media/pci/ngene/ngene-dvb.c:62:48: expected unsigned char const [usertype] *buf drivers/media/pci/ngene/ngene-dvb.c:62:48: got char const [noderef] *buf As this is intercepting a .write() file ops, we can't just memcpy. We need to use copy_from_user. Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_ringbuffer.c | 26 ++++++++++++++++++++++++++ drivers/media/dvb-core/dvb_ringbuffer.h | 2 ++ drivers/media/pci/ngene/ngene-dvb.c | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index a5712cd7c65f..1100e98a7b1d 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -166,6 +166,31 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t return len; } +ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len) +{ + int status; + size_t todo = len; + size_t split; + + split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + + if (split > 0) { + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); + if (status) + return len - todo; + buf += split; + todo -= split; + rbuf->pwrite = 0; + } + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); + if (status) + return len - todo; + rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; + + return len; +} + ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) { int status; @@ -297,3 +322,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read_user); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); +EXPORT_SYMBOL(dvb_ringbuffer_write_user); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 41f04dae69b6..9e1e11b7c39c 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h @@ -133,6 +133,8 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len); +extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len); /** diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index a8a4045f66d7..59bb2858c8d0 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -59,7 +59,7 @@ static ssize_t ts_write(struct file *file, const char __user *buf, (&dev->tsout_rbuf) >= count) < 0) return 0; - dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count); return count; } -- cgit v1.2.3 From 453afdd9ce33293f640e84dc17e5f366701516e8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Aug 2014 06:43:01 -0300 Subject: [media] cx23885: convert to vb2 As usual, this patch is very large due to the fact that half a vb2 conversion isn't possible. And since this affects 417, alsa, core, dvb, vbi and video the changes are all over. What made this more difficult was the peculiar way the risc program was setup. The driver allowed for running out of buffers in which case the DMA would stop and restart when the next buffer was queued. There was also a complicated timeout system for when buffers weren't filled. This was replaced by a much simpler scheme where there is always one buffer around and the DMA will just cycle that buffer until a new buffer is queued. In that case the previous buffer will be chained to the new buffer. An interrupt is generated at the start of the new buffer telling the driver that the previous buffer can be passed on to userspace. Much simpler and more robust. The old code seems to be copied from the cx88 driver. But it didn't fit the vb2 ops very well and replacing it with the new scheme made the code easier to understand. Not to mention that this patch removes 600 lines of code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 4 +- drivers/media/pci/cx23885/altera-ci.c | 4 +- drivers/media/pci/cx23885/cx23885-417.c | 312 +++++------- drivers/media/pci/cx23885/cx23885-alsa.c | 4 +- drivers/media/pci/cx23885/cx23885-core.c | 305 ++++------- drivers/media/pci/cx23885/cx23885-dvb.c | 131 +++-- drivers/media/pci/cx23885/cx23885-vbi.c | 275 +++++----- drivers/media/pci/cx23885/cx23885-video.c | 810 ++++++++---------------------- drivers/media/pci/cx23885/cx23885.h | 61 +-- 9 files changed, 655 insertions(+), 1251 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index e12c006e6e2d..38c3b7bc7c2a 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -7,8 +7,8 @@ config VIDEO_CX23885 select VIDEO_TUNER select VIDEO_TVEEPROM depends on RC_CORE - select VIDEOBUF_DVB - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DVB + select VIDEOBUF2_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 8302d444a0ba..2bbbf545b042 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -48,8 +48,8 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ -#include -#include +#include +#include #include "altera-ci.h" #include "dvb_ca_en50221.h" diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 56673b52c559..f1ef9017e2a7 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1138,47 +1138,100 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) /* ------------------------------------------------------------------ */ -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = q->drv_priv; - fh->q_dev->ts1.ts_packet_size = mpeglinesize; - fh->q_dev->ts1.ts_packet_count = mpeglines; + dev->ts1.ts_packet_size = mpeglinesize; + dev->ts1.ts_packet_count = mpeglines; + *num_planes = 1; + sizes[0] = mpeglinesize * mpeglines; + *num_buffers = mpegbufs; + return 0; +} - *size = fh->q_dev->ts1.ts_packet_size * fh->q_dev->ts1.ts_packet_count; - *count = mpegbufs; +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); - return 0; + return cx23885_buf_prepare(buf, &dev->ts1); } -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->q_dev->ts1, - (struct cx23885_buffer *)vb, - field); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->q_dev->ts1, (struct cx23885_buffer *)vb); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_buf_queue(&dev->ts1, buf); +} + +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq; + unsigned long flags; + int ret; + + ret = cx23885_initialize_codec(dev, 1); + if (ret == 0) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(&dev->ts1, dmaq, buf); + return 0; + } + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&dev->slock, flags); + return ret; } -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void cx23885_stop_streaming(struct vb2_queue *q) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); + struct cx23885_dev *dev = q->drv_priv; + + /* stop mpeg capture */ + cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); + + msleep(500); + cx23885_417_check_encoder(dev); + cx23885_cancel_buffers(&dev->ts1); } -static struct videobuf_queue_ops cx23885_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, +static struct vb2_ops cx23885_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, }; /* ------------------------------------------------------------------ */ @@ -1316,7 +1369,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1325,9 +1377,9 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = 0; f->fmt.pix.width = dev->ts1.width; f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } @@ -1335,15 +1387,15 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } @@ -1357,58 +1409,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; f->fmt.pix.colorspace = 0; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->mpegq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->mpegq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->mpegq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx23885_fh *fh = priv; - - return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamon(&fh->mpegq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->mpegq); -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_dev *dev = video_drvdata(file); @@ -1420,120 +1426,14 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } -static int mpeg_open(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh; - - dprintk(2, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = fh; - fh->q_dev = dev; - - videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, - &dev->pci->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - v4l2_fh_add(&fh->fh); - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - msleep(500); - cx23885_417_check_encoder(dev); - - cx23885_cancel_buffers(&dev->ts1); - } - } - - if (fh->mpegq.streaming) - videobuf_streamoff(&fh->mpegq); - if (fh->mpegq.reading) - videobuf_read_stop(&fh->mpegq); - - videobuf_mmap_free(&fh->mpegq); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - file->private_data = NULL; - kfree(fh); - - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ - /* Start mpeg encoder on first read. */ - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev, 1) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s\n", __func__); - - return videobuf_poll_stream(file, &fh->mpegq, wait); -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->mpegq, vma); -} - static struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { @@ -1551,12 +1451,13 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = vidioc_log_status, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, @@ -1613,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev) /* FIXME: Port1 hardcoded here */ int err = -ENODEV; struct cx23885_tsport *tsport = &dev->ts1; + struct vb2_queue *q; dprintk(1, "%s()\n", __func__); @@ -1640,8 +1542,24 @@ int cx23885_417_register(struct cx23885_dev *dev) /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); + q = &dev->vb2_mpegq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; video_set_drvdata(dev->v4l_device, dev); dev->v4l_device->lock = &dev->lock; + dev->v4l_device->queue = q; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index c17e4740d47c..1b162ee8c8c6 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -389,6 +389,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, return -ENOMEM; buf->bpl = chip->period_size; + chip->buf = buf; ret = cx23885_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); @@ -409,8 +410,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - chip->buf = buf; - substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; @@ -419,6 +418,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, error: kfree(buf); + chip->buf = NULL; return ret; } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 0b6bbac6990f..8d77a5649777 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -416,39 +416,23 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -void cx23885_wakeup(struct cx23885_tsport *port, +static void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - int bc; - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.sequence = q->count++; + dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_sram_channel_setup(struct cx23885_dev *dev, @@ -478,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); + cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET); + cx_write(8 + 4, 12); cx_write(8 + 8, 0); /* write CDT */ @@ -695,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev) return -EBUSY; } -static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -715,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, port->nr = portno; INIT_LIST_HEAD(&port->mpegq.active); - INIT_LIST_HEAD(&port->mpegq.queued); - port->mpegq.timeout.function = cx23885_timeout; - port->mpegq.timeout.data = (unsigned long)port; - init_timer(&port->mpegq.timeout); - mutex_init(&port->frontends.lock); INIT_LIST_HEAD(&port->frontends.felist); port->frontends.active_fe_id = 0; @@ -772,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, BUG(); } - cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, - port->reg_dma_ctl, port->dma_ctl_val, 0x00); - return 0; } @@ -1085,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) + unsigned int lines, unsigned int lpi, bool jump) { struct scatterlist *sg; unsigned int line, todo, sol; + + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(0); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + } + /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); @@ -1164,7 +1143,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; + instructions += 5; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; @@ -1173,10 +1152,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines, 0); + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines, 0); + bpl, padding, lines, 0, UNSET == top_offset); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1200,7 +1179,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, than PAGE_SIZE */ /* Jump and write need an extra dword */ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; + instructions += 4; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) @@ -1209,7 +1188,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, /* write risc instructions */ rp = risc->cpu; rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, - bpl, 0, lines, lpi); + bpl, 0, lines, lpi, lpi == 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1239,7 +1218,7 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; + instructions += 5; rc = btcx_riscmem_alloc(pci, risc, instructions*12); if (rc < 0) return rc; @@ -1250,11 +1229,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, * in the userland vbi payload */ if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 6, - bpl, padding, lines, 0); + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, - bpl, padding, lines, 0); + bpl, padding, lines, 0, UNSET == top_offset); @@ -1265,38 +1244,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) -{ - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4*16); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) +void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_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(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + btcx_riscmem_free(dev->pci, &buf->risc); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) @@ -1351,7 +1302,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); } -static int cx23885_start_dma(struct cx23885_tsport *port, +int cx23885_start_dma(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { @@ -1359,7 +1310,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, u32 reg; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, - buf->vb.width, buf->vb.height, buf->vb.field); + dev->width, dev->height, dev->field); /* Stop the fifo and risc engine for this port */ cx_clear(port->reg_dma_ctl, port->dma_ctl_val); @@ -1375,7 +1326,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, } /* write TS length to chip */ - cx_write(port->reg_lngth, buf->vb.width); + cx_write(port->reg_lngth, port->ts_packet_size); if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { @@ -1404,7 +1355,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* NOTE: this is 2 (reserved) for portb, does it matter? */ /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); - q->count = 1; + q->count = 0; /* Set VIDB pins to input */ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { @@ -1493,134 +1444,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_buffer *buf; - - dprintk(5, "%s()\n", __func__); - if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; - - dprintk(5, "%s() queue is empty\n", __func__); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5, "[%p/%d] restart_queue - f/active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(5, "[%p/%d] restart_queue - m/active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } - return 0; - } - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_dma(port, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - /* ------------------------------------------------------------------ */ -int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field) +int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; int size = port->ts_packet_size * port->ts_packet_count; + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0); int rc; dprintk(1, "%s: %p\n", __func__, buf); - if (0 != buf->vb.baddr && buf->vb.bsize < size) + if (vb2_plane_size(&buf->vb, 0) < size) return -EINVAL; + vb2_set_plane_payload(&buf->vb, 0, size); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = port->ts_packet_size; - buf->vb.height = port->ts_packet_count; - buf->vb.size = size; - buf->vb.field = field /*V4L2_FIELD_TOP*/; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_databuffer(dev->pci, &buf->risc, - videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height, 0); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!rc) + return -EIO; - fail: - cx23885_free_buffer(q, buf); - return rc; + cx23885_risc_databuffer(dev->pci, &buf->risc, + sgt->sgl, + port->ts_packet_size, port->ts_packet_count, 0); + return 0; } +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) { struct cx23885_buffer *prev; struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *cx88q = &port->mpegq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + spin_lock_irqsave(&dev->slock, flags); if (list_empty(&cx88q->active)) { - dprintk(1, "queue is empty - first active\n"); - list_add_tail(&buf->vb.queue, &cx88q->active); - cx23885_start_dma(port, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + list_add_tail(&buf->queue, &cx88q->active); dprintk(1, "[%p/%d] %s - first active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } else { - dprintk(1, "queue is not empty - append to active\n"); + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; + queue); + list_add_tail(&buf->queue, &cx88q->active); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk(1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } + spin_unlock_irqrestore(&dev->slock, flags); } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, - int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; @@ -1630,16 +1530,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); + queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", - buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); - } - if (restart) { - dprintk(1, "restarting queue\n"); - cx23885_restart_queue(port, q); + buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma); } spin_unlock_irqrestore(&port->slock, flags); } @@ -1647,27 +1542,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, void cx23885_cancel_buffers(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __func__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} - -static void cx23885_timeout(unsigned long data) -{ - struct cx23885_tsport *port = (struct cx23885_tsport *)data; - struct cx23885_dev *dev = port->dev; dprintk(1, "%s()\n", __func__); - - if (debug > 5) - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - cx23885_stop_dma(port); - do_cancel_buffers(port, "timeout", 1); + do_cancel_buffers(port, "cancel"); } int cx23885_irq_417(struct cx23885_dev *dev, u32 status) @@ -1717,11 +1595,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status) spin_lock(&port->slock); cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_B_MSK_RISCI2) { - dprintk(7, " VID_B_MSK_RISCI2\n"); - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); } if (status) { cx_write(port->reg_ts_int_stat, status); @@ -1773,14 +1646,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_BC_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - } if (status) { cx_write(port->reg_ts_int_stat, status); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index d71d59f6c6d6..332e6facc095 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -87,59 +87,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ -static int dvb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_tsport *port = q->priv_data; + struct cx23885_tsport *port = q->drv_priv; port->ts_packet_size = 188 * 4; port->ts_packet_count = 32; - - *size = port->ts_packet_size * port->ts_packet_count; - *count = 32; + *num_planes = 1; + sizes[0] = port->ts_packet_size * port->ts_packet_count; + *num_buffers = 32; return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) + +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + return cx23885_buf_prepare(buf, port); } -static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - cx23885_buf_queue(port, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void dvb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_buf_queue(port, buf); } static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { - struct videobuf_dvb_frontends *f; - struct videobuf_dvb_frontend *fe; + struct vb2_dvb_frontends *f; + struct vb2_dvb_frontend *fe; f = &port->frontends; if (f->gate <= 1) /* undefined or fe0 */ - fe = videobuf_dvb_get_frontend(f, 1); + fe = vb2_dvb_get_frontend(f, 1); else - fe = videobuf_dvb_get_frontend(f, f->gate); + fe = vb2_dvb_get_frontend(f, f->gate); if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); } -static struct videobuf_queue_ops dvb_qops = { - .buf_setup = dvb_buf_setup, - .buf_prepare = dvb_buf_prepare, - .buf_queue = dvb_buf_queue, - .buf_release = dvb_buf_release, +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_tsport *port = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &port->mpegq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(port, dmaq, buf); + return 0; +} + +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_tsport *port = q->drv_priv; + + cx23885_cancel_buffers(port); +} + +static struct vb2_ops dvb_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, }; static struct s5h1409_config hauppauge_generic_config = { @@ -859,16 +895,16 @@ static int dvb_register(struct cx23885_tsport *port) struct dib7000p_ops dib7000p_ops; struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + struct vb2_dvb_frontend *fe0, *fe1 = NULL; int mfe_shared = 0; /* bus not shared by default */ int ret; /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); if (!fe0) return -EINVAL; - /* init struct videobuf_dvb */ + /* init struct vb2_dvb */ fe0->dvb.name = dev->name; /* multi-frontend gate control is undefined or defaults to fe0 */ @@ -1388,7 +1424,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); } /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + fe1 = vb2_dvb_get_frontend(&port->frontends, 2); if (fe1 == NULL) goto frontend_detach; /* DVB-C init */ @@ -1528,7 +1564,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); /* register everything */ - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared); if (ret) goto frontend_detach; @@ -1577,14 +1613,14 @@ static int dvb_register(struct cx23885_tsport *port) frontend_detach: port->gate_ctrl = NULL; - videobuf_dvb_dealloc_frontends(&port->frontends); + vb2_dvb_dealloc_frontends(&port->frontends); return -EINVAL; } int cx23885_dvb_register(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; + struct vb2_dvb_frontend *fe0; struct cx23885_dev *dev = port->dev; int err, i; @@ -1601,13 +1637,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port) port->num_frontends); for (i = 1; i <= port->num_frontends; i++) { - if (videobuf_dvb_alloc_frontend( + struct vb2_queue *q; + + if (vb2_dvb_alloc_frontend( &port->frontends, i) == NULL) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } - fe0 = videobuf_dvb_get_frontend(&port->frontends, i); + fe0 = vb2_dvb_get_frontend(&port->frontends, i); if (!fe0) err = -EINVAL; @@ -1623,10 +1661,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), port, NULL); + q = &fe0->dvb.dvbq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = port; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &dvb_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; } err = dvb_register(port); if (err != 0) @@ -1638,7 +1687,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; + struct vb2_dvb_frontend *fe0; /* FIXME: in an error condition where the we have * an expected number of frontends (attach problem) @@ -1647,9 +1696,9 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) * This comment only applies to future boards IF they * implement MFE support. */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); if (fe0 && fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&port->frontends); + vb2_dvb_unregister_bus(&port->frontends); switch (port->dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 23790fadc6d5..67b71f9b41f4 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -38,9 +38,8 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ #define VBI_LINE_LENGTH 1440 -#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ -#define NTSC_VBI_END_LINE 21 -#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) +#define VBI_NTSC_LINE_COUNT 12 +#define VBI_PAL_LINE_COUNT 18 int cx23885_vbi_fmt(struct file *file, void *priv, @@ -48,22 +47,23 @@ int cx23885_vbi_fmt(struct file *file, void *priv, { struct cx23885_dev *dev = video_drvdata(file); + f->fmt.vbi.sampling_rate = 27000000; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sampling_rate = 27000000; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.flags = 0; f->fmt.vbi.start[0] = 10; - f->fmt.vbi.count[0] = 17; - f->fmt.vbi.start[1] = 263 + 10 + 1; - f->fmt.vbi.count[1] = 17; + f->fmt.vbi.start[1] = 272; + f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 - 1; - f->fmt.vbi.start[1] = 319 - 1; + f->fmt.vbi.start[0] = 6; + f->fmt.vbi.start[1] = 318; + f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT; } return 0; @@ -89,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) handled++; } - if (status & VID_BC_MSK_VBI_RISCI2) { - dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); - dprintk(2, "stopper vbi\n"); - spin_lock(&dev->slock); - cx23885_restart_vbi_queue(dev, &dev->vbiq); - spin_unlock(&dev->slock); - handled++; - } - return handled; } @@ -109,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], - buf->vb.width, buf->risc.dma); + VBI_LINE_LENGTH, buf->risc.dma); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); cx_write(VID_A_VBI_CTRL, 3); cx_write(VBI_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -128,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, return 0; } +/* ------------------------------------------------------------------ */ -int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_buffer *buf; - struct list_head *item; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_vbi_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + struct cx23885_dev *dev = q->drv_priv; + unsigned lines = VBI_PAL_LINE_COUNT; + + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; + *num_planes = 1; + sizes[0] = lines * VBI_LINE_LENGTH * 2; return 0; } -void cx23885_vbi_timeout(unsigned long data) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vbiq; - struct cx23885_buffer *buf; - unsigned long flags; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + unsigned lines = VBI_PAL_LINE_COUNT; + int ret; - /* Stop the VBI engine */ - cx_clear(VID_A_DMA_CTL, 0x22); + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx23885_restart_vbi_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} + if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2) + return -EINVAL; + vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2); -/* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 1440 -#define VBI_LINE_COUNT 17 + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; + cx23885_risc_vbibuffer(dev->pci, &buf->risc, + sgt->sgl, + 0, VBI_LINE_LENGTH * lines, + VBI_LINE_LENGTH, 0, + lines); return 0; } -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_vbibuffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); - fail: - cx23885_free_buffer(q, buf); - return rc; + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->q_dev; - struct cx23885_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_dmaqueue *q = &dev->vbiq; + unsigned long flags; + + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); dprintk(2, "[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; + queue); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } } -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - cx23885_free_buffer(q, buf); + cx23885_start_vbi_dma(dev, dmaq, buf); + return 0; } -struct videobuf_queue_ops cx23885_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + unsigned long flags; -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ + cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->slock, flags); +} + + +struct vb2_ops cx23885_vbi_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 9cd8cf48334b..c6921d4bb7dd 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -98,34 +98,18 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } + if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + buf->vb.v4l2_buf.sequence = q->count++; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) @@ -163,50 +147,6 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - if (dev->resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); -} - int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) { /* 8 bit registers, 8 bit values */ @@ -356,7 +296,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -369,444 +309,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_video_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, - vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } + struct cx23885_dev *dev = q->drv_priv; - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; - - *size = (dev->fmt->depth * dev->width * dev->height) >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + *num_planes = 1; + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; return 0; } -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->q_dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - int rc, init_buffer = 0; u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); int field_tff; + int ret; - if (WARN_ON(NULL == dev->fmt)) - return -EINVAL; + buf->bpl = (dev->width * dev->fmt->depth) >> 3; - if (dev->width < 48 || dev->width > norm_maxw(dev->tvnorm) || - dev->height < 32 || dev->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + if (vb2_plane_size(vb, 0) < dev->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, dev->height * buf->bpl); - if (buf->fmt != dev->fmt || - buf->vb.width != dev->width || - buf->vb.height != dev->height || - buf->vb.field != field) { - buf->fmt = dev->fmt; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - init_buffer = 1; - } + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } + switch (dev->field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) - /* NTSC or */ - field_tff = 1; - else - field_tff = 0; - - if (cx23885_boards[dev->board].force_bff) - /* PAL / SECAM OR 888 in NTSC MODE */ - field_tff = 0; - - if (field_tff) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating TFF/NTSC risc\n", + if (field_tff) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); + line0_offset = 0; + line1_offset = buf->bpl; } + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (dev->height >> 1), + buf->bpl, 0, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (dev->height >> 1), 0, + buf->bpl, 0, + dev->height >> 1); + break; + default: + BUG(); } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.v4l2_buf.index, dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} - fail: - cx23885_free_buffer(q, buf); - return rc; +static void buffer_finish(struct vb2_buffer *vb) +{ + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->q_dev; struct cx23885_dmaqueue *q = &dev->vidq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + /* add jump to start */ + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + spin_lock_irqsave(&dev->slock, flags); + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = file->private_data; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - return &fh->vidq; - case VFL_TYPE_VBI: - return &fh->vbiq; - default: - WARN_ON(1); - return NULL; - } -} - -static int get_resource(u32 type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - WARN_ON(1); - return 0; + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.v4l2_buf.index); } + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_open(struct file *file) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - - dprintk(1, "open dev=%s\n", - video_device_node_name(vdev)); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - v4l2_fh_init(&fh->fh, vdev); - file->private_data = &fh->fh; - fh->q_dev = dev; - - videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - - videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct cx23885_buffer), - fh, NULL); - - v4l2_fh_add(&fh->fh); - - dprintk(1, "post videobuf_queue_init()\n"); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + cx23885_start_video_dma(dev, dmaq, buf); return 0; } -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) +static void cx23885_stop_streaming(struct vb2_queue *q) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - if (res_locked(dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case VFL_TYPE_VBI: - if (!res_get(dev, fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - return -EINVAL; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - unsigned long req_events = poll_requested_events(wait); - unsigned int rc = 0; - - if (v4l2_event_pending(&fh->fh)) - rc = POLLPRI; - else - poll_wait(file, &fh->fh.wait, wait); - if (!(req_events & (POLLIN | POLLRDNORM))) - return rc; - - if (vdev->vfl_type == VFL_TYPE_VBI) { - if (!res_get(dev, fh, RESOURCE_VBI)) - return rc | POLLERR; - return rc | videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc |= POLLIN | POLLRDNORM; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = file->private_data; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + unsigned long flags; - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } + cx_clear(VID_A_DMA_CTL, 0x11); + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - - videobuf_mmap_free(&fh->vidq); - videobuf_mmap_free(&fh->vbiq); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - return videobuf_mmap_mapper(get_queue(file), vma); -} +static struct vb2_ops cx23885_video_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -815,11 +517,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = priv; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.field = dev->field; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -880,7 +581,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh = priv; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -892,9 +592,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; + dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - dev->width, dev->height, fh->vidq.field); + dev->width, dev->height, dev->field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); @@ -936,82 +636,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - return videobuf_reqbufs(get_queue(file), p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_querybuf(get_queue(file), p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_qbuf(get_queue(file), p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - return videobuf_dqbuf(get_queue(file), p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(i)))) - return -EBUSY; - - /* Don't start VBI streaming unless vida streaming - * has already started. - */ - if ((i == V4L2_BUF_TYPE_VBI_CAPTURE) && - ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) - return -EINVAL; - - return videobuf_streamon(get_queue(file)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cx23885_fh *fh = priv; - int err, res; - dprintk(1, "%s()\n", __func__); - - if (vdev->vfl_type == VFL_TYPE_VBI && - i != V4L2_BUF_TYPE_VBI_CAPTURE) - return -EINVAL; - if (vdev->vfl_type == VFL_TYPE_GRABBER && - i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - res = get_resource(i); - err = videobuf_streamoff(get_queue(file)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_dev *dev = video_drvdata(file); @@ -1288,7 +912,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, { struct v4l2_ctrl *mute; int old_mute_val = 1; - struct videobuf_dvb_frontend *vfe; + struct vb2_dvb_frontend *vfe; struct dvb_frontend *fe; struct analog_parameters params = { @@ -1312,7 +936,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, params.frequency, f->tuner, params.std); - vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { return -EINVAL; } @@ -1368,28 +992,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, /* ----------------------------------------------------------- */ -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx23885_video_irq(struct cx23885_dev *dev, u32 status) { u32 mask, count; @@ -1434,13 +1036,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) spin_unlock(&dev->slock); handled++; } - if (status & VID_BC_MSK_RISCI2) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } /* Allow the VBI framework to process it's payload */ handled += cx23885_vbi_irq(dev, status); @@ -1453,12 +1048,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1470,18 +1065,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_log_status = vidioc_log_status, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, @@ -1517,7 +1113,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; - btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) @@ -1525,8 +1120,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->video_dev); dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } if (dev->audio_dev) @@ -1535,6 +1128,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) int cx23885_video_register(struct cx23885_dev *dev) { + struct vb2_queue *q; int err; dprintk(1, "%s()\n", __func__); @@ -1551,21 +1145,9 @@ int cx23885_video_register(struct cx23885_dev *dev) /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); /* init vbi dma queues */ INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vbiq.timeout.function = cx23885_vbi_timeout; - dev->vbiq.timeout.data = (unsigned long)dev; - init_timer(&dev->vbiq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, - VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1626,9 +1208,42 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_audio_mux(dev, 0); mutex_unlock(&dev->lock); + q = &dev->vb2_vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_video_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + + q = &dev->vb2_vbiq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_vbi_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); + dev->video_dev->queue = &dev->vb2_vidq; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1642,6 +1257,7 @@ int cx23885_video_register(struct cx23885_dev *dev) /* register VBI device */ dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); + dev->vbi_dev->queue = &dev->vb2_vbiq; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 5f5d8e8aa472..388e420d88e9 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -25,8 +25,8 @@ #include #include #include -#include -#include +#include +#include #include #include "btcx-risc.h" @@ -35,7 +35,7 @@ #include -#define CX23885_VERSION "0.0.3" +#define CX23885_VERSION "0.0.4" #define UNSET (-1U) @@ -44,9 +44,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -136,20 +133,6 @@ struct cx23885_tvnorm { u32 cxoformat; }; -struct cx23885_fh { - struct v4l2_fh fh; - u32 resources; - struct cx23885_dev *q_dev; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; - enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, CX23885_VMUX_COMPOSITE2, @@ -172,7 +155,8 @@ enum cx23885_src_sel_type { /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head queue; /* cx23885 specific */ unsigned int bpl; @@ -248,9 +232,6 @@ struct cx23885_i2c { struct cx23885_dmaqueue { struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; u32 count; }; @@ -260,7 +241,7 @@ struct cx23885_tsport { int nr; int sram_chno; - struct videobuf_dvb_frontends frontends; + struct vb2_dvb_frontends frontends; /* dma queues */ struct cx23885_dmaqueue mpegq; @@ -389,7 +370,6 @@ struct cx23885_dev { } bridge; /* Analog video */ - u32 resources; unsigned int input; unsigned int audinput; /* Selectable audio input */ u32 tvaudio; @@ -420,16 +400,20 @@ struct cx23885_dev { /* video capture */ struct cx23885_fmt *fmt; unsigned int width, height; + unsigned field; struct cx23885_dmaqueue vidq; + struct vb2_queue vb2_vidq; struct cx23885_dmaqueue vbiq; + struct vb2_queue vb2_vbiq; + spinlock_t slock; /* MPEG Encoder ONLY settings */ u32 cx23417_mailbox; struct cx2341x_handler cxhdl; struct video_device *v4l_device; - atomic_t v4l_reader_count; + struct vb2_queue vb2_mpegq; struct cx23885_tvnorm encodernorm; /* Analog raw audio */ @@ -505,9 +489,6 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch); -extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, @@ -518,13 +499,11 @@ extern int cx23885_risc_vbibuffer(struct pci_dev *pci, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); +int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf); void cx23885_cancel_buffers(struct cx23885_tsport *port); -extern int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q); - -extern void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count); extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); @@ -558,13 +537,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, - struct cx23885_tsport *port, - struct cx23885_buffer *buf, - enum v4l2_field field); +extern int cx23885_buf_prepare(struct cx23885_buffer *buf, + struct cx23885_tsport *port); extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, +extern void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ @@ -586,9 +563,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); -extern struct videobuf_queue_ops cx23885_vbi_qops; -extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q); +extern struct vb2_ops cx23885_vbi_qops; extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ -- cgit v1.2.3 From 96f233e97587a7f6c0f47476118cdb9a23a9ebe0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2014 18:04:41 -0300 Subject: [media] cx23885: fix field handling Add missing SEQ_BT/TB support, bottom field is first for all 60 Hz formats, not just NTSC, restore an overwritten field value and initialize dev->field correctly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index c6921d4bb7dd..defdf7486eda 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -352,7 +352,7 @@ static int buffer_prepare(struct vb2_buffer *vb) buf->bpl, 0, dev->height); break; case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) + if (dev->tvnorm & V4L2_STD_525_60) /* NTSC or */ field_tff = 1; else @@ -559,6 +559,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: break; default: field = V4L2_FIELD_INTERLACED; @@ -598,6 +600,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + f->fmt.pix.field = dev->field; return 0; } @@ -1140,6 +1144,7 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->tvnorm = V4L2_STD_NTSC_M; dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); + dev->field = V4L2_FIELD_INTERLACED; dev->width = norm_maxw(dev->tvnorm); dev->height = norm_maxh(dev->tvnorm); -- cgit v1.2.3 From 4d63a25c4523b5d18e5307897d56aff785f43bf5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Aug 2014 06:26:01 -0300 Subject: [media] cx23885: remove btcx-risc dependency It's just as easy to do it in the driver. This dependency only uses a fraction of the btcx-risc module and doing it directly in the driver adds only a few lines. The btcx-risc module is really meant for the bttv driver, not for other drivers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 1 - drivers/media/pci/cx23885/Makefile | 1 - drivers/media/pci/cx23885/cx23885-alsa.c | 5 ++++- drivers/media/pci/cx23885/cx23885-core.c | 36 +++++++++++++++++--------------- drivers/media/pci/cx23885/cx23885.h | 18 ++++++++++------ 5 files changed, 35 insertions(+), 26 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 38c3b7bc7c2a..a883ea4968be 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -3,7 +3,6 @@ config VIDEO_CX23885 depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND select SND_PCM select I2C_ALGOBIT - select VIDEO_BTCX select VIDEO_TUNER select VIDEO_TVEEPROM depends on RC_CORE diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile index 2a2cafb8cf5b..a2cbdcf15a8c 100644 --- a/drivers/media/pci/cx23885/Makefile +++ b/drivers/media/pci/cx23885/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o ccflags-y += -Idrivers/media/i2c -ccflags-y += -Idrivers/media/common ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 1b162ee8c8c6..ae7c2e89ad1c 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -270,12 +270,15 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) static int dsp_buffer_free(struct cx23885_audio_dev *chip) { + struct cx23885_riscmem *risc; + BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); cx23885_alsa_dma_unmap(chip); cx23885_alsa_dma_free(chip->buf); - btcx_riscmem_free(chip->pci, &chip->buf->risc); + risc = &chip->buf->risc; + pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); chip->buf = NULL; diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 8d77a5649777..cb94366b9504 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -570,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, } static void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) + struct cx23885_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -1121,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, return rp; } -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1144,9 +1143,10 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 5; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1164,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi) { u32 instructions; __le32 *rp; - int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + syncs + jump (all 2 dwords). Here @@ -1181,9 +1180,10 @@ int cx23885_risc_databuffer(struct pci_dev *pci, instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 4; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1196,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } -int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1219,9 +1218,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); instructions += 5; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; @@ -1246,8 +1246,10 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { + struct cx23885_riscmem *risc = &buf->risc; + BUG_ON(in_interrupt()); - btcx_riscmem_free(dev->pci, &buf->risc); + pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 388e420d88e9..0e4f4061087f 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -29,7 +29,6 @@ #include #include -#include "btcx-risc.h" #include "cx23885-reg.h" #include "media/cx2341x.h" @@ -152,6 +151,13 @@ enum cx23885_src_sel_type { CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO }; +struct cx23885_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ @@ -160,7 +166,7 @@ struct cx23885_buffer { /* cx23885 specific */ unsigned int bpl; - struct btcx_riscmem risc; + struct cx23885_riscmem risc; struct cx23885_fmt *fmt; u32 count; }; @@ -300,7 +306,7 @@ struct cx23885_kernel_ir { struct cx23885_audio_buffer { unsigned int bpl; - struct btcx_riscmem risc; + struct cx23885_riscmem risc; void *vaddr; struct scatterlist *sglist; int sglen; @@ -489,13 +495,13 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch); -extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); extern int cx23885_risc_vbibuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, struct scatterlist *sglist, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); @@ -595,7 +601,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register( extern void cx23885_audio_unregister(struct cx23885_dev *dev); extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); extern int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, -- cgit v1.2.3 From f1b6a735328b507810d2436891ee977fb8cd62d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Aug 2014 06:43:36 -0300 Subject: [media] cx23885: Add busy checks before changing formats Before you can change the standard or the capture format, make sure the various vb2_queues aren't in use since you cannot change the buffer size from underneath a a busy vb2_queue. Also make sure that the return code of cx23885_set_tvnorm is returned correctly, otherwise the -EBUSY will be lost. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-417.c | 10 +++++----- drivers/media/pci/cx23885/cx23885-video.c | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index f1ef9017e2a7..6973055f0814 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1248,18 +1248,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx23885_dev *dev = video_drvdata(file); unsigned int i; + int ret; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) if (id & cx23885_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; - dev->encodernorm = cx23885_tvnorms[i]; - - /* Have the drier core notify the subdevices */ - cx23885_set_tvnorm(dev, id); - return 0; + ret = cx23885_set_tvnorm(dev, id); + if (!ret) + dev->encodernorm = cx23885_tvnorms[i]; + return ret; } static int vidioc_enum_input(struct file *file, void *priv, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index defdf7486eda..f0ea904d4669 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -119,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) (unsigned int)norm, v4l2_norm_to_name(norm)); + if (dev->tvnorm != norm) { + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + } + dev->tvnorm = norm; call_all(dev, video, s_std, norm); @@ -591,6 +597,11 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; + + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; @@ -654,9 +665,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); - cx23885_set_tvnorm(dev, tvnorms); - - return 0; + return cx23885_set_tvnorm(dev, tvnorms); } int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) -- cgit v1.2.3 From 947b38bb110c90e0bc93e7afe9ab6f007b6799a7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Sep 2014 13:26:52 -0300 Subject: [media] tw68: simplify tw68_buffer_count The code to calculate the maximum number of buffers allowed in 4 MB is 1) wrong if PAGE_SIZE != 4096 and 2) unnecessarily complex. Fix and simplify the code. Reported-by: Mauro Carvalho Chehab Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 66fae2345fdd..498ead9a956d 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -361,22 +361,13 @@ int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) /* ------------------------------------------------------------------ */ -/* nr of (tw68-)pages for the given buffer size */ -static int tw68_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - /* calc max # of buffers from size (must not exceed the 4MB virtual * address space per DMA channel) */ static int tw68_buffer_count(unsigned int size, unsigned int count) { unsigned int maxcount; - maxcount = 1024 / tw68_buffer_pages(size); + maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE); if (count > maxcount) count = maxcount; return count; -- cgit v1.2.3 From 91f96e8b7255537da3a58805cf465003521d7c5f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Sep 2014 13:26:53 -0300 Subject: [media] tw68: drop bogus cpu_to_le32() call tw_writel maps to writel which maps to __raw_writel(__cpu_to_le32(b),addr). So tw_writel already calls cpu_to_le32 and it shouldn't be called again in the code. Reported-by: Mauro Carvalho Chehab Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 498ead9a956d..5c94ac7c88d9 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -348,7 +348,7 @@ int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf) * a new address can be set. */ tw_clearl(TW68_DMAC, TW68_DMAP_EN); - tw_writel(TW68_DMAP_SA, cpu_to_le32(buf->dma)); + tw_writel(TW68_DMAP_SA, buf->dma); /* Clear any pending interrupts */ tw_writel(TW68_INTSTAT, dev->board_virqmask); /* Enable the risc engine and the fifo */ -- cgit v1.2.3 From 420b21761986dc16521e72951b9fc6e5d0a515df Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 10:19:32 -0300 Subject: [media] cx23885: fix VBI support Tested VBI support and discovered that the wrong offset was used. After this change it is now working. Verified with CC/XDS for NTSC and WSS/Teletext on PAL. It also reported the wrong start lines for the second field. That's now fixed as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 4 ++-- drivers/media/pci/cx23885/cx23885-vbi.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index cb94366b9504..331eddac7222 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1228,11 +1228,11 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, /* Sync to line 6, so US CC line 21 will appear in line '12' * in the userland vbi payload */ if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 6, + rp = cx23885_risc_field(rp, sglist, top_offset, 0, bpl, padding, lines, 0, true); if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, bpl, padding, lines, 0, UNSET == top_offset); diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 67b71f9b41f4..a7c6ef8f3ea3 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -54,14 +54,14 @@ int cx23885_vbi_fmt(struct file *file, void *priv, f->fmt.vbi.flags = 0; if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 272; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9; f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT; f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ - f->fmt.vbi.start[0] = 6; - f->fmt.vbi.start[1] = 318; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5; f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT; f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT; } -- cgit v1.2.3 From 1c5eaa23d8fb8bb8c0f4707eeb456a870d7c18c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 20 Sep 2014 10:19:33 -0300 Subject: [media] cx23885: fix size helper functions The norm_swidth function was unused and is dropped. It's not clear what the purpose of that function was. The norm_maxh function was changed so it tests for 60 Hz standards rather than for 50 Hz standards. The is the preferred order. The norm_maxw function was poorly written and used: it gives the maximum allowed line width for the given standard. For 60 Hz that's 720, but for 50 Hz that's 768 which allows for 768x576 which gives you square pixels. For 60 Hz formats it is 640x480 that gives square pixels, so there is no need to go beyond 720. The initial width was set using norm_maxh(), which was wrong. Just set to 720, that's what you normally use. Since the initial standard was NTSC anyway the initial width was always 720 anyway. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-video.c | 2 +- drivers/media/pci/cx23885/cx23885.h | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index f0ea904d4669..682a4f95df6b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1154,7 +1154,7 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->tvnorm = V4L2_STD_NTSC_M; dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); dev->field = V4L2_FIELD_INTERLACED; - dev->width = norm_maxw(dev->tvnorm); + dev->width = 720; dev->height = norm_maxh(dev->tvnorm); /* init video dma queues */ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0e4f4061087f..39a89855d1d5 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -612,15 +612,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci, static inline unsigned int norm_maxw(v4l2_std_id norm) { - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; + return (norm & V4L2_STD_525_60) ? 720 : 768; } static inline unsigned int norm_maxh(v4l2_std_id norm) { - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -static inline unsigned int norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; + return (norm & V4L2_STD_525_60) ? 480 : 576; } -- cgit v1.2.3 From 033d008821b9d04e823ef7adb5ef2504506f7028 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 21 Sep 2014 06:38:55 -0300 Subject: [media] saa7134: also capture the WSS signal for 50 Hz VBI capture The saa7134 driver missed capturing line 23 of the VBI area for the 50 Hz formats. Include that line in the VBI capture. Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-vbi.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index c06dbe17a87f..4f0b1012e4f3 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); /* ------------------------------------------------------------------ */ -#define VBI_LINE_COUNT 16 +#define VBI_LINE_COUNT 17 #define VBI_LINE_LENGTH 2048 #define VBI_SCALE 0x200 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 0cfa2ca6a32a..fc4a427cb51f 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -201,7 +201,7 @@ static struct saa7134_format formats[] = { .video_v_start = 24, \ .video_v_stop = 311, \ .vbi_v_start_0 = 7, \ - .vbi_v_stop_0 = 22, \ + .vbi_v_stop_0 = 23, \ .vbi_v_start_1 = 319, \ .src_timing = 4 -- cgit v1.2.3 From 452015de2e2afaf0e2f76f28477dd3025d44bc95 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 21 Sep 2014 06:52:03 -0300 Subject: [media] saa7134: add saa7134-go7007 This patch adds support to saa7134 for 'WIS Voyager or compatible' PCI boards such as the Sensoray model 614 with which this patch was tested. It is a saa7134-based PCI board with a go7007 MPEG encoder. This was a patch when the go7007 was still in staging and was not applied when go7007 was moved to drivers/media since it needed more work. That work is now done and this last piece of go7007 support can now go in. Signed-off-by: Hans Verkuil Tested-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/Makefile | 3 +- drivers/media/pci/saa7134/saa7134-cards.c | 29 ++ drivers/media/pci/saa7134/saa7134-core.c | 10 +- drivers/media/pci/saa7134/saa7134-go7007.c | 532 +++++++++++++++++++++++++++++ drivers/media/pci/saa7134/saa7134.h | 5 + 5 files changed, 576 insertions(+), 3 deletions(-) create mode 100644 drivers/media/pci/saa7134/saa7134-go7007.c (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile index 58de9b085689..b55bd9afda11 100644 --- a/drivers/media/pci/saa7134/Makefile +++ b/drivers/media/pci/saa7134/Makefile @@ -4,7 +4,7 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o saa7134-y += saa7134-video.o saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa7134-go7007.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o @@ -14,3 +14,4 @@ ccflags-y += -I$(srctree)/drivers/media/i2c ccflags-y += -I$(srctree)/drivers/media/tuners ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends +ccflags-y += -I$(srctree)/drivers/media/usb/go7007 diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 6e4bdb90aa92..3ca078057755 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -5827,6 +5827,29 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0000800, }, }, + [SAA7134_BOARD_WIS_VOYAGER] = { + .name = "WIS Voyager or compatible", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_GO7007, + .inputs = { { + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_svideo, + .vmux = 6, + .amux = LINE1, + } }, + }, }; @@ -7079,6 +7102,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */ .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1905, /* WIS */ + .subdevice = 0x7007, + .driver_data = SAA7134_BOARD_WIS_VOYAGER, }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 9ff03a69ced4..236ed725f933 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -160,6 +160,8 @@ static void request_module_async(struct work_struct *work){ request_module("saa7134-empress"); if (card_is_dvb(dev)) request_module("saa7134-dvb"); + if (card_is_go7007(dev)) + request_module("saa7134-go7007"); if (alsa) { if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130) request_module("saa7134-alsa"); @@ -563,8 +565,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) saa7134_irq_vbi_done(dev,status); if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && - card_has_mpeg(dev)) - saa7134_irq_ts_done(dev,status); + card_has_mpeg(dev)) { + if (dev->mops->irq_ts_done != NULL) + dev->mops->irq_ts_done(dev, status); + else + saa7134_irq_ts_done(dev, status); + } if (report & SAA7134_IRQ_REPORT_GPIO16) { switch (dev->has_remote) { diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c new file mode 100644 index 000000000000..3e9ca4821b8c --- /dev/null +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "saa7134.h" +#include "saa7134-reg.h" +#include "go7007-priv.h" + +/*#define GO7007_HPI_DEBUG*/ + +enum hpi_address { + HPI_ADDR_VIDEO_BUFFER = 0xe4, + HPI_ADDR_INIT_BUFFER = 0xea, + HPI_ADDR_INTR_RET_VALUE = 0xee, + HPI_ADDR_INTR_RET_DATA = 0xec, + HPI_ADDR_INTR_STATUS = 0xf4, + HPI_ADDR_INTR_WR_PARAM = 0xf6, + HPI_ADDR_INTR_WR_INDEX = 0xf8, +}; + +enum gpio_command { + GPIO_COMMAND_RESET = 0x00, /* 000b */ + GPIO_COMMAND_REQ1 = 0x04, /* 001b */ + GPIO_COMMAND_WRITE = 0x20, /* 010b */ + GPIO_COMMAND_REQ2 = 0x24, /* 011b */ + GPIO_COMMAND_READ = 0x80, /* 100b */ + GPIO_COMMAND_VIDEO = 0x84, /* 101b */ + GPIO_COMMAND_IDLE = 0xA0, /* 110b */ + GPIO_COMMAND_ADDR = 0xA4, /* 111b */ +}; + +struct saa7134_go7007 { + struct v4l2_subdev sd; + struct saa7134_dev *dev; + u8 *top; + u8 *bottom; + dma_addr_t top_dma; + dma_addr_t bottom_dma; +}; + +static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct saa7134_go7007, sd); +} + +static const struct go7007_board_info board_voyager = { + .flags = 0, + .sensor_flags = GO7007_SENSOR_656 | + GO7007_SENSOR_VALID_ENABLE | + GO7007_SENSOR_TV | + GO7007_SENSOR_VBI, + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | + GO7007_AUDIO_WORD_16, + .audio_rate = 48000, + .audio_bclk_div = 8, + .audio_main_div = 2, + .hpi_buffer_cap = 7, + .num_inputs = 1, + .inputs = { + { + .name = "SAA7134", + }, + }, +}; + +/********************* Driver for GPIO HPI interface *********************/ + +static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data) +{ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + /* Write HPI address */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Write low byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Write high byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + return 0; +} + +static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data) +{ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + /* Write HPI address */ + saa_writeb(SAA7134_GPIO_GPSTATUS0, addr); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); + + /* Read low byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + *data = saa_readb(SAA7134_GPIO_GPSTATUS0); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + /* Read high byte */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ); + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8; + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + + return 0; +} + +static int saa7134_go7007_interface_reset(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + u32 status; + u16 intr_val, intr_data; + int count = 20; + + saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */ + saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4); + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET); + msleep(1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); + msleep(10); + + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + status = saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_debug("status is %s\n", status & 0x40 ? "OK" : "not OK"); */ + + /* enter command mode...(?) */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2); + + do { + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + status = saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ + } while (--count > 0); + + /* Wait for an interrupt to indicate successful hardware reset */ + if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || + (intr_val & ~0x1) != 0x55aa) { + pr_err("saa7134-go7007: unable to reset the GO7007\n"); + return -1; + } + return 0; +} + +static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + int i; + u16 status_reg; + +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data); +#endif + + for (i = 0; i < 100; ++i) { + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); + if (!(status_reg & 0x0010)) + break; + msleep(10); + } + if (i == 100) { + pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n", + status_reg); + return -1; + } + gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data); + gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr); + + return 0; +} + +static int saa7134_go7007_read_interrupt(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + + /* XXX we need to wait if there is no interrupt available */ + go->interrupt_available = 1; + gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value); + gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data); +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n", + go->interrupt_value, go->interrupt_data); +#endif + return 0; +} + +static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, + unsigned long status) +{ + struct go7007 *go = video_get_drvdata(dev->empress_dev); + struct saa7134_go7007 *saa = go->hpi_context; + + if (!vb2_is_streaming(&go->vidq)) + return; + if (0 != (status & 0x000f0000)) + pr_debug("saa7134-go7007: irq: lost %ld\n", + (status >> 16) & 0x0f); + if (status & 0x100000) { + dma_sync_single_for_cpu(&dev->pci->dev, + saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); + go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + } else { + dma_sync_single_for_cpu(&dev->pci->dev, + saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); + go7007_parse_video_stream(go, saa->top, PAGE_SIZE); + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + } +} + +static int saa7134_go7007_stream_start(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + + saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), + 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&dev->pci->dev, saa->top_dma)) + return -ENOMEM; + saa->bottom_dma = dma_map_page(&dev->pci->dev, + virt_to_page(saa->bottom), + 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) { + dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, + DMA_FROM_DEVICE); + return -ENOMEM; + } + + saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000); + saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200); + + /* Set HPI interface for video */ + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPMODE0, 0x00); + + /* Enable TS interface */ + saa_writeb(SAA7134_TS_PARALLEL, 0xe6); + + /* Reset TS interface */ + saa_setb(SAA7134_TS_SERIAL1, 0x01); + saa_clearb(SAA7134_TS_SERIAL1, 0x01); + + /* Set up transfer block size */ + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); + saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); + saa_writeb(SAA7134_TS_DMA1, 0); + saa_writeb(SAA7134_TS_DMA2, 0); + + /* Enable video streaming mode */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); + + saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_PITCH(5), 128); + saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); + + /* Enable TS FIFO */ + saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); + + /* Enable DMA IRQ */ + saa_setl(SAA7134_IRQ1, + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); + + return 0; +} + +static int saa7134_go7007_stream_stop(struct go7007 *go) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev; + + if (!saa) + return -EINVAL; + dev = saa->dev; + if (!dev) + return -EINVAL; + + /* Shut down TS FIFO */ + saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5); + + /* Disable DMA IRQ */ + saa_clearl(SAA7134_IRQ1, + SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0); + + /* Disable TS interface */ + saa_clearb(SAA7134_TS_PARALLEL, 0x80); + + dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, + DMA_FROM_DEVICE); + dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, + DMA_FROM_DEVICE); + + return 0; +} + +static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) +{ + struct saa7134_go7007 *saa = go->hpi_context; + struct saa7134_dev *dev = saa->dev; + u16 status_reg; + int i; + +#ifdef GO7007_HPI_DEBUG + pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len); +#endif + + while (len > 0) { + i = len > 64 ? 64 : len; + saa_writeb(SAA7134_GPIO_GPMODE0, 0xff); + saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + while (i-- > 0) { + saa_writeb(SAA7134_GPIO_GPSTATUS0, *data); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE); + saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE); + ++data; + --len; + } + for (i = 0; i < 100; ++i) { + gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg); + if (!(status_reg & 0x0002)) + break; + } + if (i == 100) { + pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n", + status_reg); + return -1; + } + } + return 0; +} + +static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { + .interface_reset = saa7134_go7007_interface_reset, + .write_interrupt = saa7134_go7007_write_interrupt, + .read_interrupt = saa7134_go7007_read_interrupt, + .stream_start = saa7134_go7007_stream_start, + .stream_stop = saa7134_go7007_stream_stop, + .send_firmware = saa7134_go7007_send_firmware, +}; +MODULE_FIRMWARE("go7007/go7007tv.bin"); + +/* --------------------------------------------------------------------------*/ + +static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ +#if 0 + struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_dev *dev = saa->dev; + + return saa7134_s_std_internal(dev, NULL, norm); +#else + return 0; +#endif +} + +static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = { + .s_std = saa7134_go7007_s_std, +}; + +static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = { + .video = &saa7134_go7007_video_ops, +}; + +/* --------------------------------------------------------------------------*/ + + +/********************* Add/remove functions *********************/ + +static int saa7134_go7007_init(struct saa7134_dev *dev) +{ + struct go7007 *go; + struct saa7134_go7007 *saa; + struct v4l2_subdev *sd; + + pr_debug("saa7134-go7007: probing new SAA713X board\n"); + + go = go7007_alloc(&board_voyager, &dev->pci->dev); + if (go == NULL) + return -ENOMEM; + + saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); + if (saa == NULL) { + kfree(go); + return -ENOMEM; + } + + go->board_id = GO7007_BOARDID_PCI_VOYAGER; + snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci)); + strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); + go->hpi_ops = &saa7134_go7007_hpi_ops; + go->hpi_context = saa; + saa->dev = dev; + + /* Init the subdevice interface */ + sd = &saa->sd; + v4l2_subdev_init(sd, &saa7134_go7007_sd_ops); + v4l2_set_subdevdata(sd, saa); + strncpy(sd->name, "saa7134-go7007", sizeof(sd->name)); + + /* Allocate a couple pages for receiving the compressed stream */ + saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!saa->top) + goto allocfail; + saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL); + if (!saa->bottom) + goto allocfail; + + /* Boot the GO7007 */ + if (go7007_boot_encoder(go, go->board_info->flags & + GO7007_BOARD_USE_ONBOARD_I2C) < 0) + goto allocfail; + + /* Do any final GO7007 initialization, then register the + * V4L2 and ALSA interfaces */ + if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0) + goto allocfail; + + /* Register the subdevice interface with the go7007 device */ + if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0) + pr_info("saa7134-go7007: register subdev failed\n"); + + dev->empress_dev = &go->vdev; + + go->status = STATUS_ONLINE; + return 0; + +allocfail: + if (saa->top) + free_page((unsigned long)saa->top); + if (saa->bottom) + free_page((unsigned long)saa->bottom); + kfree(saa); + kfree(go); + return -ENOMEM; +} + +static int saa7134_go7007_fini(struct saa7134_dev *dev) +{ + struct go7007 *go; + struct saa7134_go7007 *saa; + + if (NULL == dev->empress_dev) + return 0; + + go = video_get_drvdata(dev->empress_dev); + if (go->audio_enabled) + go7007_snd_remove(go); + + saa = go->hpi_context; + go->status = STATUS_SHUTDOWN; + free_page((unsigned long)saa->top); + free_page((unsigned long)saa->bottom); + v4l2_device_unregister_subdev(&saa->sd); + kfree(saa); + video_unregister_device(&go->vdev); + + v4l2_device_put(&go->v4l2_dev); + dev->empress_dev = NULL; + + return 0; +} + +static struct saa7134_mpeg_ops saa7134_go7007_ops = { + .type = SAA7134_MPEG_GO7007, + .init = saa7134_go7007_init, + .fini = saa7134_go7007_fini, + .irq_ts_done = saa7134_go7007_irq_ts_done, +}; + +static int __init saa7134_go7007_mod_init(void) +{ + return saa7134_ts_register(&saa7134_go7007_ops); +} + +static void __exit saa7134_go7007_mod_cleanup(void) +{ + saa7134_ts_unregister(&saa7134_go7007_ops); +} + +module_init(saa7134_go7007_mod_init); +module_exit(saa7134_go7007_mod_cleanup); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index e47edd4b57ce..1a82dd07205b 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -338,6 +338,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_ASUSTeK_PS3_100 190 #define SAA7134_BOARD_HAWELL_HW_9004V1 191 #define SAA7134_BOARD_AVERMEDIA_A706 192 +#define SAA7134_BOARD_WIS_VOYAGER 193 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -368,6 +369,7 @@ enum saa7134_mpeg_type { SAA7134_MPEG_UNUSED, SAA7134_MPEG_EMPRESS, SAA7134_MPEG_DVB, + SAA7134_MPEG_GO7007, }; enum saa7134_mpeg_ts_type { @@ -407,6 +409,7 @@ struct saa7134_board { #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) #define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg) #define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg) +#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg) #define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg) #define card(dev) (saa7134_boards[dev->board]) #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) @@ -522,6 +525,8 @@ struct saa7134_mpeg_ops { int (*init)(struct saa7134_dev *dev); int (*fini)(struct saa7134_dev *dev); void (*signal_change)(struct saa7134_dev *dev); + void (*irq_ts_done)(struct saa7134_dev *dev, + unsigned long status); }; /* global device status */ -- cgit v1.2.3 From aff440fa6197d0f78f04cfe552c97464f7048ded Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 12:52:21 -0300 Subject: [media] saa7134: Fix compilation breakage when go7007 is not selected All error/warnings: drivers/built-in.o: In function `saa7134_go7007_fini': >> saa7134-go7007.c:(.text+0x3b628b): undefined reference to `go7007_snd_remove' drivers/built-in.o: In function `saa7134_go7007_interface_reset': >> saa7134-go7007.c:(.text+0x3b659a): undefined reference to `go7007_read_interrupt' drivers/built-in.o: In function `saa7134_go7007_init': >> saa7134-go7007.c:(.text+0x3b65fa): undefined reference to `go7007_alloc' >> saa7134-go7007.c:(.text+0x3b66ed): undefined reference to `go7007_boot_encoder' >> saa7134-go7007.c:(.text+0x3b66fe): undefined reference to `go7007_register_encoder' drivers/built-in.o: In function `saa7134_go7007_irq_ts_done': >> saa7134-go7007.c:(.text+0x3b6c2a): undefined reference to `go7007_parse_video_stream' >> saa7134-go7007.c:(.text+0x3b6c86): undefined reference to `go7007_parse_video_stream' This happens when: - VIDEO_SAA7134 is either 'm' or 'y' - VIDEO_GO7007 is not selected. Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/Kconfig | 8 ++++++++ drivers/media/pci/saa7134/Makefile | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index 18ae75546302..b44e0d70907e 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -63,3 +63,11 @@ config VIDEO_SAA7134_DVB To compile this driver as a module, choose M here: the module will be called saa7134-dvb. + +config VIDEO_SAA7134_GO7007 + tristate "go7007 support for saa7134 based TV cards" + depends on VIDEO_SAA7134 + depends on VIDEO_GO7007 + ---help--- + Enables saa7134 driver support for boards with go7007 + MPEG encoder (WIS Voyager or compatible). diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile index b55bd9afda11..09c43da67588 100644 --- a/drivers/media/pci/saa7134/Makefile +++ b/drivers/media/pci/saa7134/Makefile @@ -4,7 +4,8 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o saa7134-y += saa7134-video.o saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa7134-go7007.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o +obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o -- cgit v1.2.3 From 23ea6ec0785e25600e6bc33332cc5bc255caf91c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 07:54:09 -0300 Subject: [media] saa7134: Remove some casting warnings drivers/media/pci/saa7134/saa7134-go7007.c:247:17: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:247:17: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:247:17: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:252:17: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:252:17: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:252:17: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:299:9: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:299:9: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:299:9: got restricted __le32 [usertype] drivers/media/pci/saa7134/saa7134-go7007.c:300:9: warning: incorrect type in argument 1 (different base types) drivers/media/pci/saa7134/saa7134-go7007.c:300:9: expected unsigned int [unsigned] val drivers/media/pci/saa7134/saa7134-go7007.c:300:9: got restricted __le32 [usertype] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-go7007.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 3e9ca4821b8c..3ac987fb7606 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -244,12 +244,12 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, dma_sync_single_for_cpu(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE); go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma); } else { dma_sync_single_for_cpu(&dev->pci->dev, saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); go7007_parse_video_stream(go, saa->top, PAGE_SIZE); - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); + saa_writel(SAA7134_RS_BA1(5), saa->top_dma); } } @@ -296,8 +296,8 @@ static int saa7134_go7007_stream_start(struct go7007 *go) /* Enable video streaming mode */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); - saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma)); - saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma)); + saa_writel(SAA7134_RS_BA1(5), saa->top_dma); + saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma); saa_writel(SAA7134_RS_PITCH(5), 128); saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX); -- cgit v1.2.3 From 8eb988f1be98e13d33c786ad1511f9870d3038fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 07:58:00 -0300 Subject: [media] saa7134: Remove unused status var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/pci/saa7134/saa7134-go7007.c: In function ‘saa7134_go7007_interface_reset’: drivers/media/pci/saa7134/saa7134-go7007.c:147:6: warning: variable ‘status’ set but not used [-Wunused-but-set-variable] Signed-off-by: Mauro Carvalho Chehab Acked-by: Hans Verkuil --- drivers/media/pci/saa7134/saa7134-go7007.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 3ac987fb7606..54e650b4dff1 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -144,7 +144,6 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) { struct saa7134_go7007 *saa = go->hpi_context; struct saa7134_dev *dev = saa->dev; - u32 status; u16 intr_val, intr_data; int count = 20; @@ -162,8 +161,8 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - status = saa_readb(SAA7134_GPIO_GPSTATUS2); - /*pr_debug("status is %s\n", status & 0x40 ? "OK" : "not OK"); */ + saa_readb(SAA7134_GPIO_GPSTATUS2); + /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */ /* enter command mode...(?) */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1); @@ -172,7 +171,7 @@ static int saa7134_go7007_interface_reset(struct go7007 *go) do { saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - status = saa_readb(SAA7134_GPIO_GPSTATUS2); + saa_readb(SAA7134_GPIO_GPSTATUS2); /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */ } while (--count > 0); -- cgit v1.2.3 From f5a98f37a535a43b3a27c6a63b07f23d248e4b31 Mon Sep 17 00:00:00 2001 From: Akihiro Tsukada Date: Mon, 8 Sep 2014 14:20:43 -0300 Subject: [media] pt3: add support for Earthsoft PT3 ISDB-S/T receiver card This patch adds support for PT3 PCIe cards. PT3 has an FPGA PCIe bridge chip, a TC90522 demod chip and a VA4M6JC2103 tuner module which contains two QM1D1C0042 chips for ISDB-S and two MxL301RF's for ISDB-T. It can receive and deliver 4 (2x ISDB-S, 2x ISDB-T) streams simultaneously, and a kthread is used per stream to poll incoming data, because PT3 does not have interrupts. As an antenna input for each delivery system is split in the tuner module and shared between the corresponding two tuner chips, LNB/LNA controls that the FPGA chip provides are (naturally) shared as well. The tuner chips also share the power line in the tuner module, which is controlled on/off by a GPIO pin of the demod chip. As with the demod chip and the ISDB-T tuner chip, the init sequences/register settings for those chips are not disclosed and stored in a private memory of the FPGA, PT3 driver executes the init of those chips on behalf of their drivers. Signed-off-by: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Kconfig | 1 + drivers/media/pci/Makefile | 1 + drivers/media/pci/pt3/Kconfig | 10 + drivers/media/pci/pt3/Makefile | 8 + drivers/media/pci/pt3/pt3.c | 877 ++++++++++++++++++++++++++++++++++++++++ drivers/media/pci/pt3/pt3.h | 186 +++++++++ drivers/media/pci/pt3/pt3_dma.c | 225 +++++++++++ drivers/media/pci/pt3/pt3_i2c.c | 240 +++++++++++ 8 files changed, 1548 insertions(+) create mode 100644 drivers/media/pci/pt3/Kconfig create mode 100644 drivers/media/pci/pt3/Makefile create mode 100644 drivers/media/pci/pt3/pt3.c create mode 100644 drivers/media/pci/pt3/pt3.h create mode 100644 drivers/media/pci/pt3/pt3_dma.c create mode 100644 drivers/media/pci/pt3/pt3_i2c.c (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 933280740176..f8cec8e8cf82 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -42,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig" source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/dm1105/Kconfig" source "drivers/media/pci/pt1/Kconfig" +source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/mantis/Kconfig" source "drivers/media/pci/ngene/Kconfig" source "drivers/media/pci/ddbridge/Kconfig" diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 73d9c0f11127..a12926e4b51f 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -7,6 +7,7 @@ obj-y += ttpci/ \ pluto2/ \ dm1105/ \ pt1/ \ + pt3/ \ mantis/ \ ngene/ \ ddbridge/ \ diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig new file mode 100644 index 000000000000..16c208ae0079 --- /dev/null +++ b/drivers/media/pci/pt3/Kconfig @@ -0,0 +1,10 @@ +config DVB_PT3 + tristate "Earthsoft PT3 cards" + depends on DVB_CORE && PCI && I2C + select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT + help + Support for Earthsoft PT3 PCIe cards. + + Say Y or M if you own such a device and want to use it. diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile new file mode 100644 index 000000000000..396f146b1c18 --- /dev/null +++ b/drivers/media/pci/pt3/Makefile @@ -0,0 +1,8 @@ + +earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o + +obj-$(CONFIG_DVB_PT3) += earth-pt3.o + +ccflags-y += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-frontends +ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c new file mode 100644 index 000000000000..206ede0719b0 --- /dev/null +++ b/drivers/media/pci/pt3/pt3.c @@ -0,0 +1,877 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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 version 2. + * + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "pt3.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static bool one_adapter; +module_param(one_adapter, bool, 0444); +MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter."); + +static int num_bufs = 4; +module_param(num_bufs, int, 0444); +MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE."); + + +static const struct i2c_algorithm pt3_i2c_algo = { + .master_xfer = &pt3_i2c_master_xfer, + .functionality = &pt3_i2c_functionality, +}; + +static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = { + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11), + }, + .tuner_info = { + I2C_BOARD_INFO("qm1d1c0042", 0x63), + }, + .tuner_cfg.qm1d1c0042 = { + .lpf = 1, + }, + .init_freq = 1049480 - 300, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10), + }, + .tuner_info = { + I2C_BOARD_INFO("mxl301rf", 0x62), + }, + .init_freq = 515142857, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13), + }, + .tuner_info = { + I2C_BOARD_INFO("qm1d1c0042", 0x60), + }, + .tuner_cfg.qm1d1c0042 = { + .lpf = 1, + }, + .init_freq = 1049480 + 300, + }, + { + .demod_info = { + I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12), + }, + .tuner_info = { + I2C_BOARD_INFO("mxl301rf", 0x61), + }, + .init_freq = 521142857, + }, +}; + + +struct reg_val { + u8 reg; + u8 val; +}; + +static int +pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num) +{ + struct i2c_msg msg; + int i, ret; + + ret = 0; + msg.addr = adap->i2c_demod->addr; + msg.flags = 0; + msg.len = 2; + for (i = 0; i < num; i++) { + msg.buf = (u8 *)&data[i]; + ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1); + if (ret == 0) + ret = -EREMOTE; + if (ret < 0) + return ret; + } + return 0; +} + +static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on) +{ + iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W); +} + +static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe) +{ + struct pt3_board *pt3; + int i; + + if (one_adapter) { + pt3 = fe->dvb->priv; + for (i = 0; i < PT3_NUM_FE; i++) + if (pt3->adaps[i]->fe == fe) + return pt3->adaps[i]; + } + return container_of(fe->dvb, struct pt3_adapter, dvb_adap); +} + +/* + * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103). + * it seems that they share the power lines and Amp power line and + * adaps[3] controls those powers. + */ +static int +pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on) +{ + struct reg_val rv = { 0x1e, 0x99 }; + + if (tuner_on) + rv.val |= 0x40; + if (amp_on) + rv.val |= 0x04; + return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1); +} + +static int pt3_set_lna(struct dvb_frontend *fe) +{ + struct pt3_adapter *adap; + struct pt3_board *pt3; + u32 val; + int ret; + + /* LNA is shared btw. 2 TERR-tuners */ + + adap = pt3_find_adapter(fe); + val = fe->dtv_property_cache.lna; + if (val == LNA_AUTO || val == adap->cur_lna) + return 0; + + pt3 = adap->dvb_adap.priv; + if (mutex_lock_interruptible(&pt3->lock)) + return -ERESTARTSYS; + if (val) + pt3->lna_on_cnt++; + else + pt3->lna_on_cnt--; + + if (val && pt3->lna_on_cnt <= 1) { + pt3->lna_on_cnt = 1; + ret = pt3_set_tuner_power(pt3, true, true); + } else if (!val && pt3->lna_on_cnt <= 0) { + pt3->lna_on_cnt = 0; + ret = pt3_set_tuner_power(pt3, true, false); + } else + ret = 0; + mutex_unlock(&pt3->lock); + adap->cur_lna = (val != 0); + return ret; +} + +static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +{ + struct pt3_adapter *adap; + struct pt3_board *pt3; + bool on; + + /* LNB power is shared btw. 2 SAT-tuners */ + + adap = pt3_find_adapter(fe); + on = (volt != SEC_VOLTAGE_OFF); + if (on == adap->cur_lnb) + return 0; + adap->cur_lnb = on; + pt3 = adap->dvb_adap.priv; + if (mutex_lock_interruptible(&pt3->lock)) + return -ERESTARTSYS; + if (on) + pt3->lnb_on_cnt++; + else + pt3->lnb_on_cnt--; + + if (on && pt3->lnb_on_cnt <= 1) { + pt3->lnb_on_cnt = 1; + pt3_lnb_ctrl(pt3, true); + } else if (!on && pt3->lnb_on_cnt <= 0) { + pt3->lnb_on_cnt = 0; + pt3_lnb_ctrl(pt3, false); + } + mutex_unlock(&pt3->lock); + return 0; +} + +/* register values used in pt3_fe_init() */ + +static const struct reg_val init0_sat[] = { + { 0x03, 0x01 }, + { 0x1e, 0x10 }, +}; +static const struct reg_val init0_ter[] = { + { 0x01, 0x40 }, + { 0x1c, 0x10 }, +}; +static const struct reg_val cfg_sat[] = { + { 0x1c, 0x15 }, + { 0x1f, 0x04 }, +}; +static const struct reg_val cfg_ter[] = { + { 0x1d, 0x01 }, +}; + +/* + * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once. + * + * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF), + * the i2c sequences for init'ing them are not public and hidden in a ROM, + * and include the board specific configurations as well. + * They are stored in a lump and cannot be taken out / accessed separately, + * thus cannot be moved to the FE/tuner driver. + */ +static int pt3_fe_init(struct pt3_board *pt3) +{ + int i, ret; + struct dvb_frontend *fe; + + pt3_i2c_reset(pt3); + ret = pt3_init_all_demods(pt3); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to init demod chips."); + return ret; + } + + /* additional config? */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = pt3_demod_write(pt3->adaps[i], + init0_sat, ARRAY_SIZE(init0_sat)); + else + ret = pt3_demod_write(pt3->adaps[i], + init0_ter, ARRAY_SIZE(init0_ter)); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "demod[%d] faild in init sequence0.", i); + return ret; + } + ret = fe->ops.init(fe); + if (ret < 0) + return ret; + } + + usleep_range(2000, 4000); + ret = pt3_set_tuner_power(pt3, true, false); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to control tuner module."); + return ret; + } + + /* output pin configuration */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = pt3_demod_write(pt3->adaps[i], + cfg_sat, ARRAY_SIZE(cfg_sat)); + else + ret = pt3_demod_write(pt3->adaps[i], + cfg_ter, ARRAY_SIZE(cfg_ter)); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "demod[%d] faild in init sequence1.", i); + return ret; + } + } + usleep_range(4000, 6000); + + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.delsys[0] != SYS_ISDBS) + continue; + /* init and wake-up ISDB-S tuners */ + ret = fe->ops.tuner_ops.init(fe); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "Failed to init SAT-tuner[%d].", i); + return ret; + } + } + ret = pt3_init_all_mxl301rf(pt3); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners."); + return ret; + } + + ret = pt3_set_tuner_power(pt3, true, true); + if (ret < 0) { + dev_warn(&pt3->pdev->dev, "Failed to control tuner module."); + return ret; + } + + /* Wake up all tuners and make an initial tuning, + * in order to avoid interference among the tuners in the module, + * according to the doc from the manufacturer. + */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + ret = 0; + if (fe->ops.delsys[0] == SYS_ISDBT) + ret = fe->ops.tuner_ops.init(fe); + /* set only when called from pt3_probe(), not resume() */ + if (ret == 0 && fe->dtv_property_cache.frequency == 0) { + fe->dtv_property_cache.frequency = + adap_conf[i].init_freq; + ret = fe->ops.tuner_ops.set_params(fe); + } + if (ret < 0) { + dev_warn(&pt3->pdev->dev, + "Failed in initial tuning of tuner[%d].", i); + return ret; + } + } + + /* and sleep again, waiting to be opened by users. */ + for (i = 0; i < PT3_NUM_FE; i++) { + fe = pt3->adaps[i]->fe; + if (fe->ops.tuner_ops.sleep) + ret = fe->ops.tuner_ops.sleep(fe); + if (ret < 0) + break; + if (fe->ops.sleep) + ret = fe->ops.sleep(fe); + if (ret < 0) + break; + if (fe->ops.delsys[0] == SYS_ISDBS) + fe->ops.set_voltage = &pt3_set_voltage; + else + fe->ops.set_lna = &pt3_set_lna; + } + if (i < PT3_NUM_FE) { + dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i); + return ret; + } + return 0; +} + + +static int pt3_attach_fe(struct pt3_board *pt3, int i) +{ + struct i2c_board_info info; + struct tc90522_config cfg; + struct i2c_client *cl; + struct dvb_adapter *dvb_adap; + int ret; + + info = adap_conf[i].demod_info; + cfg = adap_conf[i].demod_cfg; + cfg.tuner_i2c = NULL; + info.platform_data = &cfg; + + ret = -ENODEV; + request_module("tc90522"); + cl = i2c_new_device(&pt3->i2c_adap, &info); + if (!cl || !cl->dev.driver) + return -ENODEV; + pt3->adaps[i]->i2c_demod = cl; + if (!try_module_get(cl->dev.driver->owner)) + goto err_demod; + + if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) { + struct qm1d1c0042_config tcfg; + + tcfg = adap_conf[i].tuner_cfg.qm1d1c0042; + tcfg.fe = cfg.fe; + info = adap_conf[i].tuner_info; + info.platform_data = &tcfg; + request_module("qm1d1c0042"); + cl = i2c_new_device(cfg.tuner_i2c, &info); + } else { + struct mxl301rf_config tcfg; + + tcfg = adap_conf[i].tuner_cfg.mxl301rf; + tcfg.fe = cfg.fe; + info = adap_conf[i].tuner_info; + info.platform_data = &tcfg; + request_module("mxl301rf"); + cl = i2c_new_device(cfg.tuner_i2c, &info); + } + if (!cl || !cl->dev.driver) + goto err_demod; + pt3->adaps[i]->i2c_tuner = cl; + if (!try_module_get(cl->dev.driver->owner)) + goto err_tuner; + + dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; + ret = dvb_register_frontend(dvb_adap, cfg.fe); + if (ret < 0) + goto err_tuner; + pt3->adaps[i]->fe = cfg.fe; + return 0; + +err_tuner: + i2c_unregister_device(pt3->adaps[i]->i2c_tuner); + if (pt3->adaps[i]->i2c_tuner->dev.driver->owner && + module_is_live(pt3->adaps[i]->i2c_tuner->dev.driver->owner)) + module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); +err_demod: + i2c_unregister_device(pt3->adaps[i]->i2c_demod); + if (pt3->adaps[i]->i2c_demod->dev.driver->owner && + module_is_live(pt3->adaps[i]->i2c_demod->dev.driver->owner)) + module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); + return ret; +} + + +static int pt3_fetch_thread(void *data) +{ + struct pt3_adapter *adap = data; + ktime_t delay; + bool was_frozen; + +#define PT3_INITIAL_BUF_DROPS 4 +#define PT3_FETCH_DELAY 10 +#define PT3_FETCH_DELAY_DELTA 2 + + pt3_init_dmabuf(adap); + adap->num_discard = PT3_INITIAL_BUF_DROPS; + + dev_dbg(adap->dvb_adap.device, + "PT3: [%s] started.\n", adap->thread->comm); + set_freezable(); + while (!kthread_freezable_should_stop(&was_frozen)) { + if (was_frozen) + adap->num_discard = PT3_INITIAL_BUF_DROPS; + + pt3_proc_dma(adap); + + delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC); + set_current_state(TASK_UNINTERRUPTIBLE); + freezable_schedule_hrtimeout_range(&delay, + PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC, + HRTIMER_MODE_REL); + } + dev_dbg(adap->dvb_adap.device, + "PT3: [%s] exited.\n", adap->thread->comm); + adap->thread = NULL; + return 0; +} + +static int pt3_start_streaming(struct pt3_adapter *adap) +{ + struct task_struct *thread; + + /* start fetching thread */ + thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i", + adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + if (IS_ERR(thread)) { + int ret = PTR_ERR(thread); + + dev_warn(adap->dvb_adap.device, + "PT3 (adap:%d, dmx:%d): failed to start kthread.\n", + adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + return ret; + } + adap->thread = thread; + + return pt3_start_dma(adap); +} + +static int pt3_stop_streaming(struct pt3_adapter *adap) +{ + int ret; + + ret = pt3_stop_dma(adap); + if (ret) + dev_warn(adap->dvb_adap.device, + "PT3: failed to stop streaming of adap:%d/FE:%d\n", + adap->dvb_adap.num, adap->fe->id); + + /* kill the fetching thread */ + ret = kthread_stop(adap->thread); + return ret; +} + +static int pt3_start_feed(struct dvb_demux_feed *feed) +{ + struct pt3_adapter *adap; + + if (signal_pending(current)) + return -EINTR; + + adap = container_of(feed->demux, struct pt3_adapter, demux); + adap->num_feeds++; + if (adap->thread) + return 0; + if (adap->num_feeds != 1) { + dev_warn(adap->dvb_adap.device, + "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n", + __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id); + adap->num_feeds = 1; + } + + return pt3_start_streaming(adap); + +} + +static int pt3_stop_feed(struct dvb_demux_feed *feed) +{ + struct pt3_adapter *adap; + + adap = container_of(feed->demux, struct pt3_adapter, demux); + + adap->num_feeds--; + if (adap->num_feeds > 0 || !adap->thread) + return 0; + adap->num_feeds = 0; + + return pt3_stop_streaming(adap); +} + + +static int pt3_alloc_adapter(struct pt3_board *pt3, int index) +{ + int ret; + struct pt3_adapter *adap; + struct dvb_adapter *da; + + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) { + dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n"); + return -ENOMEM; + } + pt3->adaps[index] = adap; + adap->adap_idx = index; + + if (index == 0 || !one_adapter) { + ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB", + THIS_MODULE, &pt3->pdev->dev, adapter_nr); + if (ret < 0) { + dev_err(&pt3->pdev->dev, + "failed to register adapter dev.\n"); + goto err_mem; + } + da = &adap->dvb_adap; + } else + da = &pt3->adaps[0]->dvb_adap; + + adap->dvb_adap.priv = pt3; + adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + adap->demux.priv = adap; + adap->demux.feednum = 256; + adap->demux.filternum = 256; + adap->demux.start_feed = pt3_start_feed; + adap->demux.stop_feed = pt3_stop_feed; + ret = dvb_dmx_init(&adap->demux); + if (ret < 0) { + dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n"); + goto err_adap; + } + + adap->dmxdev.filternum = 256; + adap->dmxdev.demux = &adap->demux.dmx; + ret = dvb_dmxdev_init(&adap->dmxdev, da); + if (ret < 0) { + dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n"); + goto err_demux; + } + + ret = pt3_alloc_dmabuf(adap); + if (ret) { + dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n"); + goto err_dmabuf; + } + + return 0; + +err_dmabuf: + pt3_free_dmabuf(adap); + dvb_dmxdev_release(&adap->dmxdev); +err_demux: + dvb_dmx_release(&adap->demux); +err_adap: + if (index == 0 || !one_adapter) + dvb_unregister_adapter(da); +err_mem: + kfree(adap); + pt3->adaps[index] = NULL; + return ret; +} + +static void pt3_cleanup_adapter(struct pt3_board *pt3, int index) +{ + struct pt3_adapter *adap; + struct dmx_demux *dmx; + + adap = pt3->adaps[index]; + if (adap == NULL) + return; + + /* stop demux kthread */ + if (adap->thread) + pt3_stop_streaming(adap); + + dmx = &adap->demux.dmx; + dmx->close(dmx); + if (adap->fe) { + adap->fe->callback = NULL; + if (adap->fe->frontend_priv) + dvb_unregister_frontend(adap->fe); + if (adap->i2c_tuner) { + module_put(adap->i2c_tuner->dev.driver->owner); + i2c_unregister_device(adap->i2c_tuner); + } + if (adap->i2c_demod) { + module_put(adap->i2c_demod->dev.driver->owner); + i2c_unregister_device(adap->i2c_demod); + } + } + pt3_free_dmabuf(adap); + dvb_dmxdev_release(&adap->dmxdev); + dvb_dmx_release(&adap->demux); + if (index == 0 || !one_adapter) + dvb_unregister_adapter(&adap->dvb_adap); + kfree(adap); + pt3->adaps[index] = NULL; +} + +#ifdef CONFIG_PM_SLEEP + +static int pt3_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pt3_board *pt3 = pci_get_drvdata(pdev); + int i; + struct pt3_adapter *adap; + + for (i = 0; i < PT3_NUM_FE; i++) { + adap = pt3->adaps[i]; + if (adap->num_feeds > 0) + pt3_stop_dma(adap); + dvb_frontend_suspend(adap->fe); + pt3_free_dmabuf(adap); + } + + pt3_lnb_ctrl(pt3, false); + pt3_set_tuner_power(pt3, false, false); + return 0; +} + +static int pt3_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pt3_board *pt3 = pci_get_drvdata(pdev); + int i, ret; + struct pt3_adapter *adap; + + ret = pt3_fe_init(pt3); + if (ret) + return ret; + + if (pt3->lna_on_cnt > 0) + pt3_set_tuner_power(pt3, true, true); + if (pt3->lnb_on_cnt > 0) + pt3_lnb_ctrl(pt3, true); + + for (i = 0; i < PT3_NUM_FE; i++) { + adap = pt3->adaps[i]; + dvb_frontend_resume(adap->fe); + ret = pt3_alloc_dmabuf(adap); + if (ret) { + dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n"); + continue; + } + if (adap->num_feeds > 0) + pt3_start_dma(adap); + } + + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + + +static void pt3_remove(struct pci_dev *pdev) +{ + struct pt3_board *pt3; + int i; + + pt3 = pci_get_drvdata(pdev); + for (i = PT3_NUM_FE - 1; i >= 0; i--) + pt3_cleanup_adapter(pt3, i); + i2c_del_adapter(&pt3->i2c_adap); + kfree(pt3->i2c_buf); + pci_iounmap(pt3->pdev, pt3->regs[0]); + pci_iounmap(pt3->pdev, pt3->regs[1]); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(pt3); +} + +static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 rev; + u32 ver; + int i, ret; + struct pt3_board *pt3; + struct i2c_adapter *i2c; + + if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1) + return -ENODEV; + + ret = pci_enable_device(pdev); + if (ret < 0) + return -ENODEV; + pci_set_master(pdev); + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret < 0) + goto err_disable_device; + + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + if (ret == 0) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + else { + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret == 0) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + else { + dev_err(&pdev->dev, "Failed to set DMA mask.\n"); + goto err_release_regions; + } + dev_info(&pdev->dev, "Use 32bit DMA.\n"); + } + + pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL); + if (!pt3) { + dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n"); + ret = -ENOMEM; + goto err_release_regions; + } + pci_set_drvdata(pdev, pt3); + pt3->pdev = pdev; + mutex_init(&pt3->lock); + pt3->regs[0] = pci_ioremap_bar(pdev, 0); + pt3->regs[1] = pci_ioremap_bar(pdev, 2); + if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) { + dev_err(&pdev->dev, "Failed to ioremap.\n"); + ret = -ENOMEM; + goto err_kfree; + } + + ver = ioread32(pt3->regs[0] + REG_VERSION); + if ((ver >> 16) != 0x0301) { + dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported", + ver >> 24, (ver & 0x00ff0000) >> 16); + ret = -ENODEV; + goto err_iounmap; + } + + pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS); + + pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL); + if (pt3->i2c_buf == NULL) { + dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n"); + ret = -ENOMEM; + goto err_iounmap; + } + i2c = &pt3->i2c_adap; + i2c->owner = THIS_MODULE; + i2c->algo = &pt3_i2c_algo; + i2c->algo_data = NULL; + i2c->dev.parent = &pdev->dev; + strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name)); + i2c_set_adapdata(i2c, pt3); + ret = i2c_add_adapter(i2c); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to add i2c adapter.\n"); + goto err_i2cbuf; + } + + for (i = 0; i < PT3_NUM_FE; i++) { + ret = pt3_alloc_adapter(pt3, i); + if (ret < 0) + break; + + ret = pt3_attach_fe(pt3, i); + if (ret < 0) + break; + } + if (i < PT3_NUM_FE) { + dev_err(&pdev->dev, "Failed to create FE%d.\n", i); + goto err_cleanup_adapters; + } + + ret = pt3_fe_init(pt3); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to init frontends.\n"); + i = PT3_NUM_FE - 1; + goto err_cleanup_adapters; + } + + dev_info(&pdev->dev, + "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n", + ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff); + return 0; + +err_cleanup_adapters: + while (i >= 0) + pt3_cleanup_adapter(pt3, i--); + i2c_del_adapter(i2c); +err_i2cbuf: + kfree(pt3->i2c_buf); +err_iounmap: + if (pt3->regs[0]) + pci_iounmap(pdev, pt3->regs[0]); + if (pt3->regs[1]) + pci_iounmap(pdev, pt3->regs[1]); +err_kfree: + kfree(pt3); +err_release_regions: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); + return ret; + +} + +static const struct pci_device_id pt3_id_table[] = { + { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) }, + { }, +}; +MODULE_DEVICE_TABLE(pci, pt3_id_table); + +SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); + +static struct pci_driver pt3_driver = { + .name = DRV_NAME, + .probe = pt3_probe, + .remove = pt3_remove, + .id_table = pt3_id_table, + + .driver.pm = &pt3_pm_ops, +}; + +module_pci_driver(pt3_driver); + +MODULE_DESCRIPTION("Earthsoft PT3 Driver"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h new file mode 100644 index 000000000000..1b3f2ad25db3 --- /dev/null +++ b/drivers/media/pci/pt3/pt3.h @@ -0,0 +1,186 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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 version 2. + * + * + * 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. + */ + +#ifndef PT3_H +#define PT3_H + +#include +#include + +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dmxdev.h" + +#include "tc90522.h" +#include "mxl301rf.h" +#include "qm1d1c0042.h" + +#define DRV_NAME KBUILD_MODNAME + +#define PT3_NUM_FE 4 + +/* + * register index of the FPGA chip + */ +#define REG_VERSION 0x00 +#define REG_BUS 0x04 +#define REG_SYSTEM_W 0x08 +#define REG_SYSTEM_R 0x0c +#define REG_I2C_W 0x10 +#define REG_I2C_R 0x14 +#define REG_RAM_W 0x18 +#define REG_RAM_R 0x1c +#define REG_DMA_BASE 0x40 /* regs for FE[i] = REG_DMA_BASE + 0x18 * i */ +#define OFST_DMA_DESC_L 0x00 +#define OFST_DMA_DESC_H 0x04 +#define OFST_DMA_CTL 0x08 +#define OFST_TS_CTL 0x0c +#define OFST_STATUS 0x10 +#define OFST_TS_ERR 0x14 + +/* + * internal buffer for I2C + */ +#define PT3_I2C_MAX 4091 +struct pt3_i2cbuf { + u8 data[PT3_I2C_MAX]; + u8 tmp; + u32 num_cmds; +}; + +/* + * DMA things + */ +#define TS_PACKET_SZ 188 +/* DMA transfers must not cross 4GiB, so use one page / transfer */ +#define DATA_XFER_SZ 4096 +#define DATA_BUF_XFERS 47 +/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */ +#define DATA_BUF_SZ (DATA_BUF_XFERS * DATA_XFER_SZ) +#define MAX_DATA_BUFS 16 +#define MIN_DATA_BUFS 2 + +#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc)) +#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS) +#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE) + +/* DMA transfer description. + * device is passed a pointer to this struct, dma-reads it, + * and gets the DMA buffer ring for storing TS data. + */ +struct xfer_desc { + u32 addr_l; /* bus address of target data buffer */ + u32 addr_h; + u32 size; + u32 next_l; /* bus adddress of the next xfer_desc */ + u32 next_h; +}; + +/* A DMA mapping of a page containing xfer_desc's */ +struct xfer_desc_buffer { + dma_addr_t b_addr; + struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */ +}; + +/* A DMA mapping of a data buffer */ +struct dma_data_buffer { + dma_addr_t b_addr; + u8 *data; /* size: u8[PAGE_SIZE] */ +}; + +/* + * device things + */ +struct pt3_adap_config { + struct i2c_board_info demod_info; + struct tc90522_config demod_cfg; + + struct i2c_board_info tuner_info; + union tuner_config { + struct qm1d1c0042_config qm1d1c0042; + struct mxl301rf_config mxl301rf; + } tuner_cfg; + u32 init_freq; +}; + +struct pt3_adapter { + struct dvb_adapter dvb_adap; /* dvb_adap.priv => struct pt3_board */ + int adap_idx; + + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend *fe; + struct i2c_client *i2c_demod; + struct i2c_client *i2c_tuner; + + /* data fetch thread */ + struct task_struct *thread; + int num_feeds; + + bool cur_lna; + bool cur_lnb; /* current LNB power status (on/off) */ + + /* items below are for DMA */ + struct dma_data_buffer buffer[MAX_DATA_BUFS]; + int buf_idx; + int buf_ofs; + int num_bufs; /* == pt3_board->num_bufs */ + int num_discard; /* how many access units to discard initially */ + + struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS]; + int num_desc_bufs; /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */ +}; + + +struct pt3_board { + struct pci_dev *pdev; + void __iomem *regs[2]; + /* regs[0]: registers, regs[1]: internal memory, used for I2C */ + + struct mutex lock; + + /* LNB power shared among sat-FEs */ + int lnb_on_cnt; /* LNB power on count */ + + /* LNA shared among terr-FEs */ + int lna_on_cnt; /* booster enabled count */ + + int num_bufs; /* number of DMA buffers allocated/mapped per FE */ + + struct i2c_adapter i2c_adap; + struct pt3_i2cbuf *i2c_buf; + + struct pt3_adapter *adaps[PT3_NUM_FE]; +}; + + +/* + * prototypes + */ +extern int pt3_alloc_dmabuf(struct pt3_adapter *adap); +extern void pt3_init_dmabuf(struct pt3_adapter *adap); +extern void pt3_free_dmabuf(struct pt3_adapter *adap); +extern int pt3_start_dma(struct pt3_adapter *adap); +extern int pt3_stop_dma(struct pt3_adapter *adap); +extern int pt3_proc_dma(struct pt3_adapter *adap); + +extern int pt3_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num); +extern u32 pt3_i2c_functionality(struct i2c_adapter *adap); +extern void pt3_i2c_reset(struct pt3_board *pt3); +extern int pt3_init_all_demods(struct pt3_board *pt3); +extern int pt3_init_all_mxl301rf(struct pt3_board *pt3); +#endif /* PT3_H */ diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c new file mode 100644 index 000000000000..f0ce90437fac --- /dev/null +++ b/drivers/media/pci/pt3/pt3_dma.c @@ -0,0 +1,225 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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 version 2. + * + * + * 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. + */ +#include +#include +#include + +#include "pt3.h" + +#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128) +#define PT3_BUF_CANARY (0x74) + +static u32 get_dma_base(int idx) +{ + int i; + + i = (idx == 1 || idx == 2) ? 3 - idx : idx; + return REG_DMA_BASE + 0x18 * i; +} + +int pt3_stop_dma(struct pt3_adapter *adap) +{ + struct pt3_board *pt3 = adap->dvb_adap.priv; + u32 base; + u32 stat; + int retry; + + base = get_dma_base(adap->adap_idx); + stat = ioread32(pt3->regs[0] + base + OFST_STATUS); + if (!(stat & 0x01)) + return 0; + + iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); + for (retry = 0; retry < 5; retry++) { + stat = ioread32(pt3->regs[0] + base + OFST_STATUS); + if (!(stat & 0x01)) + return 0; + msleep(50); + } + return -EIO; +} + +int pt3_start_dma(struct pt3_adapter *adap) +{ + struct pt3_board *pt3 = adap->dvb_adap.priv; + u32 base = get_dma_base(adap->adap_idx); + + iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL); + iowrite32(lower_32_bits(adap->desc_buf[0].b_addr), + pt3->regs[0] + base + OFST_DMA_DESC_L); + iowrite32(upper_32_bits(adap->desc_buf[0].b_addr), + pt3->regs[0] + base + OFST_DMA_DESC_H); + iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL); + return 0; +} + + +static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs) +{ + *ofs += PT3_ACCESS_UNIT; + if (*ofs >= DATA_BUF_SZ) { + *ofs -= DATA_BUF_SZ; + (*idx)++; + if (*idx == adap->num_bufs) + *idx = 0; + } + return &adap->buffer[*idx].data[*ofs]; +} + +int pt3_proc_dma(struct pt3_adapter *adap) +{ + int idx, ofs; + + idx = adap->buf_idx; + ofs = adap->buf_ofs; + + if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY) + return 0; + + while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) { + u8 *p; + + p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs]; + if (adap->num_discard > 0) + adap->num_discard--; + else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) { + dvb_dmx_swfilter_packets(&adap->demux, p, + (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ); + dvb_dmx_swfilter_packets(&adap->demux, + adap->buffer[idx].data, ofs / TS_PACKET_SZ); + } else + dvb_dmx_swfilter_packets(&adap->demux, p, + PT3_ACCESS_UNIT / TS_PACKET_SZ); + + *p = PT3_BUF_CANARY; + adap->buf_idx = idx; + adap->buf_ofs = ofs; + } + return 0; +} + +void pt3_init_dmabuf(struct pt3_adapter *adap) +{ + int idx, ofs; + u8 *p; + + idx = 0; + ofs = 0; + p = adap->buffer[0].data; + /* mark the whole buffers as "not written yet" */ + while (idx < adap->num_bufs) { + p[ofs] = PT3_BUF_CANARY; + ofs += PT3_ACCESS_UNIT; + if (ofs >= DATA_BUF_SZ) { + ofs -= DATA_BUF_SZ; + idx++; + p = adap->buffer[idx].data; + } + } + adap->buf_idx = 0; + adap->buf_ofs = 0; +} + +void pt3_free_dmabuf(struct pt3_adapter *adap) +{ + struct pt3_board *pt3; + int i; + + pt3 = adap->dvb_adap.priv; + for (i = 0; i < adap->num_bufs; i++) + dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ, + adap->buffer[i].data, adap->buffer[i].b_addr); + adap->num_bufs = 0; + + for (i = 0; i < adap->num_desc_bufs; i++) + dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE, + adap->desc_buf[i].descs, adap->desc_buf[i].b_addr); + adap->num_desc_bufs = 0; +} + + +int pt3_alloc_dmabuf(struct pt3_adapter *adap) +{ + struct pt3_board *pt3; + void *p; + int i, j; + int idx, ofs; + int num_desc_bufs; + dma_addr_t data_addr, desc_addr; + struct xfer_desc *d; + + pt3 = adap->dvb_adap.priv; + adap->num_bufs = 0; + adap->num_desc_bufs = 0; + for (i = 0; i < pt3->num_bufs; i++) { + p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ, + &adap->buffer[i].b_addr, GFP_KERNEL); + if (p == NULL) + goto failed; + adap->buffer[i].data = p; + adap->num_bufs++; + } + pt3_init_dmabuf(adap); + + /* build circular-linked pointers (xfer_desc) to the data buffers*/ + idx = 0; + ofs = 0; + num_desc_bufs = + DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE); + for (i = 0; i < num_desc_bufs; i++) { + p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE, + &desc_addr, GFP_KERNEL); + if (p == NULL) + goto failed; + adap->num_desc_bufs++; + adap->desc_buf[i].descs = p; + adap->desc_buf[i].b_addr = desc_addr; + + if (i > 0) { + d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1]; + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + } + for (j = 0; j < DESCS_IN_PAGE; j++) { + data_addr = adap->buffer[idx].b_addr + ofs; + d = &adap->desc_buf[i].descs[j]; + d->addr_l = lower_32_bits(data_addr); + d->addr_h = upper_32_bits(data_addr); + d->size = DATA_XFER_SZ; + + desc_addr += sizeof(struct xfer_desc); + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + + ofs += DATA_XFER_SZ; + if (ofs >= DATA_BUF_SZ) { + ofs -= DATA_BUF_SZ; + idx++; + if (idx >= adap->num_bufs) { + desc_addr = adap->desc_buf[0].b_addr; + d->next_l = lower_32_bits(desc_addr); + d->next_h = upper_32_bits(desc_addr); + return 0; + } + } + } + } + return 0; + +failed: + pt3_free_dmabuf(adap); + return -ENOMEM; +} diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c new file mode 100644 index 000000000000..ec6a8a2e4744 --- /dev/null +++ b/drivers/media/pci/pt3/pt3_i2c.c @@ -0,0 +1,240 @@ +/* + * Earthsoft PT3 driver + * + * Copyright (C) 2014 Akihiro Tsukada + * + * 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 version 2. + * + * + * 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. + */ +#include +#include +#include +#include +#include + +#include "pt3.h" + +#define PT3_I2C_BASE 2048 +#define PT3_CMD_ADDR_NORMAL 0 +#define PT3_CMD_ADDR_INIT_DEMOD 4096 +#define PT3_CMD_ADDR_INIT_TUNER (4096 + 2042) + +/* masks for I2C status register */ +#define STAT_SEQ_RUNNING 0x1 +#define STAT_SEQ_ERROR 0x6 +#define STAT_NO_SEQ 0x8 + +#define PT3_I2C_RUN (1 << 16) +#define PT3_I2C_RESET (1 << 17) + +enum ctl_cmd { + I_END, + I_ADDRESS, + I_CLOCK_L, + I_CLOCK_H, + I_DATA_L, + I_DATA_H, + I_RESET, + I_SLEEP, + I_DATA_L_NOP = 0x08, + I_DATA_H_NOP = 0x0c, + I_DATA_H_READ = 0x0d, + I_DATA_H_ACK0 = 0x0e, + I_DATA_H_ACK1 = 0x0f, +}; + + +static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd) +{ + int buf_idx; + + if ((cbuf->num_cmds % 2) == 0) + cbuf->tmp = cmd; + else { + cbuf->tmp |= cmd << 4; + buf_idx = cbuf->num_cmds / 2; + if (buf_idx < ARRAY_SIZE(cbuf->data)) + cbuf->data[buf_idx] = cbuf->tmp; + } + cbuf->num_cmds++; +} + +static void put_end(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_END); + if (cbuf->num_cmds % 2) + cmdbuf_add(cbuf, I_END); +} + +static void put_start(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_DATA_H); + cmdbuf_add(cbuf, I_CLOCK_H); + cmdbuf_add(cbuf, I_DATA_L); + cmdbuf_add(cbuf, I_CLOCK_L); +} + +static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val) +{ + u8 mask; + + mask = 0x80; + for (mask = 0x80; mask > 0; mask >>= 1) + cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP); + cmdbuf_add(cbuf, I_DATA_H_ACK0); +} + +static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size) +{ + int i, j; + + for (i = 0; i < size; i++) { + for (j = 0; j < 8; j++) + cmdbuf_add(cbuf, I_DATA_H_READ); + cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP); + } +} + +static void put_stop(struct pt3_i2cbuf *cbuf) +{ + cmdbuf_add(cbuf, I_DATA_L); + cmdbuf_add(cbuf, I_CLOCK_H); + cmdbuf_add(cbuf, I_DATA_H); +} + + +/* translates msgs to internal commands for bit-banging */ +static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num) +{ + int i, j; + bool rd; + + cbuf->num_cmds = 0; + for (i = 0; i < num; i++) { + rd = !!(msgs[i].flags & I2C_M_RD); + put_start(cbuf); + put_byte_write(cbuf, msgs[i].addr << 1 | rd); + if (rd) + put_byte_read(cbuf, msgs[i].len); + else + for (j = 0; j < msgs[i].len; j++) + put_byte_write(cbuf, msgs[i].buf[j]); + } + if (num > 0) { + put_stop(cbuf); + put_end(cbuf); + } +} + +static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait) +{ + int i; + u32 v; + + for (i = 0; i < max_wait; i++) { + v = ioread32(pt3->regs[0] + REG_I2C_R); + if (!(v & STAT_SEQ_RUNNING)) + break; + usleep_range(500, 750); + } + if (i >= max_wait) + return -EIO; + if (result) + *result = v; + return 0; +} + +/* send [pre-]translated i2c msgs stored at addr */ +static int send_i2c_cmd(struct pt3_board *pt3, u32 addr) +{ + u32 ret; + + /* make sure that previous transactions had finished */ + if (wait_i2c_result(pt3, NULL, 50)) { + dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n", + __func__); + return -EIO; + } + + iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W); + usleep_range(200, 300); + /* wait for the current transaction to finish */ + if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) { + dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__); + return -EIO; + } + return 0; +} + + +/* init commands for each demod are combined into one transaction + * and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD. + */ +int pt3_init_all_demods(struct pt3_board *pt3) +{ + ioread32(pt3->regs[0] + REG_I2C_R); + return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD); +} + +/* init commands for two ISDB-T tuners are hidden in ROM. */ +int pt3_init_all_mxl301rf(struct pt3_board *pt3) +{ + usleep_range(1000, 2000); + return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER); +} + +void pt3_i2c_reset(struct pt3_board *pt3) +{ + iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W); +} + +/* + * I2C algorithm + */ +int +pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct pt3_board *pt3; + struct pt3_i2cbuf *cbuf; + int i; + void __iomem *p; + + pt3 = i2c_get_adapdata(adap); + cbuf = pt3->i2c_buf; + + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RECV_LEN) { + dev_warn(&pt3->pdev->dev, + "(%s) I2C_M_RECV_LEN not supported.\n", + __func__); + return -EINVAL; + } + + translate(cbuf, msgs, num); + memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2, + cbuf->data, cbuf->num_cmds); + + if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0) + return -EIO; + + p = pt3->regs[1] + PT3_I2C_BASE; + for (i = 0; i < num; i++) + if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) { + memcpy_fromio(msgs[i].buf, p, msgs[i].len); + p += msgs[i].len; + } + + return num; +} + +u32 pt3_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} -- cgit v1.2.3 From 49310ed0ab8da344dece4a543bfcdd14490ccfa0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 23 Sep 2014 17:05:02 -0300 Subject: [media] pt3: make pt3_pm_ops() static drivers/media/pci/pt3/pt3.c:862:1: warning: symbol 'pt3_pm_ops' was not declared. Should it be static? Cc: Akihiro Tsukada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pt3/pt3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 206ede0719b0..90f86ce7a001 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -859,7 +859,7 @@ static const struct pci_device_id pt3_id_table[] = { }; MODULE_DEVICE_TABLE(pci, pt3_id_table); -SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); +static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume); static struct pci_driver pt3_driver = { .name = DRV_NAME, -- cgit v1.2.3 From b0b12e63f999c91690f3f95bd585cf7812a251d9 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:13 -0300 Subject: [media] cx23885: add i2c client handling into dvb_unregister and state Prepare cx23885 driver for handling I2C client that is needed for certain demodulators and tuners (for example Si2168 and Si2157). I2C client for tuner and demod stored in state and unregistering of the I2C devices added into dvb_unregister. Signed-off-by: Olli Salonen Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 23 ++++++++++++++++------- drivers/media/pci/cx23885/cx23885.h | 3 +++ 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 332e6facc095..3e72c95a1d59 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1688,15 +1688,24 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { struct vb2_dvb_frontend *fe0; + struct i2c_client *client; + + /* remove I2C client for tuner */ + client = port->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = port->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } - /* FIXME: in an error condition where the we have - * an expected number of frontends (attach problem) - * then this might not clean up correctly, if 1 - * is invalid. - * This comment only applies to future boards IF they - * implement MFE support. - */ fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + if (fe0 && fe0->dvb.frontend) vb2_dvb_unregister_bus(&port->frontends); diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 39a89855d1d5..458d180cf96d 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -293,6 +293,9 @@ struct cx23885_tsport { /* Workaround for a temp dvb_frontend that the tuner can attached to */ struct dvb_frontend analog_fe; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + int (*set_frontend)(struct dvb_frontend *fe); }; -- cgit v1.2.3 From 5cd3b6b40d3a08394a9e973c597a284153eac0b5 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:14 -0300 Subject: [media] cx23855: add frontend set voltage function into state Setting the LNB voltage requires setting some GPIOs on the cx23885 with some boards before calling the actual set_voltage function in the demod driver. Add a function pointer into state for that case. Signed-off-by: Olli Salonen Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 458d180cf96d..0d5888214fb6 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -297,6 +297,8 @@ struct cx23885_tsport { struct i2c_client *i2c_client_tuner; int (*set_frontend)(struct dvb_frontend *fe); + int (*fe_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); }; struct cx23885_kernel_ir { -- cgit v1.2.3 From 294422662215188ace50ae14318ac025a56843d8 Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Mon, 11 Aug 2014 16:58:15 -0300 Subject: [media] cx23855: add support for DVBSky T9580 DVB-C/T2/S2 tuner DVBSky T9580 is a dual tuner card with one DVB-T2/C tuner and one DVB-S2 tuner. It contains the following components: - PCIe bridge: Conexant CX23885 - Demod for terrestrial/cable: Silicon Labs Si2168-A30 - Tuner for terrestrial/cable: Silicon Labs Si2158-A20 - Demod for sat: Montage DS3103 - Tuner for sat: Montage TS2022 This patch depends on Max Nibble's patch for m88ds3103 (see patchwork 25312: https://patchwork.linuxtv.org/patch/25312/ ). 3 firmwares are needed: - Si2168-A30 demod and Si2158-A20 tuner: same as TechnoTrend CT2-4400, https://www.mail-archive.com/linux-media@vger.kernel.org/msg76944.html - Montage DS3103 demod: same as PCTV 461e, Antti has it on his LinuxTV project page: http://palosaari.fi/linux/v4l-dvb/firmware/M88DS3103/ IR receiver is not supported. Values in cx23885_gpio_setup, cx23885_card_setup and dvbsky_t9580_set_voltage as well as the EEPROM read function are taken from the manufacturer provided semi-open source driver. The drivers in question are Linux GPL'd media tree drivers for cx23885 modified by Max Nibble (nibble.max@gmail.com) with proprietary tuner/demod drivers. Max is aware of this patch and has approved my use of the values in this patch. Signed-off-by: Olli Salonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/Kconfig | 4 + drivers/media/pci/cx23885/cx23885-cards.c | 26 +++++ drivers/media/pci/cx23885/cx23885-dvb.c | 160 ++++++++++++++++++++++++++++++ drivers/media/pci/cx23885/cx23885.h | 1 + 4 files changed, 191 insertions(+) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index a883ea4968be..f613314b360b 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -31,12 +31,16 @@ config VIDEO_CX23885 select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 21e500b0a220..88c257d1161b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -675,6 +675,11 @@ struct cx23885_board cx23885_boards[] = { .amux = CX25840_AUDIO7, } }, }, + [CX23885_BOARD_DVBSKY_T9580] = { + .name = "DVBSky T9580", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -930,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdb98, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2, + }, { + .subvendor = 0x4254, + .subdevice = 0x9580, + .card = CX23885_BOARD_DVBSKY_T9580, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1524,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x00040004); mdelay(60); break; + case CX23885_BOARD_DVBSKY_T9580: + /* enable GPIO3-18 pins */ + cx_write(MC417_CTL, 0x00000037); + cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1); + cx23885_gpio_clear(dev, GPIO_2 | GPIO_11); + mdelay(100); + cx23885_gpio_set(dev, GPIO_2 | GPIO_11); + break; } } @@ -1847,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_DVBSKY_T9580: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0x8; /* Serial bus */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: @@ -1909,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_AVERMEDIA_HC81R: case CX23885_BOARD_TBS_6980: case CX23885_BOARD_TBS_6981: + case CX23885_BOARD_DVBSKY_T9580: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 3e72c95a1d59..13734b8c7917 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -69,6 +69,10 @@ #include "a8293.h" #include "mb86a20s.h" #include "si2165.h" +#include "si2168.h" +#include "si2157.h" +#include "m88ds3103.h" +#include "m88ts2022.h" static unsigned int debug; @@ -583,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); + + switch (voltage) { + case SEC_VOLTAGE_13: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + case SEC_VOLTAGE_18: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_set(dev, GPIO_0); + break; + case SEC_VOLTAGE_OFF: + cx23885_gpio_clear(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + } + + /* call the frontend set_voltage function */ + port->fe_set_voltage(fe, voltage); + + return 0; +} + static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; @@ -747,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = { .ref_freq_Hz = 16000000, }; +static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .lnb_en_pol = 1, + .lnb_hv_pol = 0, + .agc = 0x99, +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -896,6 +942,13 @@ static int dvb_register(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; struct vb2_dvb_frontend *fe0, *fe1 = NULL; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + struct m88ts2022_config m88ts2022_config; + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; int mfe_shared = 0; /* bus not shared by default */ int ret; @@ -1533,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_DVBSKY_T9580: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + switch (port->nr) { + /* port b - satellite */ + case 1: + /* attach frontend */ + fe0->dvb.frontend = dvb_attach(m88ds3103_attach, + &dvbsky_t9580_m88ds3103_config, + &i2c_bus2->i2c_adap, &adapter); + if (fe0->dvb.frontend == NULL) + break; + + /* attach tuner */ + m88ts2022_config.fe = fe0->dvb.frontend; + m88ts2022_config.clock = 27000000; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &m88ts2022_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + goto frontend_detach; + } + + /* delegate signal strength measurement to tuner */ + fe0->dvb.frontend->ops.read_signal_strength = + fe0->dvb.frontend->ops.tuner_ops.get_rf_strength; + + /* + * for setting the voltage we need to set GPIOs on + * the card. + */ + port->fe_set_voltage = + fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = + dvbsky_t9580_set_voltage; + + port->i2c_client_tuner = client_tuner; + + break; + /* port c - terrestrial/cable */ + case 2: + /* attach frontend */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &fe0->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (client_demod == NULL || + client_demod->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + si2157_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1607,6 +1751,22 @@ static int dvb_register(struct cx23885_tsport *port) memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); break; } + case CX23885_BOARD_DVBSKY_T9580: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr > 2) + break; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n", + port->nr, eeprom + 0xc0 + (port->nr-1) * 8); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + + (port->nr-1) * 8, 6); + break; + } } return ret; diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0d5888214fb6..6c35e6115969 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -92,6 +92,7 @@ #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44 +#define CX23885_BOARD_DVBSKY_T9580 45 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v1.2.3 From 87f4ebcd0693f6de14f60cf7bf9821a005b5850f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 11:17:06 -0300 Subject: [media] sta2x11_vip: fix address space casting drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1140:30: got void volatile [noderef] *iomem drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:1184:30: got void volatile [noderef] *iomem drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: warning: incorrect type in argument 1 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:226:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: warning: incorrect type in argument 2 (different modifiers) drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: expected void [noderef] * drivers/media/pci/sta2x11/sta2x11_vip.c:221:38: got void volatile [noderef] * Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/sta2x11/sta2x11_vip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 365bd21301ba..22450f583da1 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -152,7 +152,7 @@ struct sta2x11_vip { int tcount, bcount; int overflow; - void *iomem; /* I/O Memory */ + void __iomem *iomem; /* I/O Memory */ struct vip_config *config; }; -- cgit v1.2.3 From 5a9ff85dc176e80c6fb7067dcb807c5e3ff7a913 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 14:06:25 -0300 Subject: [media] saa7164-core: declare symbols as static Those symbols are used only at saa7164-core. drivers/media/pci/saa7164/saa7164-core.c:55:14: warning: symbol 'fw_debug' was not declared. Should it be static? drivers/media/pci/saa7164/saa7164-core.c:75:14: warning: symbol 'print_histogram' was not declared. Should it be static? drivers/media/pci/saa7164/saa7164-core.c:83:14: warning: symbol 'guard_checking' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 1bf06970ca3e..cc1be8a7a451 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -52,7 +52,7 @@ unsigned int saa_debug; module_param_named(debug, saa_debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); -unsigned int fw_debug; +static unsigned int fw_debug; module_param(fw_debug, int, 0644); MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2"); @@ -72,7 +72,7 @@ static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -unsigned int print_histogram = 64; +static unsigned int print_histogram = 64; module_param(print_histogram, int, 0644); MODULE_PARM_DESC(print_histogram, "print histogram values once"); @@ -80,7 +80,7 @@ unsigned int crc_checking = 1; module_param(crc_checking, int, 0644); MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers"); -unsigned int guard_checking = 1; +static unsigned int guard_checking = 1; module_param(guard_checking, int, 0644); MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns"); -- cgit v1.2.3 From e2392d347e1dbb4987beaaee0f87653480fcddc8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 15:49:50 -0300 Subject: [media] cx88: fix cards table CodingStyle This is actually a coding style issue, but it was generating lots of smatch warnings: drivers/media/pci/cx88/cx88-cards.c:1513:37: warning: Initializer entry defined twice drivers/media/pci/cx88/cx88-cards.c:1517:19: also defined here drivers/media/pci/cx88/cx88-cards.c:1533:36: warning: Initializer entry defined twice drivers/media/pci/cx88/cx88-cards.c:1538:19: also defined here ... Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-cards.c | 632 ++++++++++++++++++------------------ 1 file changed, 316 insertions(+), 316 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index e18a7ace08b1..851754bf1291 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE3, .vmux = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE4, .vmux = 3, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE] = { .name = "Hauppauge WinTV 34xxx models", @@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xff02, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff01, @@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PIXELVIEW] = { .name = "PixelView", @@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff10, @@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x03ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03fe, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03fe, - }}, + } }, }, [CX88_BOARD_WINFAST2000XP_EXPERT] = { .name = "Leadtek Winfast 2000XP Expert", @@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00F5e700, .gpio1 = 0x00003004, .gpio2 = 0x00F5e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00F5d700, @@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio1 = 0xe09f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio1 = 0xe05f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio1 = 0xe05f, - }}, + } }, .radio = { .gpio1 = 0xe0df, .type = CX88_RADIO, @@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 3, @@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0035e700, .gpio1 = 0x00003004, .gpio2 = 0x0035e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x00003004, .gpio2 = 0x0035c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0035c700, .gpio1 = 0x0035c700, .gpio2 = 0x02000000, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0035d700, @@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, @@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PROLINK_PLAYTVPVR] = { .name = "Prolink PlayTV PVR", @@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbff0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbff3, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbff3, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbff0, @@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000fde6, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000fde2, @@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc08, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - }}, + } }, }, [CX88_BOARD_KWORLD_DVB_T] = { .name = "KWorld/VStream XPert DVB-T", @@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { @@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_LTV883] = { @@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x07f8, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0x07f9, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000007fa, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000007fa, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x000007f8, @@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = { 0 - normal RF 1 - high RF */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0f0d, - },{ + }, { .type = CX88_VMUX_CABLE, .vmux = 0, .gpio0 = 0x0f05, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0f00, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0f00, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_DVB_T1] = { @@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_CONEXANT_DVB_T1] = { @@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PROVIDEO_PV259] = { @@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .audioroute = 1, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { @@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DNTV_LIVE_DVB_T] = { @@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD3000] = { @@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = { * * GPIO[16] = Remote control input */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00008404, @@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xed1a, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xed92, .gpio2 = 0x00ff, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xed96, @@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, @@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 1, .gpio1 = 0x0000e03f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, .gpio1 = 0x0000e07f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 3, .gpio1 = 0x0000e07f, - }} + } } }, [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = { .name = "PixelView PlayTV Ultra Pro (Stereo)", @@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, /* Some variants use a tda9874 and so need the tvaudio module. */ .audio_chip = CX88_AUDIO_TVAUDIO, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbf61, /* internal decoder */ - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbf63, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbf63, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbf60, @@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x97ed, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x97e9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x97e9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_ADSTECH_DVB_T_PCI] = { @@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { .name = "TerraTec Cinergy 1400 DVB-T", .tuner_type = TUNER_ABSENT, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = { @@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = { @@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 2, @@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = { /* Alexander Wold */ .name = "Kworld V-Stream Xpert DVD", .tuner_type = UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - }}, + } }, }, [CX88_BOARD_ATI_HDTVWONDER] = { .name = "ATI HDTV Wonder", @@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000ff7, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_WINFAST_DTV1000] = { @@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERTV_303] = { @@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00ff, .gpio1 = 0xe09f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { .name = "Hauppauge Nova-S-Plus DVB-S", @@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, .i2sinputcntl = 2, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { @@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_DVBS_100] = { @@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR1100] = { @@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xf80808, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xf80808, @@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = { @@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000067df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000067df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { @@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x3de2, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x3de6, @@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000a75f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000a75b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000a75b, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD5500] = { @@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_MCE200_DELUXE] = { @@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000BDE6 - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = { @@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x5da6, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = { @@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0788, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x078b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x078b, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x074a, @@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017304, @@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x0000b207, .gpio2 = 0x0001d701, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00015702, @@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017300, .gpio1 = 0x00008207, .gpio2 = 0x00000000, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00018300, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00018301, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00018301, .gpio1 = 0x0000f207, .gpio2 = 0x00017304, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00015702, @@ -1360,13 +1360,13 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR3000] = { @@ -1377,25 +1377,25 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, .audio_chip = CX88_AUDIO_WM8775, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x84bf, /* 1: TV Audio / FM Mono */ .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x84bf, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x84bf, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x84bf, @@ -1411,19 +1411,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0709, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x070b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x070b, - }}, + } }, }, [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", @@ -1431,28 +1431,28 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x003fffff, .gpio1 = 0x00e00000, .gpio2 = 0x003fffff, .gpio3 = 0x02000000, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE_HVR1300] = { .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", @@ -1465,25 +1465,25 @@ static const struct cx88_board cx88_boards[] = { /* * gpio0 as reported by Mike Crash */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xef88, /* 1: TV Audio / FM Mono */ .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xef88, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xef88, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, .radio = { .type = CX88_RADIO, @@ -1510,19 +1510,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DEBUG, .vmux = 3, .gpio0 = 0x04ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x07fa, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x07fa, - }}, + } }, }, [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { .name = "Pinnacle PCTV HD 800i", @@ -1530,24 +1530,24 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x04fb, .gpio1 = 0x10ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x04fb, .gpio1 = 0x10ef, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x04fb, .gpio1 = 0x10ef, .audioroute = 1, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = { @@ -1557,7 +1557,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x000027df, /* Unconfirmed */ @@ -1815,19 +1815,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x10df, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x16d9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x16d9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PROLINK_PV_8000GT] = { @@ -1967,7 +1967,7 @@ static const struct cx88_board cx88_boards[] = { * 3: Line-In Expansion * 4: FM Stereo */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xc4bf, @@ -2001,7 +2001,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2013,7 +2013,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2025,7 +2025,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2037,7 +2037,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2049,7 +2049,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2061,7 +2061,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2073,7 +2073,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, .gpio0 = 0x8080, @@ -2086,7 +2086,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2098,7 +2098,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2110,7 +2110,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2170,7 +2170,7 @@ static const struct cx88_board cx88_boards[] = { * 13: audio source (0=tuner audio,1=line in) * 14: FM (0=on,1=off ???) */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2211,7 +2211,7 @@ static const struct cx88_board cx88_boards[] = { * 13: audio source (0=tuner audio,1=line in) * 14: FM (0=on,1=off ???) */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2229,7 +2229,7 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x0400, /* pin 2 = 0 */ .gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */ .gpio2 = 0x0000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0400, /* pin 2 = 0 */ @@ -2252,7 +2252,7 @@ static const struct cx88_board cx88_boards[] = { * 14: 0: FM radio * 16: 0: RF input is cable */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0403, @@ -2280,7 +2280,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0xF0F7, .gpio2 = 0x0101, .gpio3 = 0x0000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0403, @@ -2308,7 +2308,7 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, } }, @@ -2324,19 +2324,19 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x0070, .subdevice = 0x3400, .card = CX88_BOARD_HAUPPAUGE, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x3401, .card = CX88_BOARD_HAUPPAUGE, - },{ + }, { .subvendor = 0x14c7, .subdevice = 0x0106, .card = CX88_BOARD_GDI, - },{ + }, { .subvendor = 0x14c7, .subdevice = 0x0107, /* with mpeg encoder */ .card = CX88_BOARD_GDI, - },{ + }, { .subvendor = PCI_VENDOR_ID_ATI, .subdevice = 0x00f8, .card = CX88_BOARD_ATI_WONDER_PRO, @@ -2348,176 +2348,176 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x107d, .subdevice = 0x6611, .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6613, /* NTSC */ .card = CX88_BOARD_WINFAST2000XP_EXPERT, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6620, .card = CX88_BOARD_WINFAST_DV2000, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x663b, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x663c, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x000b, .card = CX88_BOARD_AVERTV_STUDIO_303, - },{ + }, { .subvendor = 0x1462, .subdevice = 0x8606, .card = CX88_BOARD_MSI_TVANYWHERE_MASTER, - },{ + }, { .subvendor = 0x10fc, .subdevice = 0xd003, .card = CX88_BOARD_IODATA_GVVCP3PCI, - },{ + }, { .subvendor = 0x1043, .subdevice = 0x4823, /* with mpeg encoder */ .card = CX88_BOARD_ASUS_PVR_416, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08a6, .card = CX88_BOARD_KWORLD_DVB_T, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd810, .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd820, .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb00, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9002, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0187, .card = CX88_BOARD_CONEXANT_DVB_T1, - },{ + }, { .subvendor = 0x1540, .subdevice = 0x2580, .card = CX88_BOARD_PROVIDEO_PV259, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb10, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, - },{ + }, { .subvendor = 0x1554, .subdevice = 0x4811, .card = CX88_BOARD_PIXELVIEW, - },{ + }, { .subvendor = 0x7063, .subdevice = 0x3000, /* HD-3000 card */ .card = CX88_BOARD_PCHDTV_HD3000, - },{ + }, { .subvendor = 0x17de, .subdevice = 0xa8a6, .card = CX88_BOARD_DNTV_LIVE_DVB_T, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x2801, .card = CX88_BOARD_HAUPPAUGE_ROSLYN, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0342, .card = CX88_BOARD_DIGITALLOGIC_MEC, - },{ + }, { .subvendor = 0x10fc, .subdevice = 0xd035, .card = CX88_BOARD_IODATA_GVBCTV7E, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0334, .card = CX88_BOARD_ADSTECH_DVB_T_PCI, - },{ + }, { .subvendor = 0x153b, .subdevice = 0x1166, .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x8011, .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550, - },{ + }, { .subvendor = PCI_VENDOR_ID_ATI, .subdevice = 0xa101, .card = CX88_BOARD_ATI_HDTVWONDER, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x665f, .card = CX88_BOARD_WINFAST_DTV1000, - },{ + }, { .subvendor = 0x1461, .subdevice = 0x000a, .card = CX88_BOARD_AVERTV_303, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9200, .card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9201, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9202, .card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08b2, .card = CX88_BOARD_KWORLD_DVBS_100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9400, .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9402, .card = CX88_BOARD_HAUPPAUGE_HVR1100, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9800, .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9802, .card = CX88_BOARD_HAUPPAUGE_HVR1100LP, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9001, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x1822, .subdevice = 0x0025, .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x08a1, .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb50, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb54, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL, /* Re-branded DViCO: DigitalNow DVB-T Dual */ - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb11, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, @@ -2530,55 +2530,55 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x17de, .subdevice = 0x0840, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0305, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb40, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xdb44, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, - },{ + }, { .subvendor = 0x7063, .subdevice = 0x5500, .card = CX88_BOARD_PCHDTV_HD5500, - },{ + }, { .subvendor = 0x17de, .subdevice = 0x0841, .card = CX88_BOARD_KWORLD_MCE200_DELUXE, - },{ + }, { .subvendor = 0x1822, .subdevice = 0x0019, .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO, - },{ + }, { .subvendor = 0x1554, .subdevice = 0x4813, .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0842, .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x665e, .card = CX88_BOARD_WINFAST_DTV2000H, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6f2b, .card = CX88_BOARD_WINFAST_DTV2000H_J, - },{ + }, { .subvendor = 0x18ac, .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, - },{ + }, { .subvendor = 0x14f1, .subdevice = 0x0084, .card = CX88_BOARD_GENIATECH_DVBS, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1404, .card = CX88_BOARD_HAUPPAUGE_HVR3000, @@ -2590,60 +2590,60 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdccd, .card = CX88_BOARD_SAMSUNG_SMT_7020, - },{ + }, { .subvendor = 0x1461, .subdevice = 0xc111, /* AverMedia M150-D */ /* This board is known to work with the ASUS PVR416 config */ .card = CX88_BOARD_ASUS_PVR_416, - },{ + }, { .subvendor = 0xc180, .subdevice = 0xc980, .card = CX88_BOARD_TE_DTV_250_OEM_SWANN, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9600, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9601, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9602, .card = CX88_BOARD_HAUPPAUGE_HVR1300, - },{ + }, { .subvendor = 0x107d, .subdevice = 0x6632, .card = CX88_BOARD_LEADTEK_PVR2000, - },{ + }, { .subvendor = 0x12ab, .subdevice = 0x2300, /* Club3D Zap TV2100 */ .card = CX88_BOARD_KWORLD_DVB_T_CX22702, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x9000, .card = CX88_BOARD_HAUPPAUGE_DVB_T1, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1400, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1401, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x0070, .subdevice = 0x1402, .card = CX88_BOARD_HAUPPAUGE_HVR3000, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ .card = CX88_BOARD_KWORLD_DVBS_100, - },{ + }, { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, - },{ + }, { .subvendor = 0x11bd, .subdevice = 0x0051, .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, -- cgit v1.2.3 From 84babee8fea9fc4fae2b5414ce71db1902eb7b7b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 16:23:30 -0300 Subject: [media] cx88: remove return after BUG() As reported by smatch: drivers/media/pci/cx88/cx88-video.c:699 get_queue() info: ignoring unreachable code. drivers/media/pci/cx88/cx88-video.c:714 get_resource() info: ignoring unreachable code. drivers/media/pci/cx88/cx88-video.c:815 video_read() info: ignoring unreachable code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-video.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ed8cb9037b6f..ce27e6d4f16e 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -696,7 +696,6 @@ static struct videobuf_queue *get_queue(struct file *file) return &fh->vbiq; default: BUG(); - return NULL; } } @@ -711,7 +710,6 @@ static int get_resource(struct file *file) return RESOURCE_VBI; default: BUG(); - return 0; } } @@ -812,7 +810,6 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) file->f_flags & O_NONBLOCK); default: BUG(); - return 0; } } -- cgit v1.2.3 From 339f06c5d354c4c89814f11d0c3393f198b3dd00 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 24 Sep 2014 20:35:48 -0300 Subject: [media] pci drivers: use %zu instead of %zd size_t is unsigned. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-alsa-pcm.c | 2 +- drivers/media/pci/cx18/cx18-firmware.c | 4 ++-- drivers/media/pci/cx18/cx18-queue.c | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/ivtv/ivtv-alsa-pcm.c | 2 +- drivers/media/pci/ivtv/ivtv-firmware.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index 180077c49123..ffb6acdc575f 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, int period_elapsed = 0; int length; - dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, + dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc, pcm_data, num_bytes); substream = cxsc->capture_pcm_substream; diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index 53a7578d525b..c6c83445f8bf 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) } } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size); size = fw->size; release_firmware(fw); cx18_setup_page(cx, SCB_OFFSET); @@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, offset += seghdr.size; } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n", fn, apu_version, fw->size); size = fw->size; release_firmware(fw); diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 8884537bd62f..2a247d264b87 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s) ((char __iomem *)cx->scb->cpu_mdl)); CX18_ERR("Too many buffers, cannot fit in SCB area\n"); - CX18_ERR("Max buffers = %zd\n", + CX18_ERR("Max buffers = %zu\n", bufsz / sizeof(struct cx18_mdl_ent)); return -ENOMEM; } diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 6973055f0814..3948db386fb5 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -942,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", + "(have %zu, expected %d)\n", firmware->size, CX23885_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 7a9b98bc208b..7bf9cbca4fa6 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -81,7 +81,7 @@ static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc, int period_elapsed = 0; int length; - dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc, + dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc, pcm_data, num_bytes); substream = itvsc->capture_pcm_substream; diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index ed73edd2bcd3..4b0e758a7bce 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -65,7 +65,7 @@ retry: the wrong file was sometimes loaded. So we check filesizes to see if at least the right-sized file was loaded. If not, then we retry. */ - IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); + IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size); release_firmware(fw); retries--; goto retry; @@ -76,7 +76,7 @@ retry: dst++; src++; } - IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size); + IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size); release_firmware(fw); return size; } -- cgit v1.2.3 From cf3167cf1e969b17671a4d3d956d22718a8ceb85 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 26 Sep 2014 22:45:36 -0300 Subject: [media] pt3: fix DTV FE I2C driver load error paths Get rid of 'module_is_live' usage. on x86_64: when CONFIG_MODULES is not enabled: ../drivers/media/pci/pt3/pt3.c: In function 'pt3_attach_fe': ../drivers/media/pci/pt3/pt3.c:433:6: error: implicit declaration of function 'module_is_live' [-Werror=implicit-function-declaration] Reported-by: Randy Dunlap Cc: Akihiro Tsukada Cc: Stephen Rothwell Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pt3/pt3.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/media/pci') diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 90f86ce7a001..1fdeac11501a 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -393,7 +393,7 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i) return -ENODEV; pt3->adaps[i]->i2c_demod = cl; if (!try_module_get(cl->dev.driver->owner)) - goto err_demod; + goto err_demod_i2c_unregister_device; if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) { struct qm1d1c0042_config tcfg; @@ -415,28 +415,27 @@ static int pt3_attach_fe(struct pt3_board *pt3, int i) cl = i2c_new_device(cfg.tuner_i2c, &info); } if (!cl || !cl->dev.driver) - goto err_demod; + goto err_demod_module_put; pt3->adaps[i]->i2c_tuner = cl; if (!try_module_get(cl->dev.driver->owner)) - goto err_tuner; + goto err_tuner_i2c_unregister_device; dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap; ret = dvb_register_frontend(dvb_adap, cfg.fe); if (ret < 0) - goto err_tuner; + goto err_tuner_module_put; pt3->adaps[i]->fe = cfg.fe; return 0; -err_tuner: +err_tuner_module_put: + module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); +err_tuner_i2c_unregister_device: i2c_unregister_device(pt3->adaps[i]->i2c_tuner); - if (pt3->adaps[i]->i2c_tuner->dev.driver->owner && - module_is_live(pt3->adaps[i]->i2c_tuner->dev.driver->owner)) - module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner); -err_demod: +err_demod_module_put: + module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); +err_demod_i2c_unregister_device: i2c_unregister_device(pt3->adaps[i]->i2c_demod); - if (pt3->adaps[i]->i2c_demod->dev.driver->owner && - module_is_live(pt3->adaps[i]->i2c_demod->dev.driver->owner)) - module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner); + return ret; } -- cgit v1.2.3